Merge branch '_RHH/master' into _RHH/upcoming
# Conflicts: # src/battle_util.c # src/data/pokemon/species_info/gen_7_families.h # test/battle/ability/download.c # test/battle/ability/intimidate.c # test/battle/ability/supreme_overlord.c # test/battle/ability/zero_to_hero.c # test/battle/ai/ai.c # test/battle/move_effect/plasma_fists.c
11
.github/workflows/docs.yml
vendored
@ -26,8 +26,18 @@ jobs:
|
||||
run: |
|
||||
cd docs
|
||||
mdbook build
|
||||
- name: Check if Pages is enabled
|
||||
uses: octokit/request-action@v2.x
|
||||
id: check_pages
|
||||
continue-on-error: true
|
||||
with:
|
||||
route: GET /repos/{repo}/pages
|
||||
repo: ${{ github.repository }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
if: steps.check_pages.outcome == 'success'
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
@ -35,3 +45,4 @@ jobs:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
if: steps.check_pages.outcome == 'success'
|
||||
|
||||
@ -475,6 +475,13 @@ devkitARM is now installed.
|
||||
|
||||
Then proceed to [Choosing where to store pokeemerald Expansion (Linux)](#choosing-where-to-store-pokeemerald-expansion-linux).
|
||||
|
||||
### NixOS
|
||||
Run the following command to start an interactive shell with the necessary packages:
|
||||
```bash
|
||||
nix-shell -p pkgsCross.arm-embedded.stdenv.cc git pkg-config libpng
|
||||
```
|
||||
Then proceed to [Choosing where to store pokeemerald Expansion (Linux)](#choosing-where-to-store-pokeemerald-expansion-linux).
|
||||
|
||||
### Other distributions
|
||||
_(Specific instructions for other distributions would be greatly appreciated!)_
|
||||
|
||||
|
||||
2
Makefile
@ -80,7 +80,7 @@ MODERN_ELF_NAME := $(MODERN_ROM_NAME:.gba=.elf)
|
||||
MODERN_MAP_NAME := $(MODERN_ROM_NAME:.gba=.map)
|
||||
MODERN_OBJ_DIR_NAME := build/modern
|
||||
|
||||
SHELL := /bin/bash -o pipefail
|
||||
SHELL := bash -o pipefail
|
||||
|
||||
ELF = $(ROM:.gba=.elf)
|
||||
MAP = $(ROM:.gba=.map)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ -d "$DEVKITARM/bin/" ]]; then
|
||||
OBJDUMP_BIN="$DEVKITARM/bin/arm-none-eabi-objdump"
|
||||
|
||||
@ -5506,7 +5506,7 @@ BattleScript_GiveExp::
|
||||
|
||||
BattleScript_HandleFaintedMon::
|
||||
setbyte sSHIFT_SWITCHED, 0
|
||||
checkteamslost BattleScript_LinkHandleFaintedMonMultiple
|
||||
checkteamslost BattleScript_HandleFaintedMonMultiple
|
||||
jumpifbyte CMP_NOT_EQUAL, gBattleOutcome, 0, BattleScript_FaintedMonEnd
|
||||
jumpifbattletype BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE, BattleScript_FaintedMonTryChoose
|
||||
jumpifword CMP_NO_COMMON_BITS, gHitMarker, HITMARKER_PLAYER_FAINTED, BattleScript_FaintedMonTryChoose
|
||||
@ -5587,13 +5587,13 @@ BattleScript_FaintedMonShiftSwitched:
|
||||
copybyte gBattlerTarget, sSAVED_BATTLER
|
||||
goto BattleScript_FaintedMonSendOutNewEnd
|
||||
|
||||
BattleScript_LinkHandleFaintedMonMultiple::
|
||||
openpartyscreen BS_FAINTED_LINK_MULTIPLE_1, BattleScript_LinkHandleFaintedMonMultipleStart
|
||||
BattleScript_LinkHandleFaintedMonMultipleStart::
|
||||
BattleScript_HandleFaintedMonMultiple::
|
||||
openpartyscreen BS_FAINTED_MULTIPLE_1, BattleScript_HandleFaintedMonMultipleStart
|
||||
BattleScript_HandleFaintedMonMultipleStart::
|
||||
switchhandleorder BS_FAINTED, 0
|
||||
openpartyscreen BS_FAINTED_LINK_MULTIPLE_2, BattleScript_LinkHandleFaintedMonMultipleEnd
|
||||
openpartyscreen BS_FAINTED_MULTIPLE_2, BattleScript_HandleFaintedMonMultipleEnd
|
||||
switchhandleorder BS_FAINTED, 0
|
||||
BattleScript_LinkHandleFaintedMonLoop::
|
||||
BattleScript_HandleFaintedMonLoop::
|
||||
switchhandleorder BS_FAINTED, 3
|
||||
drawpartystatussummary BS_FAINTED
|
||||
getswitchedmondata BS_FAINTED
|
||||
@ -5605,9 +5605,10 @@ BattleScript_LinkHandleFaintedMonLoop::
|
||||
hidepartystatussummary BS_FAINTED
|
||||
switchinanim BS_FAINTED, FALSE
|
||||
waitstate
|
||||
switchineffects BS_FAINTED_LINK_MULTIPLE_1
|
||||
jumpifbytenotequal gBattlerFainted, gBattlersCount, BattleScript_LinkHandleFaintedMonLoop
|
||||
BattleScript_LinkHandleFaintedMonMultipleEnd::
|
||||
switchineffects BS_FAINTED_MULTIPLE_1
|
||||
jumpifbytenotequal gBattlerFainted, gBattlersCount, BattleScript_HandleFaintedMonLoop
|
||||
BattleScript_HandleFaintedMonMultipleEnd::
|
||||
switchineffects BS_FAINTED_MULTIPLE_2
|
||||
end2
|
||||
|
||||
BattleScript_LocalTrainerBattleWon::
|
||||
@ -6046,6 +6047,10 @@ BattleScript_MagicRoomEnds::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
end2
|
||||
|
||||
BattleScript_GrassyTerrainEnds::
|
||||
call BattleScript_GrassyTerrainHeals_Ret
|
||||
goto BattleScript_TerrainEnds
|
||||
|
||||
BattleScript_TerrainEnds_Ret::
|
||||
printfromtable gTerrainStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
@ -8357,6 +8362,10 @@ BattleScript_MoveUsedPsychicTerrainPrevents::
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_GrassyTerrainHeals::
|
||||
call BattleScript_GrassyTerrainHeals_Ret
|
||||
end2
|
||||
|
||||
BattleScript_GrassyTerrainHeals_Ret::
|
||||
setbyte gBattleCommunication, 0
|
||||
BattleScript_GrassyTerrainLoop:
|
||||
copyarraywithindex gBattlerAttacker, gBattlerByTurnOrder, gBattleCommunication, 1
|
||||
@ -8374,7 +8383,7 @@ BattleScript_GrassyTerrainLoopEnd::
|
||||
bicword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE
|
||||
jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_PERMANENT, BattleScript_GrassyTerrainHealEnd
|
||||
BattleScript_GrassyTerrainHealEnd:
|
||||
end2
|
||||
return
|
||||
|
||||
BattleScript_AbilityNoSpecificStatLoss::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
@ -8715,7 +8724,7 @@ BattleScript_SynchronizeActivates::
|
||||
return
|
||||
|
||||
BattleScript_NoItemSteal::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUpTarget
|
||||
printstring STRINGID_PKMNSXMADEYINEFFECTIVE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
|
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 388 B |
@ -15,5 +15,5 @@ JASC-PAL
|
||||
248 136 136
|
||||
88 104 96
|
||||
184 192 192
|
||||
0 0 0
|
||||
248 248 248
|
||||
0 0 0
|
||||
|
||||
@ -14,6 +14,6 @@ JASC-PAL
|
||||
248 224 40
|
||||
248 136 136
|
||||
88 104 96
|
||||
184 192 192
|
||||
0 0 0
|
||||
200 192 128
|
||||
247 240 184
|
||||
0 0 0
|
||||
|
||||
|
Before Width: | Height: | Size: 708 B After Width: | Height: | Size: 620 B |
|
Before Width: | Height: | Size: 666 B After Width: | Height: | Size: 571 B |
@ -10,8 +10,8 @@ JASC-PAL
|
||||
120 24 24
|
||||
232 56 40
|
||||
136 120 104
|
||||
224 216 208
|
||||
192 176 160
|
||||
248 248 248
|
||||
200 192 176
|
||||
200 160 80
|
||||
232 208 136
|
||||
248 248 248
|
||||
|
||||
|
Before Width: | Height: | Size: 837 B After Width: | Height: | Size: 816 B |
@ -15,5 +15,5 @@ JASC-PAL
|
||||
248 160 72
|
||||
112 72 24
|
||||
176 112 48
|
||||
0 0 0
|
||||
0 0 0
|
||||
8 64 88
|
||||
176 168 176
|
||||
|
||||
|
Before Width: | Height: | Size: 898 B After Width: | Height: | Size: 820 B |
@ -666,7 +666,11 @@ struct BattleStruct
|
||||
u16 abilityPreventingSwitchout;
|
||||
u8 hpScale;
|
||||
u16 synchronizeMoveEffect;
|
||||
bool8 anyMonHasTransformed;
|
||||
u8 anyMonHasTransformed:1; // Only used in battle_tv.c
|
||||
u8 multipleSwitchInBattlers:4; // One bit per battler
|
||||
u8 multipleSwitchInState:2;
|
||||
u8 multipleSwitchInCursor:3;
|
||||
u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT];
|
||||
void (*savedCallback)(void);
|
||||
u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle
|
||||
u16 chosenItem[MAX_BATTLERS_COUNT];
|
||||
@ -740,7 +744,7 @@ struct BattleStruct
|
||||
u16 moveEffect2; // For Knock Off
|
||||
u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon.
|
||||
u8 quickClawBattlerId;
|
||||
struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member)
|
||||
struct LostItem itemLost[NUM_BATTLE_SIDES][PARTY_SIZE]; // Pokemon that had items consumed or stolen (two bytes per party member per side)
|
||||
u8 forcedSwitch:4; // For each battler
|
||||
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
|
||||
u8 blunderPolicy:1; // should blunder policy activate
|
||||
|
||||
@ -146,10 +146,8 @@ bool32 HasMagicCoatAffectedMove(u32 battler);
|
||||
bool32 HasSnatchAffectedMove(u32 battler);
|
||||
|
||||
// status checks
|
||||
bool32 AI_CanBeBurned(u32 battler, u32 ability);
|
||||
bool32 AI_CanGetFrostbite(u32 battler, u32 ability);
|
||||
bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability);
|
||||
bool32 AI_CanSleep(u32 battler, u32 ability);
|
||||
bool32 IsBattlerIncapacitated(u32 battler, u32 ability);
|
||||
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 ShouldPoisonSelf(u32 battler, u32 ability);
|
||||
|
||||
@ -269,6 +269,7 @@ extern const u8 BattleScript_WonderRoomEnds[];
|
||||
extern const u8 BattleScript_MagicRoomEnds[];
|
||||
extern const u8 BattleScript_TerrainEnds[];
|
||||
extern const u8 BattleScript_TerrainEnds_Ret[];
|
||||
extern const u8 BattleScript_GrassyTerrainEnds[];
|
||||
extern const u8 BattleScript_MudSportEnds[];
|
||||
extern const u8 BattleScript_WaterSportEnds[];
|
||||
extern const u8 BattleScript_SturdiedMsg[];
|
||||
|
||||
@ -202,7 +202,7 @@ bool32 IsBattlerMegaEvolved(u32 battler);
|
||||
bool32 IsBattlerPrimalReverted(u32 battler);
|
||||
bool32 IsBattlerUltraBursted(u32 battler);
|
||||
u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method);
|
||||
bool32 TryBattleFormChange(u32 battler, u16 method);
|
||||
bool32 TryBattleFormChange(u32 battler, u32 method);
|
||||
bool32 DoBattlersShareType(u32 battler1, u32 battler2);
|
||||
bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId);
|
||||
u32 GetIllusionMonSpecies(u32 battler);
|
||||
@ -249,10 +249,10 @@ bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
|
||||
bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 BattlerAtk, u32 battlerDef);
|
||||
|
||||
bool32 CanSleep(u32 battler);
|
||||
bool32 CanBePoisoned(u32 battlerAttacker, u32 battlerTarget);
|
||||
bool32 CanBeBurned(u32 battler);
|
||||
bool32 CanBeParalyzed(u32 battler);
|
||||
bool32 CanBeSlept(u32 battler, u32 ability);
|
||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 CanBeBurned(u32 battler, u32 ability);
|
||||
bool32 CanBeParalyzed(u32 battler, u32 ability);
|
||||
bool32 CanBeFrozen(u32 battler);
|
||||
bool32 CanGetFrostbite(u32 battler);
|
||||
bool32 CanBeConfused(u32 battler);
|
||||
|
||||
@ -63,8 +63,8 @@
|
||||
#define BS_EFFECT_BATTLER 2
|
||||
#define BS_FAINTED 3
|
||||
#define BS_ATTACKER_WITH_PARTNER 4 // for Cmd_updatestatusicon
|
||||
#define BS_FAINTED_LINK_MULTIPLE_1 5 // for openpartyscreen
|
||||
#define BS_FAINTED_LINK_MULTIPLE_2 6 // for openpartyscreen
|
||||
#define BS_FAINTED_MULTIPLE_1 5 // for openpartyscreen
|
||||
#define BS_FAINTED_MULTIPLE_2 6 // for openpartyscreen
|
||||
#define BS_BATTLER_0 7
|
||||
#define BS_ATTACKER_SIDE 8 // for Cmd_jumpifability
|
||||
#define BS_TARGET_SIDE 9 // for Cmd_jumpifability
|
||||
|
||||
@ -1629,7 +1629,7 @@
|
||||
#define SPECIES_URSHIFU_RAPID_STRIKE_STYLE_GIGANTAMAX 1522
|
||||
#define SPECIES_MIMIKYU_TOTEM_BUSTED 1523
|
||||
|
||||
#define SPECIES_EGG SPECIES_MIMIKYU_TOTEM_BUSTED + 1
|
||||
#define SPECIES_EGG (SPECIES_MIMIKYU_TOTEM_BUSTED + 1)
|
||||
|
||||
#define NUM_SPECIES SPECIES_EGG
|
||||
|
||||
|
||||
@ -161,6 +161,7 @@ enum RandomTag
|
||||
RNG_ACCURACY,
|
||||
RNG_CONFUSION,
|
||||
RNG_CRITICAL_HIT,
|
||||
RNG_CURSED_BODY,
|
||||
RNG_CUTE_CHARM,
|
||||
RNG_DAMAGE_MODIFIER,
|
||||
RNG_DIRE_CLAW,
|
||||
@ -179,6 +180,7 @@ enum RandomTag
|
||||
RNG_METRONOME,
|
||||
RNG_PARALYSIS,
|
||||
RNG_POISON_POINT,
|
||||
RNG_POISON_TOUCH,
|
||||
RNG_RAMPAGE_TURNS,
|
||||
RNG_SECONDARY_EFFECT,
|
||||
RNG_SECONDARY_EFFECT_2,
|
||||
|
||||
@ -507,7 +507,7 @@
|
||||
// or loop.
|
||||
#define BATTLE_TEST_STACK_SIZE 1024
|
||||
#define MAX_TURNS 16
|
||||
#define MAX_QUEUED_EVENTS 25
|
||||
#define MAX_QUEUED_EVENTS 30
|
||||
#define MAX_EXPECTED_ACTIONS 10
|
||||
|
||||
enum { BATTLE_TEST_SINGLES, BATTLE_TEST_DOUBLES, BATTLE_TEST_WILD, BATTLE_TEST_AI_SINGLES, BATTLE_TEST_AI_DOUBLES };
|
||||
|
||||
@ -8,6 +8,7 @@ bool8 UpdateVsSeekerStepCounter(void);
|
||||
void MapResetTrainerRematches(u16 mapGroup, u16 mapNum);
|
||||
void ClearRematchMovementByTrainerId(void);
|
||||
u16 GetRematchTrainerIdVSSeeker(u16 trainerId);
|
||||
bool32 IsVsSeekerEnabled(void);
|
||||
|
||||
#define VSSEEKER_RECHARGE_STEPS 100
|
||||
|
||||
|
||||
@ -1876,7 +1876,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_REST:
|
||||
if (!AI_CanSleep(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
if (!CanBeSlept(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
ADJUST_SCORE(-10);
|
||||
//fallthrough
|
||||
case EFFECT_RESTORE_HP:
|
||||
@ -3498,7 +3498,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
break;
|
||||
case EFFECT_REST:
|
||||
if (!(AI_CanSleep(battlerAtk, aiData->abilities[battlerAtk])))
|
||||
if (!(CanBeSlept(battlerAtk, aiData->abilities[battlerAtk])))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -3978,7 +3978,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_FLAME_ORB:
|
||||
if (!ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]) && AI_CanBeBurned(battlerAtk, aiData->abilities[battlerDef]))
|
||||
if (!ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]) && CanBeBurned(battlerAtk, aiData->abilities[battlerDef]))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
|
||||
@ -485,7 +485,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
|
||||
{
|
||||
//Yawn
|
||||
if (gStatuses3[battler] & STATUS3_YAWN
|
||||
&& AI_CanSleep(battler, monAbility)
|
||||
&& CanBeSlept(battler, monAbility)
|
||||
&& gBattleMons[battler].hp > gBattleMons[battler].maxHP / 3)
|
||||
{
|
||||
switchMon = TRUE;
|
||||
@ -1362,8 +1362,6 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon
|
||||
hazardDamage += spikesDamage;
|
||||
}
|
||||
|
||||
// Toxic Spikes
|
||||
// TODO: CanBePoisoned compatibility to avoid duplicate code
|
||||
if ((hazardFlags & SIDE_STATUS_TOXIC_SPIKES) && (defType1 != TYPE_POISON && defType2 != TYPE_POISON
|
||||
&& defType1 != TYPE_STEEL && defType2 != TYPE_STEEL
|
||||
&& ability != ABILITY_IMMUNITY && ability != ABILITY_POISON_HEAL && ability != ABILITY_COMATOSE
|
||||
|
||||
@ -2731,48 +2731,18 @@ bool32 IsBattlerIncapacitated(u32 battler, u32 ability)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 AI_CanSleep(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_INSOMNIA
|
||||
|| ability == ABILITY_VITAL_SPIRIT
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| (gFieldStatuses & (STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN))
|
||||
|| IsAbilityStatusProtected(battler))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanSleep(battlerDef, defAbility)
|
||||
if (!CanBeSlept(battlerDef, defAbility)
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) // shouldn't try to sleep mon that partner is trying to make sleep
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 AI_CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
u32 ability = AI_DATA->abilities[battlerDef];
|
||||
|
||||
if (!(CanPoisonType(battlerAtk, battlerDef))
|
||||
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battlerDef].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_IMMUNITY
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| AI_IsAbilityOnSide(battlerDef, ABILITY_PASTEL_VEIL)
|
||||
|| gBattleMons[battlerDef].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battlerDef)
|
||||
|| AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ShouldPoisonSelf(u32 battler, u32 ability)
|
||||
{
|
||||
if (AI_CanBePoisoned(battler, battler, 0) && (
|
||||
if (CanBePoisoned(battler, battler, GetBattlerAbility(battler)) && (
|
||||
ability == ABILITY_MARVEL_SCALE
|
||||
|| ability == ABILITY_POISON_HEAL
|
||||
|| ability == ABILITY_QUICK_FEET
|
||||
@ -2787,7 +2757,7 @@ bool32 ShouldPoisonSelf(u32 battler, u32 ability)
|
||||
|
||||
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanBePoisoned(battlerAtk, battlerDef, move)
|
||||
if (!CanBePoisoned(battlerAtk, battlerDef, GetBattlerAbility(battlerDef))
|
||||
|| AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove))
|
||||
@ -2800,20 +2770,9 @@ bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u3
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 AI_CanBeParalyzed(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_LIMBER
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC)
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanBeParalyzed(battlerDef, defAbility)
|
||||
if (!CanBeParalyzed(battlerDef, defAbility)
|
||||
|| AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0
|
||||
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
@ -2847,19 +2806,6 @@ bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battler
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanBeBurned(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_WATER_VEIL
|
||||
|| ability == ABILITY_WATER_BUBBLE
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| IS_BATTLER_OF_TYPE(battler, TYPE_FIRE)
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanGetFrostbite(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability == ABILITY_MAGMA_ARMOR
|
||||
@ -2874,7 +2820,7 @@ bool32 AI_CanGetFrostbite(u32 battler, u32 ability)
|
||||
|
||||
bool32 ShouldBurnSelf(u32 battler, u32 ability)
|
||||
{
|
||||
if (AI_CanBeBurned(battler, ability) && (
|
||||
if (CanBeBurned(battler, ability) && (
|
||||
ability == ABILITY_QUICK_FEET
|
||||
|| ability == ABILITY_HEATPROOF
|
||||
|| ability == ABILITY_MAGIC_GUARD
|
||||
@ -2888,7 +2834,7 @@ bool32 ShouldBurnSelf(u32 battler, u32 ability)
|
||||
|
||||
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!AI_CanBeBurned(battlerDef, defAbility)
|
||||
if (!CanBeBurned(battlerDef, defAbility)
|
||||
|| AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == AI_EFFECTIVENESS_x0
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove))
|
||||
|
||||
@ -517,7 +517,7 @@ static void RecordedPlayerHandleIntroTrainerBallThrow(u32 battler)
|
||||
else
|
||||
trainerPicId = gSaveBlock2Ptr->playerGender + TRAINER_BACK_PIC_BRENDAN;
|
||||
|
||||
trainerPal = gTrainerSprites[trainerPicId].palette.data;
|
||||
trainerPal = gTrainerBacksprites[trainerPicId].palette.data;
|
||||
BtlController_HandleIntroTrainerBallThrow(battler, 0xD6F9, trainerPal, 24, Intro_TryShinyAnimShowHealthbox);
|
||||
}
|
||||
|
||||
|
||||
@ -759,7 +759,7 @@ void BS_SetMaxMoveEffect(void)
|
||||
{
|
||||
static const u8 sSnoozeEffects[] = {TRUE, FALSE};
|
||||
if (!(gStatuses3[gBattlerTarget] & STATUS3_YAWN)
|
||||
&& CanSleep(gBattlerTarget)
|
||||
&& CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget))
|
||||
&& RandomElement(RNG_G_MAX_SNOOZE, sSnoozeEffects)) // 50% chance of success
|
||||
{
|
||||
gStatuses3[gBattlerTarget] |= STATUS3_YAWN_TURN(2);
|
||||
@ -865,7 +865,7 @@ void BS_TrySetStatus1(void)
|
||||
switch (status1)
|
||||
{
|
||||
case STATUS1_POISON:
|
||||
if (CanBePoisoned(gBattlerAttacker, gBattlerTarget))
|
||||
if (CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 |= STATUS1_POISON;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
||||
@ -873,7 +873,7 @@ void BS_TrySetStatus1(void)
|
||||
}
|
||||
break;
|
||||
case STATUS1_PARALYSIS:
|
||||
if (CanBeParalyzed(gBattlerTarget))
|
||||
if (CanBeParalyzed(gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 |= STATUS1_PARALYSIS;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
|
||||
@ -881,7 +881,7 @@ void BS_TrySetStatus1(void)
|
||||
}
|
||||
break;
|
||||
case STATUS1_SLEEP:
|
||||
if (CanSleep(gBattlerTarget))
|
||||
if (CanBeSlept(gBattlerTarget, GetBattlerAbility(gBattlerTarget)))
|
||||
{
|
||||
if (B_SLEEP_TURNS >= GEN_5)
|
||||
gBattleMons[gBattlerTarget].status1 |= STATUS1_SLEEP_TURN((Random() % 3) + 2);
|
||||
|
||||
@ -3109,7 +3109,8 @@ static void BattleStartClearSetData(void)
|
||||
{
|
||||
gBattleStruct->usedHeldItems[i][B_SIDE_PLAYER] = 0;
|
||||
gBattleStruct->usedHeldItems[i][B_SIDE_OPPONENT] = 0;
|
||||
gBattleStruct->itemLost[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
||||
gBattleStruct->itemLost[B_SIDE_PLAYER][i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
||||
gBattleStruct->itemLost[B_SIDE_OPPONENT][i].originalItem = GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM);
|
||||
gPartyCriticalHits[i] = 0;
|
||||
gBattleStruct->allowedToChangeFormInWeather[i][B_SIDE_PLAYER] = FALSE;
|
||||
gBattleStruct->allowedToChangeFormInWeather[i][B_SIDE_OPPONENT] = FALSE;
|
||||
|
||||
@ -2860,7 +2860,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
|
||||
if (i != gBattlersCount)
|
||||
break;
|
||||
if (!CanSleep(gEffectBattler))
|
||||
if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler);
|
||||
@ -2899,7 +2899,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STATUS_HAD_NO_EFFECT;
|
||||
RESET_RETURN
|
||||
}
|
||||
if (!CanBePoisoned(gBattleScripting.battler, gEffectBattler))
|
||||
if (!CanBePoisoned(gBattleScripting.battler, gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
statusChanged = TRUE;
|
||||
@ -2943,7 +2943,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CanBeBurned(gEffectBattler))
|
||||
if (!CanBeBurned(gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
statusChanged = TRUE;
|
||||
@ -3008,7 +3008,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
}
|
||||
if (!CanParalyzeType(gBattleScripting.battler, gEffectBattler))
|
||||
break;
|
||||
if (!CanBeParalyzed(gEffectBattler))
|
||||
if (!CanBeParalyzed(gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
break;
|
||||
|
||||
statusChanged = TRUE;
|
||||
@ -3046,7 +3046,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
}
|
||||
if (gBattleMons[gEffectBattler].status1)
|
||||
break;
|
||||
if (CanBePoisoned(gBattleScripting.battler, gEffectBattler))
|
||||
if (CanBePoisoned(gBattleScripting.battler, gEffectBattler, GetBattlerAbility(gEffectBattler)))
|
||||
{
|
||||
// It's redundant, because at this point we know the status1 value is 0.
|
||||
gBattleMons[gEffectBattler].status1 &= ~STATUS1_TOXIC_POISON;
|
||||
@ -3410,7 +3410,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
}
|
||||
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_STICKY_HOLD)
|
||||
{
|
||||
BattleScriptPushCursor();
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
gBattlescriptCurrInstr = BattleScript_NoItemSteal;
|
||||
|
||||
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
|
||||
@ -3533,6 +3533,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
case MOVE_EFFECT_SPECTRAL_THIEF:
|
||||
if (!NoAliveMonsForEitherParty())
|
||||
{
|
||||
bool32 contrary = (GetBattlerAbility(gBattlerAttacker) == ABILITY_CONTRARY);
|
||||
gBattleStruct->stolenStats[0] = 0; // Stats to steal.
|
||||
gBattleScripting.animArg1 = 0;
|
||||
for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++)
|
||||
@ -3554,16 +3555,16 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
if (gBattleScripting.animArg1 == 0)
|
||||
{
|
||||
if (byTwo)
|
||||
gBattleScripting.animArg1 = STAT_ANIM_PLUS2 + i;
|
||||
gBattleScripting.animArg1 = (contrary ? STAT_ANIM_MINUS2 : STAT_ANIM_PLUS2) + i;
|
||||
else
|
||||
gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + i;
|
||||
gBattleScripting.animArg1 = (contrary ? STAT_ANIM_MINUS1 : STAT_ANIM_PLUS1) + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (byTwo)
|
||||
gBattleScripting.animArg1 = STAT_ANIM_MULTIPLE_PLUS2;
|
||||
gBattleScripting.animArg1 = (contrary ? STAT_ANIM_MULTIPLE_MINUS2 : STAT_ANIM_MULTIPLE_PLUS2);
|
||||
else
|
||||
gBattleScripting.animArg1 = STAT_ANIM_MULTIPLE_PLUS1;
|
||||
gBattleScripting.animArg1 = (contrary ? STAT_ANIM_MULTIPLE_MINUS1 : STAT_ANIM_MULTIPLE_PLUS1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4590,7 +4591,7 @@ bool32 NoAliveMonsForEitherParty(void)
|
||||
return (NoAliveMonsForPlayer() || NoAliveMonsForOpponent());
|
||||
}
|
||||
|
||||
// For battles that aren't BATTLE_TYPE_LINK or BATTLE_TYPE_RECORDED_LINK, the only thing this
|
||||
// For battles that aren't BATTLE_TYPE_LINK or BATTLE_TYPE_RECORDED_LINK or trainer battles, the only thing this
|
||||
// command does is check whether the player has won/lost by totaling each team's HP. It then
|
||||
// sets gBattleOutcome accordingly, if necessary.
|
||||
static void Cmd_checkteamslost(void)
|
||||
@ -4606,10 +4607,12 @@ static void Cmd_checkteamslost(void)
|
||||
if (NoAliveMonsForOpponent())
|
||||
gBattleOutcome |= B_OUTCOME_WON;
|
||||
|
||||
// For link battles that haven't ended, count number of empty battler spots
|
||||
// In link multi battles, jump to pointer if more than 1 spot empty
|
||||
// Fair switching - everyone has to switch in most at the same time, without knowing which pokemon the other trainer selected.
|
||||
// In vanilla Emerald this was only used for link battles, in expansion it's also used for regular trainer battles.
|
||||
// For battles that haven't ended, count number of empty battler spots
|
||||
// In multi battles, jump to pointer if more than 1 spot empty
|
||||
// In non-multi battles, jump to pointer if 1 spot is missing on both sides
|
||||
if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)))
|
||||
if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER)))
|
||||
{
|
||||
s32 i, emptyPlayerSpots, emptyOpponentSpots;
|
||||
|
||||
@ -5482,7 +5485,7 @@ static void Cmd_moveend(void)
|
||||
}
|
||||
// Not strictly a protect effect, but works the same way
|
||||
else if (gProtectStructs[gBattlerTarget].beakBlastCharge
|
||||
&& CanBeBurned(gBattlerAttacker)
|
||||
&& CanBeBurned(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
@ -6761,7 +6764,7 @@ static void Cmd_openpartyscreen(void)
|
||||
u32 i, battler = 0;
|
||||
const u8 *failInstr = cmd->failInstr;
|
||||
|
||||
if (cmd->battler == BS_FAINTED_LINK_MULTIPLE_1)
|
||||
if (cmd->battler == BS_FAINTED_MULTIPLE_1)
|
||||
{
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||
{
|
||||
@ -6916,7 +6919,7 @@ static void Cmd_openpartyscreen(void)
|
||||
}
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (cmd->battler == BS_FAINTED_LINK_MULTIPLE_2)
|
||||
else if (cmd->battler == BS_FAINTED_MULTIPLE_2)
|
||||
{
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
||||
{
|
||||
@ -7134,13 +7137,8 @@ bool32 DoSwitchInAbilities(u32 battler)
|
||||
|| AbilityBattleEffects(ABILITYEFFECT_TRACE2, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
static void Cmd_switchineffects(void)
|
||||
static void UpdateSentMonFlags(u32 battler)
|
||||
{
|
||||
CMD_ARGS(u8 battler);
|
||||
|
||||
s32 i;
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
|
||||
UpdateSentPokesToOpponentValue(battler);
|
||||
|
||||
gHitMarker &= ~HITMARKER_FAINTED(battler);
|
||||
@ -7148,7 +7146,11 @@ static void Cmd_switchineffects(void)
|
||||
|
||||
if (!BattlerHasAi(battler))
|
||||
gBattleStruct->appearedInBattle |= gBitTable[gBattlerPartyIndexes[battler]];
|
||||
}
|
||||
|
||||
static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
||||
{
|
||||
u32 i;
|
||||
// Neutralizing Gas announces itself before hazards
|
||||
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS && gSpecialStatuses[battler].announceNeutralizingGas == 0)
|
||||
{
|
||||
@ -7266,7 +7268,7 @@ static void Cmd_switchineffects(void)
|
||||
BattleScriptPushCursor();
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_HP_TRAP;
|
||||
gBattlescriptCurrInstr = BattleScript_HealReplacementZMove;
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -7281,9 +7283,9 @@ static void Cmd_switchineffects(void)
|
||||
gDisableStructs[battler].truantSwitchInHack = 0;
|
||||
|
||||
if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE))
|
||||
return;
|
||||
return TRUE;
|
||||
else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
gDisableStructs[battler].stickyWebDone = FALSE;
|
||||
gDisableStructs[battler].spikesDone = FALSE;
|
||||
@ -7299,22 +7301,68 @@ static void Cmd_switchineffects(void)
|
||||
gBattleStruct->hpOnSwitchout[GetBattlerSide(i)] = gBattleMons[i].hp;
|
||||
}
|
||||
|
||||
if (cmd->battler == BS_FAINTED_LINK_MULTIPLE_1)
|
||||
{
|
||||
u32 hitmarkerFaintBits = gHitMarker >> 28;
|
||||
|
||||
gBattlerFainted++;
|
||||
while (1)
|
||||
{
|
||||
if (hitmarkerFaintBits & gBitTable[gBattlerFainted] && !(gAbsentBattlerFlags & gBitTable[gBattlerFainted]))
|
||||
break;
|
||||
if (gBattlerFainted >= gBattlersCount)
|
||||
break;
|
||||
gBattlerFainted++;
|
||||
}
|
||||
}
|
||||
gBattleStruct->forcedSwitch &= ~(gBitTable[battler]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE; // Effect's script plays.
|
||||
}
|
||||
|
||||
static void Cmd_switchineffects(void)
|
||||
{
|
||||
CMD_ARGS(u8 battler);
|
||||
u32 i, battler = GetBattlerForBattleScript(cmd->battler);
|
||||
|
||||
switch (cmd->battler)
|
||||
{
|
||||
// Multiple mons fainted and are being switched-in. Their abilities/hazards will play according to speed ties.
|
||||
case BS_FAINTED_MULTIPLE_1: // Saves the battlers.
|
||||
gBattleStruct->multipleSwitchInBattlers |= gBitTable[battler];
|
||||
UpdateSentMonFlags(battler);
|
||||
|
||||
// Increment fainted battler.
|
||||
do
|
||||
{
|
||||
gBattlerFainted++;
|
||||
if (gBattlerFainted >= gBattlersCount)
|
||||
break;
|
||||
if (gHitMarker & HITMARKER_FAINTED(gBattlerFainted) && !(gAbsentBattlerFlags & gBitTable[gBattlerFainted]))
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
return;
|
||||
case BS_FAINTED_MULTIPLE_2: // Plays hazards/abilities.
|
||||
switch (gBattleStruct->multipleSwitchInState)
|
||||
{
|
||||
case 0: // Sort battlers by speed
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
gBattleStruct->multipleSwitchInSortedBattlers[i] = i;
|
||||
SortBattlersBySpeed(gBattleStruct->multipleSwitchInSortedBattlers, FALSE);
|
||||
gBattleStruct->multipleSwitchInState++;
|
||||
gBattleStruct->multipleSwitchInCursor = 0;
|
||||
// Loop through all available battlers
|
||||
case 1:
|
||||
for (; gBattleStruct->multipleSwitchInCursor < gBattlersCount; gBattleStruct->multipleSwitchInCursor++)
|
||||
{
|
||||
gBattlerFainted = gBattleStruct->multipleSwitchInSortedBattlers[gBattleStruct->multipleSwitchInCursor];
|
||||
if (gBattleStruct->multipleSwitchInBattlers & gBitTable[gBattlerFainted])
|
||||
{
|
||||
if (DoSwitchInEffectsForBattler(gBattlerFainted))
|
||||
return;
|
||||
}
|
||||
}
|
||||
// All battlers done, end
|
||||
gBattleStruct->multipleSwitchInBattlers = 0;
|
||||
gBattleStruct->multipleSwitchInState = 0;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UpdateSentMonFlags(battler);
|
||||
if (!DoSwitchInEffectsForBattler(battler))
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7961,7 +8009,7 @@ static void BestowItem(u32 battlerAtk, u32 battlerDef)
|
||||
// Called by Cmd_removeitem. itemId represents the item that was removed, not being given.
|
||||
static bool32 TrySymbiosis(u32 battler, u32 itemId)
|
||||
{
|
||||
if (!gBattleStruct->itemLost[gBattlerPartyIndexes[battler]].stolen
|
||||
if (!gBattleStruct->itemLost[B_SIDE_PLAYER][gBattlerPartyIndexes[battler]].stolen
|
||||
&& gBattleStruct->changedItems[battler] == ITEM_NONE
|
||||
&& GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_EJECT_BUTTON
|
||||
&& GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_EJECT_PACK
|
||||
@ -9914,16 +9962,17 @@ static void Cmd_various(void)
|
||||
case VARIOUS_PSYCHO_SHIFT:
|
||||
{
|
||||
VARIOUS_ARGS(const u8 *failInstr);
|
||||
u32 targetAbility = GetBattlerAbility(gBattlerTarget);
|
||||
// Psycho shift works
|
||||
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget))
|
||||
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_TOXIC_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_TOXIC_POISON) && CanBePoisoned(gBattlerAttacker, gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_BURN) && CanBeBurned(gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_BURN) && CanBeBurned(gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && CanBeParalyzed(gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && CanBeParalyzed(gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) && CanSleep(gBattlerTarget))
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) && CanBeSlept(gBattlerTarget, targetAbility))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
|
||||
else if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE) && CanBeFrozen(gBattlerTarget))
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 5;
|
||||
@ -13383,7 +13432,16 @@ static void Cmd_handlefurycutter(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gDisableStructs[gBattlerAttacker].furyCutterCounter != 5
|
||||
u32 max;
|
||||
|
||||
if (B_UPDATED_MOVE_DATA >= GEN_6)
|
||||
max = 3;
|
||||
else if (B_UPDATED_MOVE_DATA == GEN_5)
|
||||
max = 4;
|
||||
else
|
||||
max = 5;
|
||||
|
||||
if (gDisableStructs[gBattlerAttacker].furyCutterCounter < max
|
||||
&& gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT) // Don't increment counter on first hit
|
||||
gDisableStructs[gBattlerAttacker].furyCutterCounter++;
|
||||
|
||||
@ -15297,6 +15355,13 @@ static void Cmd_givecaughtmon(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
||||
if (B_RESTORE_HELD_BATTLE_ITEMS >= GEN_9)
|
||||
{
|
||||
u16 lostItem = gBattleStruct->itemLost[B_SIDE_OPPONENT][gBattlerPartyIndexes[GetCatchingBattler()]].originalItem;
|
||||
if (lostItem != ITEM_NONE && ItemId_GetPocket(lostItem) != POCKET_BERRIES)
|
||||
SetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_HELD_ITEM, &lostItem); // Restore non-berry items
|
||||
}
|
||||
|
||||
if (GiveMonToPlayer(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]]) != MON_GIVEN_TO_PARTY)
|
||||
{
|
||||
if (!ShouldShowBoxWasFullMessage())
|
||||
|
||||
@ -1938,15 +1938,16 @@ static bool32 HasAtLeastFiveBadges(void)
|
||||
void IncrementRematchStepCounter(void)
|
||||
{
|
||||
#if FREE_MATCH_CALL == FALSE
|
||||
if (HasAtLeastFiveBadges()
|
||||
&& (I_VS_SEEKER_CHARGING != 0)
|
||||
&& (!CheckBagHasItem(ITEM_VS_SEEKER, 1)))
|
||||
{
|
||||
if (gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX)
|
||||
gSaveBlock1Ptr->trainerRematchStepCounter = STEP_COUNTER_MAX;
|
||||
else
|
||||
gSaveBlock1Ptr->trainerRematchStepCounter++;
|
||||
}
|
||||
if (!HasAtLeastFiveBadges())
|
||||
return;
|
||||
|
||||
if (IsVsSeekerEnabled())
|
||||
return;
|
||||
|
||||
if (gSaveBlock1Ptr->trainerRematchStepCounter >= STEP_COUNTER_MAX)
|
||||
gSaveBlock1Ptr->trainerRematchStepCounter = STEP_COUNTER_MAX;
|
||||
else
|
||||
gSaveBlock1Ptr->trainerRematchStepCounter++;
|
||||
#endif //FREE_MATCH_CALL
|
||||
}
|
||||
|
||||
|
||||
@ -932,11 +932,11 @@ u8 GetBattlerForBattleScript(u8 caseId)
|
||||
case BS_FAINTED:
|
||||
ret = gBattlerFainted;
|
||||
break;
|
||||
case BS_FAINTED_LINK_MULTIPLE_1:
|
||||
case BS_FAINTED_MULTIPLE_1:
|
||||
ret = gBattlerFainted;
|
||||
break;
|
||||
case BS_ATTACKER_WITH_PARTNER:
|
||||
case BS_FAINTED_LINK_MULTIPLE_2:
|
||||
case BS_FAINTED_MULTIPLE_2:
|
||||
case BS_ATTACKER_SIDE:
|
||||
case BS_TARGET_SIDE:
|
||||
case BS_PLAYER1:
|
||||
@ -1691,7 +1691,10 @@ static bool32 EndTurnTerrain(u32 terrainFlag, u32 stringTableId)
|
||||
gFieldStatuses &= ~terrainFlag;
|
||||
TryToRevertMimicryAndFlags();
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = stringTableId;
|
||||
BattleScriptExecute(BattleScript_TerrainEnds);
|
||||
if (terrainFlag & STATUS_FIELD_GRASSY_TERRAIN)
|
||||
BattleScriptExecute(BattleScript_GrassyTerrainEnds);
|
||||
else
|
||||
BattleScriptExecute(BattleScript_TerrainEnds);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -3364,7 +3367,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
|
||||
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION)
|
||||
{
|
||||
// confusion dmg
|
||||
if (RandomWeighted(RNG_CONFUSION, (B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 2 : 1), 1))
|
||||
if (RandomPercentage(RNG_CONFUSION, (B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50)))
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = TRUE;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
@ -5339,7 +5342,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& !IsAbilityOnSide(gBattlerAttacker, ABILITY_AROMA_VEIL)
|
||||
&& gBattleMons[gBattlerAttacker].pp[gChosenMovePos] != 0
|
||||
&& !(GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX) // TODO: Max Moves don't make contact, useless?
|
||||
&& (Random() % 3) == 0)
|
||||
&& RandomPercentage(RNG_CURSED_BODY, 30))
|
||||
{
|
||||
gDisableStructs[gBattlerAttacker].disabledMove = gChosenMove;
|
||||
gDisableStructs[gBattlerAttacker].disableTimer = 4;
|
||||
@ -5500,8 +5503,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
}
|
||||
break;
|
||||
case ABILITY_EFFECT_SPORE:
|
||||
{
|
||||
u32 ability = GetBattlerAbility(gBattlerAttacker);
|
||||
if ((!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS) || B_POWDER_GRASS < GEN_6)
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_OVERCOAT
|
||||
&& ability != ABILITY_OVERCOAT
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES)
|
||||
{
|
||||
u32 poison, paralysis, sleep;
|
||||
@ -5529,7 +5534,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanSleep(gBattlerAttacker)
|
||||
&& CanBeSlept(gBattlerAttacker, ability)
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker))
|
||||
{
|
||||
@ -5541,6 +5546,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
effect++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ABILITY_POISON_POINT:
|
||||
if (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_POISON_POINT, 30) : RandomChance(RNG_POISON_POINT, 1, 3))
|
||||
@ -5550,7 +5556,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanBePoisoned(gBattlerTarget, gBattlerAttacker)
|
||||
&& CanBePoisoned(gBattlerTarget, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker))
|
||||
{
|
||||
@ -5571,7 +5577,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanBeParalyzed(gBattlerAttacker)
|
||||
&& CanBeParalyzed(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker))
|
||||
{
|
||||
@ -5591,7 +5597,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& (IsMoveMakingContact(move, gBattlerAttacker))
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& CanBeBurned(gBattlerAttacker)
|
||||
&& CanBeBurned(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
|
||||
&& (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_FLAME_BODY, 30) : RandomChance(RNG_FLAME_BODY, 1, 3)))
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN;
|
||||
@ -5808,11 +5814,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget)
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget))
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS
|
||||
&& IsMoveMakingContact(move, gBattlerAttacker)
|
||||
&& TARGET_TURN_DAMAGED // Need to actually hit the target
|
||||
&& (Random() % 3) == 0)
|
||||
&& RandomPercentage(RNG_POISON_TOUCH, 30))
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_POISON;
|
||||
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
|
||||
@ -5826,7 +5832,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget)
|
||||
&& CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget))
|
||||
&& TARGET_TURN_DAMAGED // Need to actually hit the target
|
||||
&& RandomWeighted(RNG_TOXIC_CHAIN, 7, 3))
|
||||
{
|
||||
@ -6276,7 +6282,14 @@ u32 GetBattlerAbility(u32 battler)
|
||||
bool32 noAbilityShield = GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD;
|
||||
|
||||
if (gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed)
|
||||
{
|
||||
// Edge case: pokemon under the effect of gastro acid transforms into a pokemon with Comatose (Todo: verify how other unsuppressable abilities behave)
|
||||
if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED
|
||||
&& gStatuses3[battler] & STATUS3_GASTRO_ACID
|
||||
&& gBattleMons[battler].ability == ABILITY_COMATOSE)
|
||||
return ABILITY_NONE;
|
||||
return gBattleMons[battler].ability;
|
||||
}
|
||||
|
||||
if (gStatuses3[battler] & STATUS3_GASTRO_ACID)
|
||||
return ABILITY_NONE;
|
||||
@ -6289,6 +6302,7 @@ u32 GetBattlerAbility(u32 battler)
|
||||
if (((IsMoldBreakerTypeAbility(gBattleMons[gBattlerAttacker].ability)
|
||||
&& !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID))
|
||||
|| gMovesInfo[gCurrentMove].ignoresTargetAbility)
|
||||
&& battler != gBattlerAttacker
|
||||
&& gAbilitiesInfo[gBattleMons[battler].ability].breakable
|
||||
&& noAbilityShield
|
||||
&& gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker
|
||||
@ -6410,83 +6424,78 @@ bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag)
|
||||
return IsBattlerGrounded(battler);
|
||||
}
|
||||
|
||||
bool32 CanSleep(u32 battler)
|
||||
bool32 CanBeSlept(u32 battler, u32 ability)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if (ability == ABILITY_INSOMNIA
|
||||
|| ability == ABILITY_VITAL_SPIRIT
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityOnSide(battler, ABILITY_SWEET_VEIL)
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBePoisoned(u32 battlerAttacker, u32 battlerTarget)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battlerTarget);
|
||||
|
||||
if (!(CanPoisonType(battlerAttacker, battlerTarget))
|
||||
|| gSideStatuses[GetBattlerSide(battlerTarget)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battlerTarget].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_IMMUNITY
|
||||
|| ability == ABILITY_VITAL_SPIRIT
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| IsAbilityOnSide(battlerTarget, ABILITY_PASTEL_VEIL)
|
||||
|| IsAbilityStatusProtected(battlerTarget)
|
||||
|| IsBattlerTerrainAffected(battlerTarget, STATUS_FIELD_MISTY_TERRAIN))
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityOnSide(battler, ABILITY_SWEET_VEIL)
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeBurned(u32 battler)
|
||||
bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (!(CanPoisonType(battlerAtk, battlerDef))
|
||||
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battlerDef].status1 & STATUS1_ANY
|
||||
|| defAbility == ABILITY_IMMUNITY
|
||||
|| defAbility == ABILITY_COMATOSE
|
||||
|| defAbility == ABILITY_PURIFYING_SALT
|
||||
|| IsAbilityOnSide(battlerDef, ABILITY_PASTEL_VEIL)
|
||||
|| IsAbilityStatusProtected(battlerDef)
|
||||
|| IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeBurned(u32 battler, u32 ability)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_FIRE)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_WATER_VEIL
|
||||
|| ability == ABILITY_WATER_BUBBLE
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_THERMAL_EXCHANGE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeParalyzed(u32 battler, u32 ability)
|
||||
{
|
||||
if ((B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC))
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| ability == ABILITY_WATER_VEIL
|
||||
|| ability == ABILITY_WATER_BUBBLE
|
||||
|| ability == ABILITY_LIMBER
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_THERMAL_EXCHANGE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeParalyzed(u32 battler)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if ((B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_ELECTRIC))
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| ability == ABILITY_LIMBER
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 CanBeFrozen(u32 battler)
|
||||
{
|
||||
u16 ability = GetBattlerAbility(battler);
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
|
||||
|| IsBattlerWeatherAffected(battler, B_WEATHER_SUN)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| ability == ABILITY_MAGMA_ARMOR
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
|| IsBattlerWeatherAffected(battler, B_WEATHER_SUN)
|
||||
|| gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD
|
||||
|| ability == ABILITY_MAGMA_ARMOR
|
||||
|| ability == ABILITY_COMATOSE
|
||||
|| ability == ABILITY_PURIFYING_SALT
|
||||
|| gBattleMons[battler].status1 & STATUS1_ANY
|
||||
|| IsAbilityStatusProtected(battler)
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
@ -6509,8 +6518,8 @@ bool32 CanGetFrostbite(u32 battler)
|
||||
bool32 CanBeConfused(u32 battler)
|
||||
{
|
||||
if (GetBattlerAbility(battler) == ABILITY_OWN_TEMPO
|
||||
|| gBattleMons[battler].status2 & STATUS2_CONFUSION
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
|| gBattleMons[battler].status2 & STATUS2_CONFUSION
|
||||
|| IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
@ -8026,7 +8035,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
|
||||
switch (battlerHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_TOXIC_ORB:
|
||||
if (CanBePoisoned(battler, battler))
|
||||
if (CanBePoisoned(battler, battler, GetBattlerAbility(battler)))
|
||||
{
|
||||
effect = ITEM_STATUS_CHANGE;
|
||||
gBattleMons[battler].status1 = STATUS1_TOXIC_POISON;
|
||||
@ -8035,7 +8044,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_FLAME_ORB:
|
||||
if (CanBeBurned(battler))
|
||||
if (CanBeBurned(battler, battlerAbility))
|
||||
{
|
||||
effect = ITEM_STATUS_CHANGE;
|
||||
gBattleMons[battler].status1 = STATUS1_BURN;
|
||||
@ -8300,7 +8309,7 @@ u8 IsMonDisobedient(void)
|
||||
obedienceLevel = levelReferenced - obedienceLevel;
|
||||
|
||||
calc = (Random() & 255);
|
||||
if (calc < obedienceLevel && CanSleep(gBattlerAttacker))
|
||||
if (calc < obedienceLevel && CanBeSlept(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)))
|
||||
{
|
||||
// try putting asleep
|
||||
int i;
|
||||
@ -10734,12 +10743,12 @@ bool32 CanBattlerFormChange(u32 battler, u16 method)
|
||||
return DoesSpeciesHaveFormChangeMethod(gBattleMons[battler].species, method);
|
||||
}
|
||||
|
||||
bool32 TryBattleFormChange(u32 battler, u16 method)
|
||||
bool32 TryBattleFormChange(u32 battler, u32 method)
|
||||
{
|
||||
u8 monId = gBattlerPartyIndexes[battler];
|
||||
u8 side = GetBattlerSide(battler);
|
||||
u32 monId = gBattlerPartyIndexes[battler];
|
||||
u32 side = GetBattlerSide(battler);
|
||||
struct Pokemon *party = GetBattlerParty(battler);
|
||||
u16 targetSpecies;
|
||||
u32 targetSpecies;
|
||||
|
||||
if (!CanBattlerFormChange(battler, method))
|
||||
return FALSE;
|
||||
@ -10777,10 +10786,14 @@ bool32 TryBattleFormChange(u32 battler, u16 method)
|
||||
|
||||
if (restoreSpecies)
|
||||
{
|
||||
u32 abilityForm = gBattleMons[battler].ability;
|
||||
// Reverts the original species
|
||||
TryToSetBattleFormChangeMoves(&party[monId], method);
|
||||
SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[side][monId]);
|
||||
RecalcBattlerStats(battler, &party[monId]);
|
||||
// Battler data is not updated with regular form's ability, not doing so could cause wrong ability activation.
|
||||
if (method == FORM_CHANGE_FAINT)
|
||||
gBattleMons[battler].ability = abilityForm;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -11064,9 +11077,9 @@ void TryRestoreHeldItems(void)
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
// Check if held items should be restored after battle based on generation
|
||||
if (B_RESTORE_HELD_BATTLE_ITEMS >= GEN_9 || gBattleStruct->itemLost[i].stolen || returnNPCItems)
|
||||
if (B_RESTORE_HELD_BATTLE_ITEMS >= GEN_9 || gBattleStruct->itemLost[B_SIDE_PLAYER][i].stolen || returnNPCItems)
|
||||
{
|
||||
u16 lostItem = gBattleStruct->itemLost[i].originalItem;
|
||||
u16 lostItem = gBattleStruct->itemLost[B_SIDE_PLAYER][i].originalItem;
|
||||
|
||||
// Check if the lost item is a berry and the mon is not holding it
|
||||
if (ItemId_GetPocket(lostItem) == POCKET_BERRIES && GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM) != lostItem)
|
||||
@ -11127,8 +11140,8 @@ void TrySaveExchangedItem(u32 battler, u16 stolenItem)
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
|
||||
&& !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
|
||||
&& GetBattlerSide(battler) == B_SIDE_PLAYER
|
||||
&& stolenItem == gBattleStruct->itemLost[gBattlerPartyIndexes[battler]].originalItem)
|
||||
gBattleStruct->itemLost[gBattlerPartyIndexes[battler]].stolen = TRUE;
|
||||
&& stolenItem == gBattleStruct->itemLost[B_SIDE_PLAYER][gBattlerPartyIndexes[battler]].originalItem)
|
||||
gBattleStruct->itemLost[B_SIDE_PLAYER][gBattlerPartyIndexes[battler]].stolen = TRUE;
|
||||
}
|
||||
|
||||
bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes)
|
||||
|
||||
@ -2548,7 +2548,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
|
||||
#else
|
||||
.name = _("SuprswtSyrup"),
|
||||
#endif
|
||||
.description = COMPOUND_STRING("Lowers the foe's Speed."),
|
||||
.description = COMPOUND_STRING("Lowers the foe's Evasion."),
|
||||
.aiRating = 5,
|
||||
},
|
||||
|
||||
|
||||
@ -15646,7 +15646,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
||||
|
||||
[MOVE_FLORAL_HEALING] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_MOVE_NAME("FloralHealng", "Floral Healng"),
|
||||
.name = HANDLE_EXPANDED_MOVE_NAME("FloralHealng", "Floral Healing"),
|
||||
.description = COMPOUND_STRING(
|
||||
"Restores an ally's HP.\n"
|
||||
"Heals more on grass."),
|
||||
@ -18422,7 +18422,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
||||
|
||||
[MOVE_JUNGLE_HEALING] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_MOVE_NAME("JungleHealng", "Jungle Healng"),
|
||||
.name = HANDLE_EXPANDED_MOVE_NAME("JungleHealng", "Jungle Healing"),
|
||||
.description = COMPOUND_STRING(
|
||||
"Heals HP and status of\n"
|
||||
"itself and allies in battle."),
|
||||
@ -21042,7 +21042,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
|
||||
},
|
||||
[MOVE_OCEANIC_OPERETTA] =
|
||||
{
|
||||
.name = COMPOUND_STRING("Oceaning Operetta"),
|
||||
.name = COMPOUND_STRING("Oceanic Operetta"),
|
||||
.description = sNullDescription,
|
||||
.effect = EFFECT_HIT,
|
||||
.power = 195,
|
||||
|
||||
@ -76,11 +76,7 @@ const struct SpeciesInfo gSpeciesInfo[] =
|
||||
.categoryName = _("Unknown"),
|
||||
.height = 0,
|
||||
.weight = 0,
|
||||
.description = COMPOUND_STRING(
|
||||
"This is a newly discovered Pokémon.\n"
|
||||
"It is currently under investigation.\n"
|
||||
"No detailed information is available\n"
|
||||
"at this time."),
|
||||
.description = gFallbackPokedexText,
|
||||
.pokemonScale = 256,
|
||||
.pokemonOffset = 0,
|
||||
.trainerScale = 256,
|
||||
|
||||
@ -4143,6 +4143,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] =
|
||||
.baseSpAttack = 60, \
|
||||
.baseSpDefense = 100, \
|
||||
.weight = 400, \
|
||||
.description = gMiniorMeteorPokedexText, \
|
||||
.frontPic = gMonFrontPic_MiniorMeteor, \
|
||||
.frontPicSize = MON_COORDS_SIZE(48, 40), \
|
||||
.frontPicYOffset = 14, \
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
// fallback
|
||||
const u8 gFallbackPokedexText[] = _(
|
||||
"This is a newly discovered Pokémon.\n"
|
||||
"It is currently under investigation.\n"
|
||||
"No detailed information is available\n"
|
||||
"at this time.");
|
||||
|
||||
// Gen 1 families
|
||||
const u8 gRaticateAlolanPokedexText[] = _(
|
||||
"It forms a group of Rattata, which it \n"
|
||||
|
||||
@ -577,6 +577,14 @@ u16 GetRematchTrainerIdVSSeeker(u16 trainerId)
|
||||
return gRematchTable[tableId].trainerIds[rematchTrainerIdx];
|
||||
}
|
||||
|
||||
bool32 IsVsSeekerEnabled(void)
|
||||
{
|
||||
if (I_VS_SEEKER_CHARGING == 0)
|
||||
return FALSE;
|
||||
|
||||
return (CheckBagHasItem(ITEM_VS_SEEKER, 1));
|
||||
}
|
||||
|
||||
static bool8 ObjectEventIdIsSane(u8 objectEventId)
|
||||
{
|
||||
struct ObjectEvent *objectEvent = &gObjectEvents[objectEventId];
|
||||
|
||||
@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battler
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Chi-Yu!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN);
|
||||
MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
54
test/battle/ability/comatose.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Comatose prevents status-inducing moves")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISONPOWDER; }
|
||||
PARAMETRIZE { move = MOVE_SLEEP_POWDER; }
|
||||
PARAMETRIZE { move = MOVE_THUNDER_WAVE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
MESSAGE("Komala is drowsing!");
|
||||
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ABILITY_POPUP(player, ABILITY_COMATOSE);
|
||||
MESSAGE("It doesn't affect Komala…");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Comatose may be suppressed if pokemon transformed into a pokemon with Comatose ability and was under the effects of Gastro Acid")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISONPOWDER; }
|
||||
PARAMETRIZE { move = MOVE_SLEEP_POWDER; }
|
||||
PARAMETRIZE { move = MOVE_THUNDER_WAVE; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); Speed(30); }
|
||||
OPPONENT(SPECIES_DITTO) { Speed(20); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_GASTRO_ACID); MOVE(opponent, MOVE_TRANSFORM); }
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
MESSAGE("Komala is drowsing!");
|
||||
MESSAGE("Komala used Gastro Acid!");
|
||||
MESSAGE("Foe Ditto used Transform!");
|
||||
MESSAGE("Foe Ditto transformed into Komala!");
|
||||
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
if (move == MOVE_POISONPOWDER) { STATUS_ICON(opponent, poison: TRUE); }
|
||||
else if (move == MOVE_TOXIC) { STATUS_ICON(opponent, badPoison: TRUE); }
|
||||
else if (move == MOVE_THUNDER_WAVE) { STATUS_ICON(opponent, paralysis: TRUE); }
|
||||
else if (move == MOVE_SLEEP_POWDER) { STATUS_ICON(opponent, sleep: TRUE); }
|
||||
}
|
||||
}
|
||||
@ -106,23 +106,122 @@ SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion holds a T
|
||||
|
||||
SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion poisons a target with Synchronize, Synchronize will not poison Poison- or Steel-type Pokémon")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_ABRA) { Ability(ABILITY_SYNCHRONIZE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TOXIC); }
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
if (move == MOVE_TOXIC)
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
else
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player);
|
||||
STATUS_ICON(player, badPoison: TRUE);
|
||||
STATUS_ICON(player, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Corrosion cannot bypass moves or Abilities that prevent poisoning, such as Safeguard or Immunity");
|
||||
TO_DO_BATTLE_TEST("If the Pokémon with this Ability uses Magic Coat to reflect a status move that inflicts poison, the reflected move will be able to poison Poison- or Steel-type Pokémon.");
|
||||
TO_DO_BATTLE_TEST("Moves used by a Pokémon with Corrosion that are reflected by Magic Coat or Magic Bounce do not retain the ability to poison Poison- or Steel-type Pokémon.")
|
||||
SINGLE_BATTLE_TEST("Corrosion cannot bypass moves that prevent poisoning such as Safeguard")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SAFEGUARD); MOVE(player, move); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Corrosion cannot bypass abilities that prevent poisoning such as Immunity")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_IMMUNITY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Corrosion allows the Pokémon with the ability to poison a Steel or Poison-type opponent by using Magic Coat")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_BELDUM);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MAGIC_COAT); MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_COAT, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player); // Bounced by Magic Coat
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
if (move == MOVE_TOXIC)
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
else
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Corrosion's effect is lost if the move used by the Pokémon with the ability is reflected by Magic Coat")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move = MOVE_POISON_POWDER; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
|
||||
ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON);
|
||||
ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT);
|
||||
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_MAGIC_COAT); MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_COAT, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player);
|
||||
if (move == MOVE_TOXIC)
|
||||
STATUS_ICON(opponent, badPoison: TRUE);
|
||||
else
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
test/battle/ability/cursed_body.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Cursed Body triggers 30% of the time")
|
||||
{
|
||||
PASSES_RANDOMLY(3, 10, RNG_CURSED_BODY);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_AQUA_JET); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AQUA_JET, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_CURSED_BODY);
|
||||
MESSAGE("Wobbuffet's Aqua Jet was disabled by Foe Frillish's Cursed Body!");
|
||||
}
|
||||
}
|
||||
@ -56,6 +56,7 @@ SINGLE_BATTLE_TEST("Download raises Sp.Attack if enemy has lower Sp. Def than De
|
||||
SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet", s16 damagePhysical, s16 damageSpecial)
|
||||
{
|
||||
u32 ability;
|
||||
|
||||
PARAMETRIZE { ability = ABILITY_TRACE; }
|
||||
PARAMETRIZE { ability = ABILITY_DOWNLOAD; }
|
||||
GIVEN {
|
||||
@ -73,13 +74,13 @@ SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet
|
||||
// Everyone faints.
|
||||
|
||||
SEND_IN_MESSAGE("Porygon");
|
||||
MESSAGE("2 sent out Porygon2!");
|
||||
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(player, ABILITY_DOWNLOAD);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Porygon's Download raised its Attack!");
|
||||
}
|
||||
MESSAGE("2 sent out Porygon2!");
|
||||
|
||||
if (ability == ABILITY_DOWNLOAD)
|
||||
{
|
||||
ABILITY_POPUP(opponent, ABILITY_DOWNLOAD);
|
||||
|
||||
4
test/battle/ability/full_metal_body.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for Full Metal Body are handled in test/battle/ability/clear_body.c
|
||||
@ -78,23 +78,29 @@ DOUBLE_BATTLE_TEST("Intimidate doesn't activate on an empty field in a double ba
|
||||
// Everyone faints.
|
||||
|
||||
SEND_IN_MESSAGE("Ekans");
|
||||
MESSAGE("2 sent out Arbok!");
|
||||
SEND_IN_MESSAGE("Abra");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Arbok's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Wynaut's attack!");
|
||||
|
||||
}
|
||||
MESSAGE("2 sent out Arbok!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Ekans's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Abra's attack!");
|
||||
}
|
||||
SEND_IN_MESSAGE("Abra");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
// Intimidate activates after all battlers have been brought out
|
||||
ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Arbok's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Ekans's Intimidate cuts Foe Wynaut's attack!");
|
||||
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Ekans's attack!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
MESSAGE("Foe Arbok's Intimidate cuts Abra's attack!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,6 +217,35 @@ SINGLE_BATTLE_TEST("Intimidate can not further lower opponents Atk stat if it is
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Intimidate is not going to trigger if a mon switches out through u-turn and the opposing field is empty")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WYNAUT) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_TREECKO);
|
||||
OPPONENT(SPECIES_TORCHIC);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponentRight, MOVE_HEALING_WISH);
|
||||
MOVE(playerLeft, MOVE_U_TURN, target: opponentLeft);
|
||||
SEND_OUT(playerLeft, 2);
|
||||
SEND_OUT(opponentLeft, 2);
|
||||
SEND_OUT(opponentRight, 3);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEALING_WISH, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, playerLeft);
|
||||
HP_BAR(opponentLeft);
|
||||
MESSAGE("2 sent out Treecko!");
|
||||
MESSAGE("2 sent out Torchic!");
|
||||
NOT ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutralizing Gas")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
@ -49,8 +49,8 @@ AI_SINGLE_BATTLE_TEST("AI doesn't use accuracy-lowering moves if it knows that t
|
||||
for (j = MOVE_NONE + 1; j < MOVES_COUNT; j++)
|
||||
{
|
||||
if (gMovesInfo[j].effect == EFFECT_ACCURACY_DOWN || gMovesInfo[j].effect == EFFECT_ACCURACY_DOWN_2) {
|
||||
PARAMETRIZE{ moveAI = j; abilityAI = ABILITY_SWIFT_SWIM; }
|
||||
PARAMETRIZE{ moveAI = j; abilityAI = ABILITY_MOLD_BREAKER; }
|
||||
PARAMETRIZE { moveAI = j; abilityAI = ABILITY_SWIFT_SWIM; }
|
||||
PARAMETRIZE { moveAI = j; abilityAI = ABILITY_MOLD_BREAKER; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -56,6 +56,23 @@ SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the user")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Own Tempo is ignored by Mold Breaker")
|
||||
{
|
||||
KNOWN_FAILING; // Ideally the func CanBeConfused should be split into AttackerCanBeConfused and TargetCanBeConfused or we do it in the same func but have a check for when battlerAtk == battlerDef
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE);
|
||||
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); }
|
||||
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CONFUSE_RAY); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_OWN_TEMPO);
|
||||
MESSAGE("Foe Slowpoke's Own Tempo prevents confusion!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Own Tempo cures confusion obtained from an opponent with Mold Breaker")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
|
||||
77
test/battle/ability/poison_touch.c
Normal file
@ -0,0 +1,77 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Poison Touch has a 30% chance to poison when attacking with contact moves")
|
||||
{
|
||||
PASSES_RANDOMLY(3, 10, RNG_POISON_TOUCH);
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].makesContact);
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Poison Touch only applies when using contact moves")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move = MOVE_SWIFT; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].makesContact);
|
||||
ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact);
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
if (gMovesInfo[move].makesContact) {
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
} else {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Poison Touch applies between multi-hit move hits")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_ARM_THRUST].effect == EFFECT_MULTI_HIT);
|
||||
ASSUME(gMovesInfo[MOVE_ARM_THRUST].makesContact);
|
||||
ASSUME(gItemsInfo[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN);
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_PECHA_BERRY); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ARM_THRUST); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ARM_THRUST, player);
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
MESSAGE("Foe Wobbuffet's Pecha Berry cured poison!");
|
||||
STATUS_ICON(opponent, poison: FALSE);
|
||||
ABILITY_POPUP(player, ABILITY_POISON_TOUCH);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
|
||||
MESSAGE("Foe Wobbuffet was poisoned by Grimer's Poison Touch!");
|
||||
STATUS_ICON(opponent, poison: TRUE);
|
||||
}
|
||||
}
|
||||
18
test/battle/ability/sticky_hold.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Sticky Hold prevents item theft")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM));
|
||||
PLAYER(SPECIES_URSALUNA) { Item(ITEM_NONE); }
|
||||
OPPONENT(SPECIES_GASTRODON) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_LIFE_ORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THIEF); }
|
||||
} SCENE {
|
||||
MESSAGE("Ursaluna used Thief!");
|
||||
ABILITY_POPUP(opponent, ABILITY_STICKY_HOLD);
|
||||
MESSAGE("Foe Gastrodon's Sticky Hold made Thief ineffective!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,9 +107,9 @@ SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all batt
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
SEND_IN_MESSAGE("Kingambit");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_SUPREME_OVERLORD);
|
||||
MESSAGE("Kingambit gained strength from the fallen!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
128
test/battle/ability/switch_in_abilities.c
Normal file
@ -0,0 +1,128 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order at the battle's start - Single Battle")
|
||||
{
|
||||
u32 spdPlayer, spdOpponent;
|
||||
|
||||
PARAMETRIZE { spdPlayer = 5; spdOpponent = 1; }
|
||||
PARAMETRIZE { spdOpponent = 5; spdPlayer = 1; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_EKANS) { Speed(spdPlayer); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_NINETALES) { Speed(spdOpponent); Ability(ABILITY_DROUGHT); }
|
||||
} WHEN {
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
if (spdPlayer > spdOpponent) {
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
|
||||
} else {
|
||||
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order at the battle's start - Double Battle")
|
||||
{
|
||||
u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2;
|
||||
|
||||
PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; }
|
||||
PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; }
|
||||
PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KYOGRE) { Speed(spdPlayer1); Ability(ABILITY_DRIZZLE); }
|
||||
PLAYER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_PORYGON2) { Speed(spdOpponent1); Ability(ABILITY_DOWNLOAD); }
|
||||
OPPONENT(SPECIES_PINSIR) { Speed(spdOpponent2); Ability(ABILITY_MOLD_BREAKER); }
|
||||
} WHEN {
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
if (spdPlayer1 == 5) {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DRIZZLE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_MOLD_BREAKER);
|
||||
} else if (spdOpponent2 == 5) {
|
||||
ABILITY_POPUP(opponentRight, ABILITY_MOLD_BREAKER);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DRIZZLE);
|
||||
} else {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DRIZZLE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_MOLD_BREAKER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - Single Battle")
|
||||
{
|
||||
u32 spdPlayer, spdOpponent;
|
||||
|
||||
PARAMETRIZE { spdPlayer = 5; spdOpponent = 1; }
|
||||
PARAMETRIZE { spdOpponent = 5; spdPlayer = 1; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
PLAYER(SPECIES_EKANS) { Speed(spdPlayer); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
OPPONENT(SPECIES_PORYGON2) { Speed(spdOpponent); Ability(ABILITY_DOWNLOAD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); }
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Explosion!");
|
||||
if (spdPlayer > spdOpponent) {
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponent, ABILITY_DOWNLOAD);
|
||||
} else {
|
||||
ABILITY_POPUP(opponent, ABILITY_DOWNLOAD);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - Double Battle")
|
||||
{
|
||||
u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2;
|
||||
|
||||
PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; }
|
||||
PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; }
|
||||
PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); }
|
||||
PLAYER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); }
|
||||
OPPONENT(SPECIES_WEEZING_GALARIAN) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); }
|
||||
OPPONENT(SPECIES_VULPIX_ALOLAN) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(playerRight, 3); SEND_OUT(opponentRight, 3); }
|
||||
TURN { ; }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Explosion!");
|
||||
if (spdPlayer1 == 5) {
|
||||
ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING);
|
||||
} else if (spdOpponent2 == 5) {
|
||||
ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM);
|
||||
} else {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM);
|
||||
ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battler
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Chien-Pao!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN);
|
||||
MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battl
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Wo-Chien!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_TABLETS_OF_RUIN);
|
||||
MESSAGE("Wo-Chien's Tablets of Ruin weakened the Attack of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battle
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Ting-Lu!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_VESSEL_OF_RUIN);
|
||||
MESSAGE("Ting-Lu's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
test/battle/ability/white_smoke.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for White Smoke are handled in test/battle/ability/clear_body.c
|
||||
@ -153,9 +153,9 @@ SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
SEND_IN_MESSAGE("Palafin");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_ZERO_TO_HERO);
|
||||
MESSAGE("Palafin underwent a heroic transformation!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -402,9 +402,9 @@ AI_DOUBLE_BATTLE_TEST("AI will not use Helping Hand if partner does not have any
|
||||
{
|
||||
u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE;
|
||||
|
||||
PARAMETRIZE{ move1 = MOVE_LEER; move2 = MOVE_TOXIC; }
|
||||
PARAMETRIZE{ move1 = MOVE_HELPING_HAND; move2 = MOVE_PROTECT; }
|
||||
PARAMETRIZE{ move1 = MOVE_ACUPRESSURE; move2 = MOVE_DOUBLE_TEAM; move3 = MOVE_TOXIC; move4 = MOVE_PROTECT; }
|
||||
PARAMETRIZE { move1 = MOVE_LEER; move2 = MOVE_TOXIC; }
|
||||
PARAMETRIZE { move1 = MOVE_HELPING_HAND; move2 = MOVE_PROTECT; }
|
||||
PARAMETRIZE { move1 = MOVE_ACUPRESSURE; move2 = MOVE_DOUBLE_TEAM; move3 = MOVE_TOXIC; move4 = MOVE_PROTECT; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
@ -431,7 +431,7 @@ AI_DOUBLE_BATTLE_TEST("AI will not use a status move if partner already chose He
|
||||
for (j = MOVE_NONE + 1; j < MOVES_COUNT; j++)
|
||||
{
|
||||
if (gMovesInfo[j].category == DAMAGE_CATEGORY_STATUS) {
|
||||
PARAMETRIZE{ statusMove = j; }
|
||||
PARAMETRIZE { statusMove = j; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,8 +20,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon switch out after using a status move onc
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@ -55,8 +55,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use stat boosting moves")
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@ -87,10 +87,10 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are the on
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 0; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; isAlive = 1; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@ -122,10 +122,10 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they don't have
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE{ ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
PARAMETRIZE{ ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_SWAMPERT; move = MOVE_WATERFALL; }
|
||||
PARAMETRIZE { ability = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
PARAMETRIZE { ability = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_ELEKID; move = MOVE_THUNDER_WAVE; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
@ -157,10 +157,10 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are trappe
|
||||
|
||||
for (j = 0; j < ARRAY_COUNT(choiceItems); j++)
|
||||
{
|
||||
PARAMETRIZE{ aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE{ aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE{ aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
PARAMETRIZE{ aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_RHYDON; playerAbility = ABILITY_LIGHTNING_ROD; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_NONE; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
PARAMETRIZE { aiAbility = ABILITY_KLUTZ; heldItem = choiceItems[j]; species = SPECIES_DUGTRIO; playerAbility = ABILITY_ARENA_TRAP; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
|
||||
@ -5,8 +5,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Mirror Coat against specia
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_MIRROR_COAT].effect == EFFECT_MIRROR_COAT);
|
||||
@ -24,8 +24,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Counter against physical a
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_COUNTER].effect == EFFECT_COUNTER);
|
||||
@ -43,8 +43,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will prioritize Revenge if slower")
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_REVENGE].effect == EFFECT_REVENGE);
|
||||
@ -60,8 +60,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: Mid-battle switches prioritize offensive o
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | aiRiskyFlag);
|
||||
@ -78,8 +78,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI prefers high damage moves at the expens
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
PARAMETRIZE { aiRiskyFlag = 0; }
|
||||
PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
|
||||
|
||||
@ -127,9 +127,9 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemo
|
||||
u32 speedAlakazm;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = TRUE; } // AI will always send out Alakazan as it sees a KO with Focus Blast, even if Alakazam dies before it can get it off
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = FALSE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES lets AI see that Alakazam would be KO'd before it can KO, and won't switch it in
|
||||
PARAMETRIZE{ speedAlakazm = 400; alakazamFirst = TRUE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES recognizes that Alakazam is faster and can KO, and will switch it in
|
||||
PARAMETRIZE { speedAlakazm = 200; alakazamFirst = TRUE; } // AI will always send out Alakazan as it sees a KO with Focus Blast, even if Alakazam dies before it can get it off
|
||||
PARAMETRIZE { speedAlakazm = 200; alakazamFirst = FALSE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES lets AI see that Alakazam would be KO'd before it can KO, and won't switch it in
|
||||
PARAMETRIZE { speedAlakazm = 400; alakazamFirst = TRUE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES recognizes that Alakazam is faster and can KO, and will switch it in
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
@ -159,8 +159,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI considers hazard damage whe
|
||||
u32 aiIsSmart = 0;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ aiIsSmart = 0; aiSmartSwitchFlags = 0; } // AI doesn't care about hazard damage resulting in Pokemon being KO'd
|
||||
PARAMETRIZE{ aiIsSmart = 1; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES avoids being KO'd as a result of hazards damage
|
||||
PARAMETRIZE { aiIsSmart = 0; aiSmartSwitchFlags = 0; } // AI doesn't care about hazard damage resulting in Pokemon being KO'd
|
||||
PARAMETRIZE { aiIsSmart = 1; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES avoids being KO'd as a result of hazards damage
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
@ -181,10 +181,10 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize
|
||||
u32 move2;
|
||||
u32 expectedIndex;
|
||||
|
||||
PARAMETRIZE{ expectedIndex = 3; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; } // When not smart, AI will only switch in a defensive mon if it has a SE move, otherwise will just default to damage
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; }
|
||||
PARAMETRIZE{ expectedIndex = 2; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // When smart, AI will prioritize SE move, but still switch in good type matchup without SE move
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; }
|
||||
PARAMETRIZE { expectedIndex = 3; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; } // When not smart, AI will only switch in a defensive mon if it has a SE move, otherwise will just default to damage
|
||||
PARAMETRIZE { expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; }
|
||||
PARAMETRIZE { expectedIndex = 2; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // When smart, AI will prioritize SE move, but still switch in good type matchup without SE move
|
||||
PARAMETRIZE { expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
@ -257,8 +257,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemo
|
||||
{
|
||||
u32 move1;
|
||||
|
||||
PARAMETRIZE{ move1 = MOVE_TACKLE; }
|
||||
PARAMETRIZE{ move1 = MOVE_RAPID_SPIN; }
|
||||
PARAMETRIZE { move1 = MOVE_TACKLE; }
|
||||
PARAMETRIZE { move1 = MOVE_RAPID_SPIN; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
|
||||
@ -153,3 +153,26 @@ SINGLE_BATTLE_TEST("Regular Mega Evolution and Fervent Wish Mega Evolution can h
|
||||
EXPECT_EQ(opponent->species, SPECIES_GARDEVOIR_MEGA);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Mega Evolved Pokemon do not change abilities after fainting")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_CRUNCH].makesContact == TRUE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[0] != ABILITY_ROUGH_SKIN);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[1] != ABILITY_ROUGH_SKIN);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[2] != ABILITY_ROUGH_SKIN);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GARCHOMP) { Ability(ABILITY_ROUGH_SKIN); Item(ITEM_GARCHOMPITE); HP(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CRUNCH); MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CRUNCH, player);
|
||||
MESSAGE("Foe Garchomp fainted!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_ROUGH_SKIN);
|
||||
MESSAGE("Wobbuffet was hurt by Foe Garchomp's Rough Skin!");
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,12 +163,12 @@ SINGLE_BATTLE_TEST("Berry hold effect cures status if a pokemon enters a battle"
|
||||
u16 status;
|
||||
u16 item;
|
||||
|
||||
PARAMETRIZE{ status = STATUS1_BURN; item = ITEM_RAWST_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; item = ITEM_ASPEAR_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; item = ITEM_CHERI_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; item = ITEM_CHESTO_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; item = ITEM_RAWST_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; item = ITEM_ASPEAR_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; item = ITEM_CHERI_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; item = ITEM_PECHA_BERRY; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; item = ITEM_CHESTO_BERRY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_RAWST_BERRY].holdEffect == HOLD_EFFECT_CURE_BRN);
|
||||
|
||||
@ -112,12 +112,12 @@ SINGLE_BATTLE_TEST("Ice Heal heals a battler from being frozen")
|
||||
SINGLE_BATTLE_TEST("Full Heal heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_FULL_HEAL].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -134,12 +134,12 @@ SINGLE_BATTLE_TEST("Full Heal heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Heal Powder heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_HEAL_POWDER].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -156,12 +156,12 @@ SINGLE_BATTLE_TEST("Heal Powder heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Pewter Crunchies heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_PEWTER_CRUNCHIES].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -178,12 +178,12 @@ SINGLE_BATTLE_TEST("Pewter Crunchies heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Lava Cookies heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LAVA_COOKIE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -200,12 +200,12 @@ SINGLE_BATTLE_TEST("Lava Cookies heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Rage Candy Bar heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_RAGE_CANDY_BAR].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -222,12 +222,12 @@ SINGLE_BATTLE_TEST("Rage Candy Bar heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Old Gateu heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_OLD_GATEAU].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -244,12 +244,12 @@ SINGLE_BATTLE_TEST("Old Gateu heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Casteliacone heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_CASTELIACONE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -266,12 +266,12 @@ SINGLE_BATTLE_TEST("Casteliacone heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Lumiose Galette heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LUMIOSE_GALETTE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -288,12 +288,12 @@ SINGLE_BATTLE_TEST("Lumiose Galette heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Shalour Sable heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_SHALOUR_SABLE].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
@ -310,12 +310,12 @@ SINGLE_BATTLE_TEST("Shalour Sable heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Big Malasada heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_BIG_MALASADA].battleUsage == EFFECT_ITEM_CURE_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
|
||||
@ -9,13 +9,13 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE{ status = STATUS1_NONE; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_NONE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); Status1(status); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@ -35,13 +35,13 @@ SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures any primary s
|
||||
SINGLE_BATTLE_TEST("Full Restore restores a party members HP and cures any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE{ status = STATUS1_NONE; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_NONE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); Status1(status); }
|
||||
PLAYER(SPECIES_WYNAUT) { HP(1); MaxHP(300); Status1(status); }
|
||||
@ -64,12 +64,12 @@ SINGLE_BATTLE_TEST("Full Restore restores a party members HP and cures any prima
|
||||
SINGLE_BATTLE_TEST("Full Restore heals a battler from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
@ -86,12 +86,12 @@ SINGLE_BATTLE_TEST("Full Restore heals a battler from any primary status")
|
||||
SINGLE_BATTLE_TEST("Full Restore heals a party member from any primary status")
|
||||
{
|
||||
u16 status;
|
||||
PARAMETRIZE{ status = STATUS1_BURN; }
|
||||
PARAMETRIZE{ status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE{ status = STATUS1_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE{ status = STATUS1_SLEEP; }
|
||||
PARAMETRIZE { status = STATUS1_BURN; }
|
||||
PARAMETRIZE { status = STATUS1_FREEZE; }
|
||||
PARAMETRIZE { status = STATUS1_PARALYSIS; }
|
||||
PARAMETRIZE { status = STATUS1_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_TOXIC_POISON; }
|
||||
PARAMETRIZE { status = STATUS1_SLEEP; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT) { Status1(status); }
|
||||
|
||||
@ -1,5 +1,48 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Acrobatics doubles in power if the user has no held item");
|
||||
TO_DO_BATTLE_TEST("Acrobatics still doubles in power when Flying Gem is consumed");
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_ACROBATICS].effect == EFFECT_ACROBATICS);
|
||||
ASSUME(gMovesInfo[MOVE_ACROBATICS].type == TYPE_FLYING);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Acrobatics doubles in power if the user has no held item", s16 damage)
|
||||
{
|
||||
u16 heldItem;
|
||||
PARAMETRIZE { heldItem = ITEM_POTION; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_ACROBATICS); }
|
||||
} SCENE {
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Acrobatics still doubles in power when Flying Gem is consumed", s16 damage)
|
||||
{
|
||||
u16 heldItem;
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_FLYING_GEM; }
|
||||
GIVEN {
|
||||
ASSUME(I_GEM_BOOST_POWER >= GEN_6);
|
||||
ASSUME(gItemsInfo[ITEM_FLYING_GEM].holdEffect == HOLD_EFFECT_GEMS);
|
||||
ASSUME(gItemsInfo[ITEM_FLYING_GEM].secondaryId == TYPE_FLYING);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_ACROBATICS); }
|
||||
} SCENE {
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
if (I_GEM_BOOST_POWER >= GEN_6)
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.3), (results[1].damage));
|
||||
else
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), (results[1].damage));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,18 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Hone Claws increases Attack and Accuracy by one stage each");
|
||||
SINGLE_BATTLE_TEST("Hone Claws increases Attack and Accuracy by one stage each")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_HONE_CLAWS].effect == EFFECT_ATTACK_ACCURACY_UP);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_HONE_CLAWS); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HONE_CLAWS, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("Wobbuffet's Attack rose!");
|
||||
MESSAGE("Wobbuffet's accuracy rose!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,8 +10,8 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Aura Wheel raises Speed; fails if the user is not Morpeko")
|
||||
{
|
||||
u16 species;
|
||||
PARAMETRIZE{ species = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE{ species = SPECIES_MORPEKO; }
|
||||
PARAMETRIZE { species = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { species = SPECIES_MORPEKO; }
|
||||
GIVEN {
|
||||
PLAYER(species);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
|
||||
@ -253,8 +253,8 @@ SINGLE_BATTLE_TEST("Embargo disables the effect of the Plate items on the move J
|
||||
{
|
||||
u32 heldItem;
|
||||
|
||||
PARAMETRIZE{ heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE{ heldItem = ITEM_PIXIE_PLATE; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_PIXIE_PLATE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ARCEUS) { Item(heldItem); };
|
||||
OPPONENT(SPECIES_DRAGONITE);
|
||||
@ -274,8 +274,8 @@ SINGLE_BATTLE_TEST("Embargo disables the effect of the Drive items on the move T
|
||||
{
|
||||
u32 heldItem;
|
||||
|
||||
PARAMETRIZE{ heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE{ heldItem = ITEM_SHOCK_DRIVE; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_SHOCK_DRIVE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GENESECT) { Item(heldItem); };
|
||||
OPPONENT(SPECIES_GYARADOS);
|
||||
@ -295,8 +295,8 @@ SINGLE_BATTLE_TEST("Embargo disables the effect of the Memory items on the move
|
||||
{
|
||||
u32 heldItem;
|
||||
|
||||
PARAMETRIZE{ heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE{ heldItem = ITEM_FIRE_MEMORY; }
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_FIRE_MEMORY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_SILVALLY) { Item(heldItem); };
|
||||
OPPONENT(SPECIES_VENUSAUR);
|
||||
|
||||
38
test/battle/move_effect/fury_cutter.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_FURY_CUTTER].effect == EFFECT_FURY_CUTTER);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Fury Cutter power doubles with each use, up to 160 power")
|
||||
{
|
||||
s16 damage[6];
|
||||
int turn;
|
||||
int maxTurns;
|
||||
|
||||
if (B_UPDATED_MOVE_DATA >= GEN_6)
|
||||
maxTurns = 4;
|
||||
else if (B_UPDATED_MOVE_DATA == GEN_5)
|
||||
maxTurns = 5;
|
||||
else
|
||||
maxTurns = 6;
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CROBAT);
|
||||
OPPONENT(SPECIES_LINOONE) { HP(900); }
|
||||
} WHEN {
|
||||
for (turn = 0; turn < maxTurns; turn++)
|
||||
TURN { MOVE(player, MOVE_FURY_CUTTER); }
|
||||
} SCENE {
|
||||
for (turn = 0; turn < maxTurns; turn++) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_CUTTER, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[turn]);
|
||||
}
|
||||
} THEN {
|
||||
for (turn = 1; turn < maxTurns - 1; turn++)
|
||||
EXPECT_MUL_EQ(damage[turn - 1], UQ_4_12(2.0), damage[turn]);
|
||||
EXPECT_EQ(damage[maxTurns - 2], damage[maxTurns - 1]);
|
||||
}
|
||||
}
|
||||
@ -126,6 +126,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
|
||||
ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
@ -137,7 +138,6 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
|
||||
|
||||
SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
|
||||
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
|
||||
@ -149,7 +149,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
|
||||
ABILITY_POPUP(player, ABILITY_ELECTRIC_SURGE);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
NOT ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
ABILITY_POPUP(player, ABILITY_INTIMIDATE);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||
|
||||
@ -47,20 +47,19 @@ SINGLE_BATTLE_TEST("Plasma Fists turns normal moves into electric for the remain
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Plasma Fists type-changing effect is applied after Pixilate")
|
||||
SINGLE_BATTLE_TEST("Plasma Fists type-changing effect does not override Pixilate")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KRABBY) { Speed(300); };
|
||||
OPPONENT(SPECIES_ALTARIA) { Speed(1); Item(ITEM_ALTARIANITE); }
|
||||
OPPONENT(SPECIES_SYLVEON) { Speed(1); Ability(ABILITY_PIXILATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_EMBER, gimmick: GIMMICK_MEGA); }
|
||||
TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
MESSAGE("Krabby used Plasma Fists!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player);
|
||||
MESSAGE("A deluge of ions showers the battlefield!");
|
||||
MESSAGE("Foe Altaria used Ember!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent);
|
||||
MESSAGE("Foe Sylveon used Tackle!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
NOT MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,24 +111,24 @@ SINGLE_BATTLE_TEST("Roost suppresses the user's Flying-typing this turn, then re
|
||||
SINGLE_BATTLE_TEST("Roost, if used by a Flying/Flying type, treats the user as a Normal-type (or Typeless in Gen. 4) until the end of the turn")
|
||||
{
|
||||
u32 damagingMove;
|
||||
PARAMETRIZE{ damagingMove = MOVE_POUND; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_KARATE_CHOP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_GUST; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_POISON_STING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EARTHQUAKE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ROCK_THROW; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LEECH_LIFE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LICK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_STEEL_WING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EMBER; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_WATER_GUN; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_VINE_WHIP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_THUNDER_SHOCK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_CONFUSION; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ICE_BEAM; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DRAGON_BREATH; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_BITE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DISARMING_VOICE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_POUND; }
|
||||
PARAMETRIZE { damagingMove = MOVE_KARATE_CHOP; }
|
||||
PARAMETRIZE { damagingMove = MOVE_GUST; }
|
||||
PARAMETRIZE { damagingMove = MOVE_POISON_STING; }
|
||||
PARAMETRIZE { damagingMove = MOVE_EARTHQUAKE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_ROCK_THROW; }
|
||||
PARAMETRIZE { damagingMove = MOVE_LEECH_LIFE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_LICK; }
|
||||
PARAMETRIZE { damagingMove = MOVE_STEEL_WING; }
|
||||
PARAMETRIZE { damagingMove = MOVE_EMBER; }
|
||||
PARAMETRIZE { damagingMove = MOVE_WATER_GUN; }
|
||||
PARAMETRIZE { damagingMove = MOVE_VINE_WHIP; }
|
||||
PARAMETRIZE { damagingMove = MOVE_THUNDER_SHOCK; }
|
||||
PARAMETRIZE { damagingMove = MOVE_CONFUSION; }
|
||||
PARAMETRIZE { damagingMove = MOVE_ICE_BEAM; }
|
||||
PARAMETRIZE { damagingMove = MOVE_DRAGON_BREATH; }
|
||||
PARAMETRIZE { damagingMove = MOVE_BITE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_DISARMING_VOICE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_TORNADUS].types[0] == TYPE_FLYING);
|
||||
@ -179,24 +179,24 @@ SINGLE_BATTLE_TEST("Roost, if used by a Flying/Flying type, treats the user as a
|
||||
SINGLE_BATTLE_TEST("Roost, if used by a Mystery/Flying type, treats the user as a Mystery/Mystery type until the end of the turn")
|
||||
{
|
||||
u32 damagingMove;
|
||||
PARAMETRIZE{ damagingMove = MOVE_POUND; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_KARATE_CHOP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_GUST; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_POISON_STING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EARTHQUAKE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ROCK_THROW; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LEECH_LIFE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_LICK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_STEEL_WING; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_EMBER; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_WATER_GUN; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_VINE_WHIP; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_THUNDER_SHOCK; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_CONFUSION; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_ICE_BEAM; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DRAGON_BREATH; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_BITE; }
|
||||
PARAMETRIZE{ damagingMove = MOVE_DISARMING_VOICE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_POUND; }
|
||||
PARAMETRIZE { damagingMove = MOVE_KARATE_CHOP; }
|
||||
PARAMETRIZE { damagingMove = MOVE_GUST; }
|
||||
PARAMETRIZE { damagingMove = MOVE_POISON_STING; }
|
||||
PARAMETRIZE { damagingMove = MOVE_EARTHQUAKE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_ROCK_THROW; }
|
||||
PARAMETRIZE { damagingMove = MOVE_LEECH_LIFE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_LICK; }
|
||||
PARAMETRIZE { damagingMove = MOVE_STEEL_WING; }
|
||||
PARAMETRIZE { damagingMove = MOVE_EMBER; }
|
||||
PARAMETRIZE { damagingMove = MOVE_WATER_GUN; }
|
||||
PARAMETRIZE { damagingMove = MOVE_VINE_WHIP; }
|
||||
PARAMETRIZE { damagingMove = MOVE_THUNDER_SHOCK; }
|
||||
PARAMETRIZE { damagingMove = MOVE_CONFUSION; }
|
||||
PARAMETRIZE { damagingMove = MOVE_ICE_BEAM; }
|
||||
PARAMETRIZE { damagingMove = MOVE_DRAGON_BREATH; }
|
||||
PARAMETRIZE { damagingMove = MOVE_BITE; }
|
||||
PARAMETRIZE { damagingMove = MOVE_DISARMING_VOICE; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_MOLTRES].types[0] == TYPE_FIRE);
|
||||
|
||||
@ -56,7 +56,7 @@ DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explos
|
||||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
OPPONENT(SPECIES_ALAKAZAM) {Speed(100);}
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_STICKY_WEB); MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(opponentRight, 3); }
|
||||
TURN {}
|
||||
@ -65,13 +65,13 @@ DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explos
|
||||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("2 sent out Alakazam!");
|
||||
MESSAGE("Foe Alakazam was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Foe Alakazam's Speed fell!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ SINGLE_BATTLE_TEST("Strength Sap lowers Attack by 1 and restores HP based on tar
|
||||
{
|
||||
u32 atkStat = 0;
|
||||
|
||||
PARAMETRIZE{ atkStat = 100; }
|
||||
PARAMETRIZE{ atkStat = 50; }
|
||||
PARAMETRIZE { atkStat = 100; }
|
||||
PARAMETRIZE { atkStat = 50; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(200); }
|
||||
@ -35,8 +35,8 @@ SINGLE_BATTLE_TEST("Strength Sap works exactly the same when attacker is behind
|
||||
{
|
||||
u32 atkStat = 0;
|
||||
|
||||
PARAMETRIZE{ atkStat = 100; }
|
||||
PARAMETRIZE{ atkStat = 50; }
|
||||
PARAMETRIZE { atkStat = 100; }
|
||||
PARAMETRIZE { atkStat = 50; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(200); }
|
||||
@ -65,7 +65,7 @@ SINGLE_BATTLE_TEST("Strength Sap lowers Attack by 1 and restores HP based on tar
|
||||
|
||||
for (j = 0; j <= MAX_STAT_STAGE; j++) {
|
||||
if (j == DEFAULT_STAT_STAGE - 1) { continue; } // Ignore -6, because Strength Sap won't work otherwise
|
||||
PARAMETRIZE{ statStage = j; }
|
||||
PARAMETRIZE { statStage = j; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
|
||||
@ -48,3 +48,21 @@ SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids toxic when it can not poison target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_SNORLAX; ability = ABILITY_IMMUNITY; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_BULBASAUR; ability = ABILITY_OVERGROW; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_TOXIC); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_TOXIC); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,8 +243,8 @@ SINGLE_BATTLE_TEST("Solar Beam and Solar Blade can be used instantly in Sunlight
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in Rain", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_RAIN_DANCE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_RAIN_DANCE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@ -261,8 +261,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in Rain", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in Rain", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_RAIN_DANCE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_RAIN_DANCE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
@ -279,8 +279,8 @@ SINGLE_BATTLE_TEST("Solar Blade's power is halved in Rain", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in a Sandstorm", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@ -297,8 +297,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in a Sandstorm", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in a Sandstorm", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@ -315,8 +315,8 @@ SINGLE_BATTLE_TEST("Solar Blade's power is halved in a Sandstorm", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in Hail", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_HAIL; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_HAIL; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@ -333,8 +333,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in Hail", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in Hail", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_HAIL; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_HAIL; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@ -351,8 +351,8 @@ SINGLE_BATTLE_TEST("Solar Blade's power is halved in Hail", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Beam's power is halved in Snow", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@ -369,8 +369,8 @@ SINGLE_BATTLE_TEST("Solar Beam's power is halved in Snow", s16 damage)
|
||||
SINGLE_BATTLE_TEST("Solar Blade's power is halved in Snow", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
|
||||
@ -9,8 +9,8 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Fire-type move in Sunlight", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SUNNY_DAY; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SUNNY_DAY; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_MEGANIUM);
|
||||
@ -27,8 +27,8 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Fire-type move
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Water-type move in Rain", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_RAIN_DANCE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_RAIN_DANCE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ARCANINE);
|
||||
@ -45,8 +45,8 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Water-type mov
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Rock-type move in a Sandstorm", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_MAGMAR) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
@ -63,9 +63,9 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Rock-type move
|
||||
SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to an Ice-type move in Hail and Snow", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE{ move = MOVE_HAIL; }
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_HAIL; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_DRAGONAIR) { Item(ITEM_SAFETY_GOGGLES); };
|
||||
|
||||
@ -32,4 +32,42 @@ SINGLE_BATTLE_TEST("Hurricane bypasses accuracy checks in Rain")
|
||||
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
|
||||
}
|
||||
}
|
||||
TO_DO_BATTLE_TEST("Hurricane Veil can hit airborne targets") // Fly, Bounce, Sky Drop
|
||||
|
||||
SINGLE_BATTLE_TEST("Hurricane can hit airborne targets (Fly, Bounce)")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_FLY; }
|
||||
PARAMETRIZE { move = MOVE_BOUNCE; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE);
|
||||
ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_FLY].argument)) == STATUS3_ON_AIR);
|
||||
ASSUME(gMovesInfo[MOVE_BOUNCE].effect == EFFECT_SEMI_INVULNERABLE);
|
||||
ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_BOUNCE].argument)) == STATUS3_ON_AIR);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(move); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_HURRICANE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HURRICANE, player);
|
||||
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Hurricane can hit airborne targets (Sky Drop)")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP);
|
||||
ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_SKY_DROP].argument)) == STATUS3_ON_AIR);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_SKY_DROP, target: opponentLeft); MOVE(playerRight, MOVE_HURRICANE, target: playerLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HURRICANE, playerRight);
|
||||
NONE_OF { MESSAGE("Wobbuffet's attack missed!"); }
|
||||
}
|
||||
}
|
||||
|
||||
74
test/battle/move_flags/ignores_target_ability.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_SUNSTEEL_STRIKE].ignoresTargetAbility);
|
||||
ASSUME(gMovesInfo[MOVE_MOONGEIST_BEAM].ignoresTargetAbility);
|
||||
ASSUME(gMovesInfo[MOVE_PHOTON_GEYSER].ignoresTargetAbility);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("ignoresTargetAbility moves do not ignore the attacker's own ability", s16 damage)
|
||||
{
|
||||
u32 ability, move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_MAGIC_GUARD; }
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_UNAWARE; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_MAGIC_GUARD; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_UNAWARE; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_MAGIC_GUARD; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_UNAWARE; }
|
||||
|
||||
ASSUME(gAbilitiesInfo[ABILITY_UNAWARE].breakable);
|
||||
ASSUME(gMovesInfo[MOVE_IRON_DEFENSE].effect == EFFECT_DEFENSE_UP_2);
|
||||
ASSUME(gMovesInfo[MOVE_AMNESIA].effect == EFFECT_SPECIAL_DEFENSE_UP_2);
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_CLEFABLE) { Speed(1); Ability(ability); }
|
||||
OPPONENT(SPECIES_ARON) { Speed(2); }
|
||||
} WHEN {
|
||||
if (gMovesInfo[move].category == DAMAGE_CATEGORY_PHYSICAL)
|
||||
TURN { MOVE(opponent, MOVE_IRON_DEFENSE); MOVE(player, move); }
|
||||
else
|
||||
TURN { MOVE(opponent, MOVE_AMNESIA); MOVE(player, move); }
|
||||
} SCENE {
|
||||
if (gMovesInfo[move].category == DAMAGE_CATEGORY_PHYSICAL)
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, opponent);
|
||||
else
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_AMNESIA, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, UQ_4_12(2.0), results[3].damage);
|
||||
EXPECT_MUL_EQ(results[4].damage, UQ_4_12(2.0), results[5].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("ignoresTargetAbility moves do ignore target's abilities", s16 damage)
|
||||
{
|
||||
u32 ability, move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_INNER_FOCUS; }
|
||||
PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_MULTISCALE; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_INNER_FOCUS; }
|
||||
PARAMETRIZE { move = MOVE_MOONGEIST_BEAM; ability = ABILITY_MULTISCALE; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_INNER_FOCUS; }
|
||||
PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_MULTISCALE; }
|
||||
|
||||
ASSUME(gAbilitiesInfo[ABILITY_MULTISCALE].breakable);
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_AZUMARILL);
|
||||
OPPONENT(SPECIES_DRAGONITE) { Ability(ability); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_EQ(results[0].damage, results[1].damage);
|
||||
EXPECT_EQ(results[2].damage, results[3].damage);
|
||||
EXPECT_EQ(results[4].damage, results[5].damage);
|
||||
}
|
||||
}
|
||||
@ -35,3 +35,23 @@ SINGLE_BATTLE_TEST("Burn reduces Attack by 50%", s16 damage)
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids Will-o-Wisp when it can not burn target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BUIZEL; ability = ABILITY_WATER_VEIL; }
|
||||
PARAMETRIZE { species = SPECIES_DEWPIDER; ability = ABILITY_WATER_BUBBLE; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_ARCTIBAX; ability = ABILITY_THERMAL_EXCHANGE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_CHARMANDER; ability = ABILITY_BLAZE; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_WILL_O_WISP); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_WILL_O_WISP); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,3 +42,21 @@ SINGLE_BATTLE_TEST("Paralysis has a 25% chance of skipping the turn")
|
||||
MESSAGE("Wobbuffet is paralyzed! It can't move!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_HITMONLEE; ability = ABILITY_LIMBER; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
PARAMETRIZE { species = SPECIES_PIKACHU; ability = ABILITY_STATIC; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_THUNDER_WAVE); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_THUNDER_WAVE); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,3 +21,21 @@ SINGLE_BATTLE_TEST("Sleep prevents the battler from using a move")
|
||||
MESSAGE("Wobbuffet used Celebrate!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI avoids hypnosis when it can not put target to sleep")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_HOOTHOOT; ability = ABILITY_INSOMNIA; }
|
||||
PARAMETRIZE { species = SPECIES_MANKEY; ability = ABILITY_VITAL_SPIRIT; }
|
||||
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
|
||||
PARAMETRIZE { species = SPECIES_NACLI; ability = ABILITY_PURIFYING_SALT; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_HYPNOSIS); }
|
||||
} WHEN {
|
||||
TURN { SCORE_EQ(opponent, MOVE_CELEBRATE, MOVE_HYPNOSIS); } // Both get -10
|
||||
}
|
||||
}
|
||||
|
||||
28
test/battle/status2/confusion.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Confusion adds a 50/33% chance to hit self with 40 power")
|
||||
{
|
||||
s16 damage[2];
|
||||
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].power == 40);
|
||||
|
||||
PASSES_RANDOMLY(B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50, 100, RNG_CONFUSION);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); };
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); };
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE, WITH_RNG(RNG_DAMAGE_MODIFIER, 0)); MOVE(player, MOVE_CONFUSE_RAY); }
|
||||
TURN;
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
HP_BAR(player, captureDamage: &damage[0]);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, player);
|
||||
MESSAGE("Foe Wobbuffet became confused!");
|
||||
MESSAGE("Foe Wobbuffet is confused!");
|
||||
MESSAGE("It hurt itself in its confusion!");
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
} THEN {
|
||||
EXPECT_EQ(damage[0], damage[1]);
|
||||
}
|
||||
}
|
||||
@ -85,3 +85,27 @@ SINGLE_BATTLE_TEST("Grassy Terrain lasts for 5 turns")
|
||||
MESSAGE("The grass disappeared from the battlefield.");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Grassy Terrain heals the pokemon on the field for the duration of the terrain, including last turn")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); };
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_GRASSY_TERRAIN); }
|
||||
TURN {}
|
||||
TURN {}
|
||||
TURN {}
|
||||
TURN {}
|
||||
} SCENE {
|
||||
MESSAGE("Foe Wobbuffet used Celebrate!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GRASSY_TERRAIN, player);
|
||||
MESSAGE("Grass grew to cover the battlefield!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("Foe Wobbuffet is healed by the grassy terrain!");
|
||||
MESSAGE("The grass disappeared from the battlefield.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,8 +20,8 @@ SINGLE_BATTLE_TEST("Sandstorm deals 1/16 damage per turn")
|
||||
SINGLE_BATTLE_TEST("Sandstorm multiplies the special defense of Rock-types by 1.5x", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SANDSTORM; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
PLAYER(SPECIES_WOBBUFFET) ;
|
||||
|
||||
@ -13,8 +13,8 @@ ASSUMPTIONS
|
||||
SINGLE_BATTLE_TEST("Snow multiplies the defense of Ice-types by 1.5x", s16 damage)
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE{ move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE{ move = MOVE_CELEBRATE; }
|
||||
PARAMETRIZE { move = MOVE_SNOWSCAPE; }
|
||||
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GLALIE);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "global.h"
|
||||
#include "string_util.h"
|
||||
#include "test/test.h"
|
||||
#include "constants/form_change_types.h"
|
||||
|
||||
@ -138,3 +139,18 @@ TEST("No species has two evolutions that use the evolution tracker")
|
||||
|
||||
EXPECT(evolutionTrackerEvolutions < 2);
|
||||
}
|
||||
|
||||
extern const u8 gFallbackPokedexText[];
|
||||
|
||||
TEST("Every species has a description")
|
||||
{
|
||||
u32 i;
|
||||
u32 species = SPECIES_NONE;
|
||||
for (i = 1; i < NUM_SPECIES; i++)
|
||||
{
|
||||
if (IsSpeciesEnabled(i))
|
||||
PARAMETRIZE { species = i; }
|
||||
}
|
||||
|
||||
EXPECT_NE(StringCompare(GetSpeciesPokedexDescription(species), gFallbackPokedexText), 0);
|
||||
}
|
||||
|
||||
@ -46,10 +46,14 @@ void ReadJascPaletteLine(FILE *fp, char *line)
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
FATAL_ERROR("LF line endings aren't supported.\n");
|
||||
{
|
||||
line[length] = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == EOF)
|
||||
FATAL_ERROR("Unexpected EOF. No CRLF at end of file.\n");
|
||||
FATAL_ERROR("Unexpected EOF. No LF or CRLF at end of file.\n");
|
||||
|
||||
if (c == 0)
|
||||
FATAL_ERROR("NUL character in file.\n");
|
||||
|
||||