Skip to content

Commit

Permalink
Adds Toxic Chain's effect (#4823)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexOn1ine authored Jun 18, 2024
2 parents cba3cf4 + 1fd23ec commit f106b21
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ enum RandomTag
RNG_SPEED_TIE,
RNG_STATIC,
RNG_STENCH,
RNG_TOXIC_CHAIN,
RNG_TRI_ATTACK,
RNG_QUICK_DRAW,
RNG_QUICK_CLAW,
Expand Down
28 changes: 28 additions & 0 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5806,6 +5806,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
effect++;
}
break;
case ABILITY_TOXIC_CHAIN:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& IsBattlerAlive(gBattlerTarget)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget)
&& TARGET_TURN_DAMAGED // Need to actually hit the target
&& RandomWeighted(RNG_TOXIC_CHAIN, 7, 3))
{
gBattleScripting.moveEffect = MOVE_EFFECT_TOXIC;
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect;
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
effect++;
}
break;
case ABILITY_STENCH:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& IsBattlerAlive(gBattlerTarget)
Expand Down Expand Up @@ -7955,6 +7971,18 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move
effect = DamagedStatBoostBerryEffect(battler, STAT_SPDEF, DAMAGE_CATEGORY_SPECIAL);
break;
case HOLD_EFFECT_CURE_STATUS: // only Toxic Chain's interaction with Knock Off
case HOLD_EFFECT_CURE_PSN:
if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem) && GetBattlerAbility(gBattlerAttacker) == ABILITY_TOXIC_CHAIN && gMovesInfo[gCurrentMove].effect == EFFECT_KNOCK_OFF)
{
gBattleScripting.battler = battler;
gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER);
BattleScriptExecute(BattleScript_BerryCurePsnEnd2);
BtlController_EmitSetMonData(battler, 0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_STICKY_BARB:
if (TARGET_TURN_DAMAGED
&& (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
Expand Down
112 changes: 112 additions & 0 deletions test/battle/ability/toxic_chain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include "global.h"
#include "test/battle.h"

SINGLE_BATTLE_TEST("Toxic Chain inflicts bad poison when attacking")
{
PASSES_RANDOMLY(3, 10, RNG_TOXIC_CHAIN);
GIVEN {
ASSUME(gMovesInfo[MOVE_TACKLE].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ABILITY_POPUP(player, ABILITY_TOXIC_CHAIN);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
MESSAGE("Foe Wobbuffet is badly poisoned!");
STATUS_ICON(opponent, badPoison: TRUE);
} THEN {
EXPECT(opponent->status1 & STATUS1_TOXIC_POISON);
}
}

SINGLE_BATTLE_TEST("Toxic Chain inflicts bad poison on any hit of a multi-hit move")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].effect == EFFECT_MULTI_HIT);
ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].power > 0);
ASSUME(gItemsInfo[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN);
PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_PECHA_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_DOUBLE_SLAP); }
} SCENE {
ABILITY_POPUP(player, ABILITY_TOXIC_CHAIN);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
MESSAGE("Foe Wobbuffet is badly poisoned!");
STATUS_ICON(opponent, badPoison: TRUE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
STATUS_ICON(opponent, badPoison: FALSE);
ABILITY_POPUP(player, ABILITY_TOXIC_CHAIN);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
MESSAGE("Foe Wobbuffet is badly poisoned!");
STATUS_ICON(opponent, badPoison: TRUE);
} THEN {
EXPECT(opponent->status1 & STATUS1_TOXIC_POISON);
}
}

DOUBLE_BATTLE_TEST("Toxic Chain can inflict bad poison on both foes")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].target == MOVE_TARGET_BOTH);
ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].power > 0);
PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerLeft, MOVE_RAZOR_LEAF, WITH_RNG(RNG_TOXIC_CHAIN, TRUE)); }
} SCENE {
HP_BAR(opponentLeft);
ABILITY_POPUP(playerLeft, ABILITY_TOXIC_CHAIN);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponentLeft);
MESSAGE("Foe Wobbuffet is badly poisoned!");
STATUS_ICON(opponentLeft, badPoison: TRUE);
HP_BAR(opponentRight);
ABILITY_POPUP(playerLeft, ABILITY_TOXIC_CHAIN);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponentRight);
MESSAGE("Foe Wynaut is badly poisoned!");
STATUS_ICON(opponentRight, badPoison: TRUE);
} THEN {
EXPECT(opponentLeft->status1 & STATUS1_TOXIC_POISON);
EXPECT(opponentRight->status1 & STATUS1_TOXIC_POISON);
}
}

SINGLE_BATTLE_TEST("Toxic Chain makes Lum/Pecha Berry trigger before being knocked off")
{
u16 item = 0;

PARAMETRIZE { item = ITEM_PECHA_BERRY; }
PARAMETRIZE { item = ITEM_LUM_BERRY; }

GIVEN {
ASSUME(gMovesInfo[MOVE_KNOCK_OFF].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF);
ASSUME(gMovesInfo[MOVE_KNOCK_OFF].power > 0);
ASSUME(gItemsInfo[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN);
ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS);
PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); }
OPPONENT(SPECIES_WOBBUFFET) { Item(item); }
} WHEN {
TURN { MOVE(player, MOVE_KNOCK_OFF, WITH_RNG(RNG_TOXIC_CHAIN, TRUE)); }
} SCENE {
ABILITY_POPUP(player, ABILITY_TOXIC_CHAIN);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
MESSAGE("Foe Wobbuffet is badly poisoned!");
STATUS_ICON(opponent, badPoison: TRUE);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
STATUS_ICON(opponent, badPoison: FALSE);
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF);
MESSAGE("Okidogi knocked off Foe Wobbuffet's Pecha Berry!");
MESSAGE("Okidogi knocked off Foe Wobbuffet's Lum Berry!");
}
} THEN {
EXPECT(opponent->status1 == 0);
}
}

0 comments on commit f106b21

Please sign in to comment.