Master to upcoming, 2024-11-29 (#5735)

This commit is contained in:
Bassoonian 2024-11-29 12:19:08 +01:00 committed by GitHub
commit 5da1f322d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 299 additions and 25 deletions

View file

@ -6,12 +6,16 @@
pokeemerald-expansion is a decomp hack base project based off pret's [pokeemerald](https://github.com/pret/pokeemerald) decompilation project. It's recommended that any new projects that plan on using it, to clone this repository instead of pret's vanilla repository, as we regurlarly incorporate pret's documentation changes. This is ***NOT*** a standalone romhack, and as such, most features will be unavailable and/or unbalanced if played as is.
## Using pokeemerald-expansion
If you use pokeemerald-expansion in your hack, please add RHH (Rom Hacking Hideout) to your credits list. Optionally, you can list the version used, so it can help players know what features to expect.
You can phrase it as the following:
```
Based off RHH's pokeemerald-expansion 1.9.3 https://github.com/rh-hideout/pokeemerald-expansion/
```
Please follow the instructions in `INSTALL.md` to get pokeemerald-expansion set up on your machine.
## What features are included?
- ***IMPORTANT*❗❗ Read through these to learn what features you can toggle**:
- [Battle configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/battle.h)

View file

@ -10093,7 +10093,6 @@ gBattleAnimMove_FloralHealing::
loadspritegfx ANIM_TAG_ORBS @circles
loadspritegfx ANIM_TAG_PINK_PETAL @pink particles
monbg ANIM_ATTACKER
monbg ANIM_TARGET
playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER
call CIRCLES_LEAVES
call CIRCLES_LEAVES
@ -10101,6 +10100,7 @@ gBattleAnimMove_FloralHealing::
panse SE_M_COMET_PUNCH, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 0x2, 0x0
playsewithpan SE_M_TWISTER, 0x0
createsprite gSweetScentPetalSpriteTemplate, ANIM_ATTACKER, 2, 0x46, 0x1, 0x40
clearmonbg ANIM_ATTACKER
delay 0x2
createsprite gFloralHealingWindLeavesTemplate, ANIM_ATTACKER, 2, 0x3c, 0x0, 0x40
delay 0x2
@ -10123,6 +10123,7 @@ gBattleAnimMove_FloralHealing::
createsprite gSweetScentPetalSpriteTemplate, ANIM_ATTACKER, 2, 0x55, 0x0, 0x78
delay 0x2
loopsewithpan SE_M_POISON_POWDER, SOUND_PAN_TARGET, 0x12, 0xa
monbg ANIM_TARGET
call FloralHealingSpores
call FloralHealingSpores
call FloralHealingSpores
@ -10133,7 +10134,6 @@ gBattleAnimMove_FloralHealing::
createsprite gGrantingStarsSpriteTemplate, ANIM_ATTACKER, 16, 0xc, 0xfffb, 0x1, 0x0, 0x20, 0x3c, 0x1
waitforvisualfinish
clearmonbg ANIM_TARGET
clearmonbg ANIM_ATTACKER
end
FloralHealingSpores:
createsprite gFloralHealingFlowerTemplate, ANIM_ATTACKER, 2, 0x0, 0xffec, 0x55, 0x50, 0x0

View file

@ -2401,7 +2401,6 @@ BattleScript_EffectHealingWish::
storehealingwish BS_ATTACKER
.if B_HEALING_WISH_SWITCH <= GEN_4
openpartyscreen BS_ATTACKER, BattleScript_EffectHealingWishEnd
switchoutabilities BS_ATTACKER
waitstate
switchhandleorder BS_ATTACKER, 2
returnatktoball
@ -5755,7 +5754,6 @@ BattleScript_PrintFullBox::
BattleScript_ActionSwitch::
hpthresholds2 BS_ATTACKER
saveattacker
printstring STRINGID_RETURNMON
jumpifbattletype BATTLE_TYPE_DOUBLE, BattleScript_PursuitSwitchDmgSetMultihit
setmultihit 1
@ -5773,7 +5771,6 @@ BattleScript_DoSwitchOut::
switchoutabilities BS_ATTACKER
updatedynamax
waitstate
restoreattacker
returnatktoball
waitstate
drawpartystatussummary BS_ATTACKER
@ -9633,7 +9630,9 @@ BattleScript_EjectButtonActivates::
removeitem BS_SCRIPTING
makeinvisible BS_SCRIPTING
openpartyscreen BS_SCRIPTING, BattleScript_EjectButtonEnd
copybyte sSAVED_BATTLER, sBATTLER
switchoutabilities BS_SCRIPTING
copybyte sBATTLER, sSAVED_BATTLER
waitstate
switchhandleorder BS_SCRIPTING 0x2
returntoball BS_SCRIPTING, FALSE
@ -9730,6 +9729,7 @@ BattleScript_PastelVeilEnd:
end3
BattleScript_NeutralizingGasExits::
saveattacker
savetarget
pause B_WAIT_TIME_SHORT
printstring STRINGID_NEUTRALIZINGGASOVER
@ -9739,6 +9739,7 @@ BattleScript_NeutralizingGasExitsLoop:
switchinabilities BS_TARGET
addbyte gBattlerTarget, 1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_NeutralizingGasExitsLoop
restoreattacker
restoretarget
return

Binary file not shown.

Before

Width:  |  Height:  |  Size: 686 B

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1,7 +1,7 @@
JASC-PAL
0100
16
255 255 255
120 255 255
254 235 185
220 220 218
235 192 100
@ -16,4 +16,4 @@ JASC-PAL
64 64 64
45 43 43
8 8 8
0 0 0
255 255 255

View file

@ -16,4 +16,4 @@ JASC-PAL
64 64 64
45 43 43
8 8 8
0 0 0
255 255 255

Binary file not shown.

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 B

After

Width:  |  Height:  |  Size: 563 B

View file

@ -289,9 +289,9 @@ enum MoveEndEffects
MOVEEND_RECOIL,
MOVEEND_ITEM_EFFECTS_ATTACKER,
MOVEEND_MAGICIAN, // Occurs after final multi-hit strike, and after other items/abilities would activate
MOVEEND_RED_CARD, // Red Card triggers before Eject Pack
MOVEEND_EJECT_ITEMS,
MOVEEND_WHITE_HERB,
MOVEEND_RED_CARD,
MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc
MOVEEND_CHANGED_ITEMS,
MOVEEND_PICKPOCKET,

View file

@ -134,4 +134,8 @@
// param1: amount of days
#define FORM_CHANGE_DAYS_PASSED 23
// Form change for Aegislash
#define FORM_CHANGE_BATTLE_ATTACK 24
#define FORM_CHANGE_BATTLE_KINGS_SHIELD 25
#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H

View file

@ -1125,7 +1125,6 @@ static bool32 NoTargetPresent(u8 battler, u32 move)
return FALSE;
}
// TODO: Convert this to a proper FORM_CHANGE type.
static bool32 TryAegiFormChange(void)
{
// Only Aegislash with Stance Change can transform, transformed mons cannot.
@ -1140,12 +1139,12 @@ static bool32 TryAegiFormChange(void)
case SPECIES_AEGISLASH_SHIELD: // Shield -> Blade
if (IS_MOVE_STATUS(gCurrentMove))
return FALSE;
gBattleMons[gBattlerAttacker].species = SPECIES_AEGISLASH_BLADE;
TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_ATTACK);
break;
case SPECIES_AEGISLASH_BLADE: // Blade -> Shield
if (gCurrentMove != MOVE_KINGS_SHIELD)
return FALSE;
gBattleMons[gBattlerAttacker].species = SPECIES_AEGISLASH_SHIELD;
TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_KINGS_SHIELD);
break;
}
@ -1782,8 +1781,6 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
if (!RandomPercentage(RNG_ACCURACY, accuracy))
{
gMoveResultFlags |= MOVE_RESULT_MISSED;
if (holdEffectAtk == HOLD_EFFECT_BLUNDER_POLICY)
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_DARTS
&& !recalcDragonDarts // So we don't jump back and forth between targets
@ -2266,6 +2263,7 @@ END:
}
if (gSpecialStatuses[gBattlerAttacker].gemBoost
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& gBattleMons[gBattlerAttacker].item
&& gMovesInfo[gCurrentMove].effect != EFFECT_PLEDGE
&& gCurrentMove != MOVE_STRUGGLE)
@ -2678,6 +2676,13 @@ static void Cmd_resultmessage(void)
return;
}
if (gMoveResultFlags & MOVE_RESULT_MISSED && !(gMoveResultFlags & (MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED)))
{
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY
&& !IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove))
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
}
if (gMoveResultFlags & MOVE_RESULT_MISSED && (!(gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) || gBattleCommunication[MISS_TYPE] > B_MSG_AVOIDED_ATK))
{
if (gBattleCommunication[MISS_TYPE] > B_MSG_AVOIDED_ATK) // Wonder Guard or Levitate - show the ability pop-up
@ -4157,6 +4162,15 @@ static void Cmd_tryfaintmon(void)
}
else
{
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS
&& !(gAbsentBattlerFlags & (1u << battler))
&& !IsBattlerAlive(battler))
{
gBattleMons[battler].ability = ABILITY_NONE;
BattleScriptPush(gBattlescriptCurrInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
return;
}
if (cmd->battler == BS_ATTACKER)
{
destinyBondBattler = gBattlerTarget;
@ -14788,7 +14802,7 @@ static void Cmd_switchoutabilities(void)
MarkBattlerForControllerExec(battler);
break;
case ABILITY_REGENERATOR:
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 3;
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 3;
gBattleMoveDamage += gBattleMons[battler].hp;
if (gBattleMoveDamage > gBattleMons[battler].maxHP)
gBattleMoveDamage = gBattleMons[battler].maxHP;

View file

@ -6889,7 +6889,7 @@ static u8 TrySetEnigmaBerry(u32 battler)
{
if (IsBattlerAlive(battler)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& ((TARGET_TURN_DAMAGED && gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements)
&& ((BATTLER_TURN_DAMAGED(battler) && gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements)
&& !(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP)
&& (B_HEAL_BLOCKING < GEN_5 || !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)))
{
@ -6913,7 +6913,7 @@ static u8 DamagedStatBoostBerryEffect(u32 battler, u8 statId, u8 category)
|| (!DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& GetBattleMoveCategory(gCurrentMove) == category
&& battler != gBattlerAttacker
&& TARGET_TURN_DAMAGED))
&& BATTLER_TURN_DAMAGED(battler)))
)
{
BufferStatChange(battler, statId, STRINGID_STATROSE);
@ -10936,6 +10936,10 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
if (GetBattlerTeraType(battler) == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_ATTACK:
case FORM_CHANGE_BATTLE_KINGS_SHIELD:
targetSpecies = formChanges[i].targetSpecies;
break;
}
}
}

View file

@ -12217,7 +12217,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Coil"),
.description = COMPOUND_STRING(
"Coils up to raise Attack\n"
"Coils up to raise Attack,\n"
"Defense and Accuracy."),
.effect = EFFECT_COIL,
.power = 0,
@ -17335,7 +17335,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.name = COMPOUND_STRING("Octolock"),
.description = COMPOUND_STRING(
"Traps the foe to lower Def\n"
"and Sp. Def fall each turn."),
"and Sp. Def each turn."),
.effect = EFFECT_OCTOLOCK,
.power = 0,
.type = TYPE_FIGHTING,
@ -20610,6 +20610,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.priority = 0,
.category = DAMAGE_CATEGORY_PHYSICAL,
.makesContact = TRUE,
.minimizeDoubleDamage = TRUE,
.battleAnimScript = gBattleAnimMove_SupercellSlam,
},

View file

@ -789,9 +789,11 @@ static const struct FormChange sFurfrouFormChangeTable[] = {
#if P_FAMILY_HONEDGE
static const struct FormChange sAegislashFormChangeTable[] = {
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_FAINT, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_END_BATTLE, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_BATTLE_ATTACK, SPECIES_AEGISLASH_BLADE},
{FORM_CHANGE_BATTLE_KINGS_SHIELD, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_FAINT, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_END_BATTLE, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_TERMINATOR},
};
#endif //P_FAMILY_HONEDGE

View file

@ -3,7 +3,7 @@
ASSUMPTIONS
{
ASSUME(B_PROTEAN_LIBERO == GEN_9);
ASSUME(B_DAUNTLESS_SHIELD == GEN_9);
}
SINGLE_BATTLE_TEST("Dauntless Shield raises Defense by one stage")

View file

@ -246,7 +246,7 @@ DOUBLE_BATTLE_TEST("Intimidate is not going to trigger if a mon switches out thr
}
}
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutralizing Gas")
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutralizing Gas - switching out")
{
GIVEN {
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
@ -263,3 +263,91 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutral
SEND_IN_MESSAGE("Wobbuffet");
}
}
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - switching moves")
{
u32 move;
PARAMETRIZE { move = MOVE_U_TURN; }
PARAMETRIZE { move = MOVE_HEALING_WISH; }
PARAMETRIZE { move = MOVE_BATON_PASS; }
GIVEN {
ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE);
ASSUME(gMovesInfo[MOVE_HEALING_WISH].effect == EFFECT_HEALING_WISH);
ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
} WHEN {
TURN { MOVE(player, move); SEND_OUT(player, 1); }
} SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, move, player);
MESSAGE("The effects of the neutralizing gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
SEND_IN_MESSAGE("Wobbuffet");
} THEN {
if (move == MOVE_HEALING_WISH)
EXPECT_EQ(player->hp, player->maxHP);
}
}
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - opponent caused switches")
{
u32 move, item;
PARAMETRIZE { move = MOVE_TACKLE; item = ITEM_EJECT_BUTTON; }
PARAMETRIZE { move = MOVE_GROWL; item = ITEM_EJECT_PACK; }
PARAMETRIZE { move = MOVE_ROAR; item = ITEM_NONE; }
PARAMETRIZE { move = MOVE_DRAGON_TAIL; item = ITEM_NONE; }
GIVEN {
ASSUME(gItemsInfo[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON);
ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK);
ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN);
ASSUME(gMovesInfo[MOVE_ROAR].effect == EFFECT_ROAR);
ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); Item(item); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
} WHEN {
if (item != ITEM_NONE) {
TURN { MOVE(opponent, move); SEND_OUT(player, 1); }
} else {
TURN { MOVE(opponent, move); }
}
} SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
if (item != ITEM_NONE)
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("The effects of the neutralizing gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
if (item != ITEM_NONE) {
SEND_IN_MESSAGE("Wobbuffet");
} else {
MESSAGE("Wobbuffet was dragged out!");
}
}
}
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - fainted")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FELL_STINGER].effect == EFFECT_FELL_STINGER);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
} WHEN {
TURN { MOVE(opponent, MOVE_FELL_STINGER); SEND_OUT(player, 1); }
} SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, opponent);
MESSAGE("The effects of the neutralizing gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
MESSAGE("Weezing fainted!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
SEND_IN_MESSAGE("Wobbuffet");
}
}

View file

@ -0,0 +1,67 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gItemsInfo[ITEM_BLUNDER_POLICY].holdEffect == HOLD_EFFECT_BLUNDER_POLICY);
}
SINGLE_BATTLE_TEST("Blunder Policy raises the users speed by 2 stages if the user misses")
{
PASSES_RANDOMLY(3, 10, RNG_ACCURACY);
GIVEN {
ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].accuracy == 70);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_BLUNDER_POLICY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FOCUS_BLAST); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_BLAST, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
} THEN {
EXPECT(player->item == ITEM_NONE);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 2);
}
}
SINGLE_BATTLE_TEST("Blunder Policy will never trigger if the move fails due to an immunity")
{
PASSES_RANDOMLY(10, 10, RNG_ACCURACY);
GIVEN {
ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].accuracy == 70);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_BLUNDER_POLICY); }
OPPONENT(SPECIES_GASTLY);
} WHEN {
TURN { MOVE(player, MOVE_FOCUS_BLAST); }
} SCENE {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_BLAST, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
}
} THEN {
EXPECT(player->item == ITEM_BLUNDER_POLICY);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
}
}
SINGLE_BATTLE_TEST("Blunder Policy will never trigger if the move fails due to Protect")
{
PASSES_RANDOMLY(10, 10, RNG_ACCURACY);
GIVEN {
ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].accuracy == 70);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_BLUNDER_POLICY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_FOCUS_BLAST); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_BLAST, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
}
} THEN {
EXPECT(player->item == ITEM_BLUNDER_POLICY);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
}
}

View file

@ -58,3 +58,19 @@ SINGLE_BATTLE_TEST("Enigma Berry does nothing if Heal Block applies")
}
}
}
DOUBLE_BATTLE_TEST("Enigma Berry doesn't trigger if partner was hit")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT) { Item(ITEM_ENIGMA_BERRY); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
} THEN {
EXPECT(opponentRight->item == ITEM_ENIGMA_BERRY);
}
}

View file

@ -73,3 +73,19 @@ SINGLE_BATTLE_TEST("Kee Berry doesn't trigger if the item hold user used a physi
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
}
}
DOUBLE_BATTLE_TEST("Kee Berry doesn't trigger if partner was hit")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT) { Item(ITEM_KEE_BERRY); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
} THEN {
EXPECT(opponentRight->item == ITEM_KEE_BERRY);
}
}

View file

@ -73,3 +73,19 @@ SINGLE_BATTLE_TEST("Maranga Berry doesn't trigger if the item hold user used a s
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE);
}
}
DOUBLE_BATTLE_TEST("Maranga Berry doesn't trigger if partner was hit")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT) { Item(ITEM_MARANGA_BERRY); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
} THEN {
EXPECT(opponentRight->item == ITEM_MARANGA_BERRY);
}
}

View file

@ -468,3 +468,25 @@ SINGLE_BATTLE_TEST("Red Card prevents Emergency Exit activation when triggered")
}
TO_DO_BATTLE_TEST("Red Card activates but fails if the attacker has Dynamaxed");
SINGLE_BATTLE_TEST("Red Card activates before Eject Pack")
{
GIVEN {
ASSUME(MoveHasAdditionalEffectSelf(MOVE_OVERHEAT, MOVE_EFFECT_SP_ATK_MINUS_2) == TRUE);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(player, MOVE_OVERHEAT); MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_OVERHEAT, player);
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Wobbuffet is switched out with the Eject Button!");
}
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
MESSAGE("The opposing Wobbuffet held up its Red Card against Wobbuffet!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
}
}

View file

@ -26,3 +26,21 @@ SINGLE_BATTLE_TEST("Confusion adds a 50/33% chance to hit self with 40 power")
EXPECT_EQ(damage[0], damage[1]);
}
}
SINGLE_BATTLE_TEST("Confusion self hit does not consume Gems")
{
PASSES_RANDOMLY(B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50, 100, RNG_CONFUSION);
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_CONFUSE_RAY); MOVE(player, MOVE_TACKLE); }
} SCENE {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Normal Gem strengthened Wobbuffet's power!");
}
MESSAGE("It hurt itself in its confusion!");
}
}

View file

@ -1545,6 +1545,7 @@ static void fprint_species(FILE *f, const char *prefix, struct String s)
static const unsigned char *male = (unsigned char *)u8"";
static const unsigned char *female = (unsigned char *)u8"";
static const unsigned char *e_diacritic = (unsigned char *)u8"é";
static const unsigned char *right_single_quotation_mark = (unsigned char *)u8"";
for (int i = 0; i < s.string_n; i++)
{
unsigned char c = s.string[i];
@ -1562,7 +1563,7 @@ static void fprint_species(FILE *f, const char *prefix, struct String s)
underscore = false;
fputc(c - 'a' + 'A', f);
}
else if (c == '\'' || c == '%')
else if (c == '\'' || c == '%' || is_utf8_character(s, &i, right_single_quotation_mark))
{
// Do nothing.
}