diff --git a/.all-contributorsrc b/.all-contributorsrc
index 627b52827a..3d356bbc97 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -651,6 +651,15 @@
"contributions": [
"bug"
]
+ },
+ {
+ "login": "KnightGallade",
+ "name": "KnightGallade",
+ "avatar_url": "https://avatars.githubusercontent.com/u/189022270?v=4",
+ "profile": "https://github.com/KnightGallade",
+ "contributions": [
+ "bug"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/CREDITS.md b/CREDITS.md
index c3d7df099a..133208fa95 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -93,6 +93,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
 PacFire 🎨 |
 ChrispyChris27 💻 |
 LogicalLlama 🐛 |
+  KnightGallade 🐛 |
diff --git a/asm/macros/battle_anim_script.inc b/asm/macros/battle_anim_script.inc
index c24a6b8253..17d0ca3e7f 100644
--- a/asm/macros/battle_anim_script.inc
+++ b/asm/macros/battle_anim_script.inc
@@ -648,3 +648,7 @@
.macro shake_battle_platforms priority=2, x_offset:req, y_offset:req, shakes:req, delay:req
createvisualtask AnimTask_ShakeBattlePlatforms, \priority, \x_offset, \y_offset, \shakes, \delay
.endm
+
+ .macro create_surf_wave priority=2, palette:req
+ createvisualtask AnimTask_CreateSurfWave, \priority, \palette
+ .endm
diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s
index 582dd5c331..e2cdc9b158 100644
--- a/data/battle_anim_scripts.s
+++ b/data/battle_anim_scripts.s
@@ -4409,7 +4409,7 @@ FlameBurstSpread:
gBattleAnimMove_SludgeWave::
panse SE_M_WHIRLPOOL, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 0x2, 0x0
- createvisualtask AnimTask_CreateSurfWave, 2, ANIM_SURF_PAL_SLUDGE_WAVE
+ create_surf_wave palette=ANIM_SURF_PAL_SLUDGE_WAVE
waitforvisualfinish
end
@@ -12875,7 +12875,7 @@ gBattleAnimMove_ZippyZap::
gBattleAnimMove_SplishySplash::
loadspritegfx ANIM_TAG_SPARK_2
- createvisualtask AnimTask_CreateSurfWave, 2, ANIM_SURF_PAL_SURF
+ create_surf_wave palette=ANIM_SURF_PAL_SURF
delay 24
panse SE_M_SURF, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, +2, 0
waitforvisualfinish
@@ -27017,7 +27017,7 @@ gBattleAnimMove_Crabhammer::
end
gBattleAnimMove_Surf::
- createvisualtask AnimTask_CreateSurfWave, 2, ANIM_SURF_PAL_SURF
+ create_surf_wave palette=ANIM_SURF_PAL_SURF
delay 24
panse SE_M_SURF, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, +2, 0
waitforvisualfinish
@@ -29320,7 +29320,7 @@ ArmThrustLeft:
gBattleAnimMove_MuddyWater::
panse SE_M_WHIRLPOOL, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, +2, 0
- createvisualtask AnimTask_CreateSurfWave, 2, ANIM_SURF_PAL_MUDDY_WATER
+ create_surf_wave palette=ANIM_SURF_PAL_MUDDY_WATER
waitforvisualfinish
end
@@ -32493,7 +32493,7 @@ FinishAcidDownpour:
createsprite gAcidDownpourReversalSpriteTemplate, ANIM_ATTACKER, 2, 0x1a, 0xd2
delay 32
panse SE_M_WHIRLPOOL, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 0x2, 0x0
- createvisualtask AnimTask_CreateSurfWave, 0x2, ANIM_SURF_PAL_SLUDGE_WAVE
+ create_surf_wave priority=0x2, palette=ANIM_SURF_PAL_SLUDGE_WAVE
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 2, 0, 7, (RGB(28, 3, 22) | RGB_ALPHA)
createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 2, 50, 1
call AcidDownpourFlare
@@ -33388,7 +33388,7 @@ gBattleAnimMove_HydroVortex::
loadspritegfx ANIM_TAG_WATER_ORB @whirlpool
createvisualtask AnimTask_AllBattlersInvisibleExceptAttackerAndTarget, 0xA
waitforvisualfinish
- createvisualtask AnimTask_CreateSurfWave, 0x2, 0x0
+ create_surf_wave priority=0x2, palette=0x0
delay 24
panse SE_M_SURF, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 0x2, 0x0
waitforvisualfinish
diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s
index df8affa835..2000ef4e84 100644
--- a/data/battle_scripts_1.s
+++ b/data/battle_scripts_1.s
@@ -1422,6 +1422,7 @@ BattleScript_ToxicThreadTryPsn::
BattleScript_EffectVenomDrench::
attackcanceler
+ jumpifsubstituteblocks BattleScript_ButItFailed
jumpifstatus BS_TARGET, STATUS1_PSN_ANY, BattleScript_EffectVenomDrenchCanBeUsed
goto BattleScript_ButItFailed
BattleScript_EffectVenomDrenchCanBeUsed:
@@ -3856,6 +3857,7 @@ BattleScript_EffectWaterSport::
BattleScript_EffectTickle::
attackcanceler
+ jumpifsubstituteblocks BattleScript_ButItFailed
jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_TickleDoMoveAnim
jumpifstat BS_TARGET, CMP_EQUAL, STAT_DEF, MIN_STAT_STAGE, BattleScript_CantLowerMultipleStats
BattleScript_TickleDoMoveAnim::
diff --git a/include/constants/battle.h b/include/constants/battle.h
index 67198a38bb..ba632e6f90 100644
--- a/include/constants/battle.h
+++ b/include/constants/battle.h
@@ -236,6 +236,7 @@ enum VolatileFlags
F(VOLATILE_BEADS_OF_RUIN, beadsOfRuin, (u32, 1)) \
F(VOLATILE_IS_TRANSFORMED_MON_SHINY, isTransformedMonShiny, (u32, 1)) \
F(VOLATILE_TRANSFORMED_MON_PID, transformedMonPID, (u32, UINT32_MAX)) \
+ F(VOLATILE_TRANSFORMED_MON_SPECIES, transformedMonSpecies, (u32, NUM_SPECIES)) \
F(VOLATILE_DISABLED_MOVE, disabledMove, (u32, MOVES_COUNT_ALL)) \
F(VOLATILE_ENCORED_MOVE, encoredMove, (u32, MOVES_COUNT_ALL)) \
F(VOLATILE_PROTECT_USES, consecutiveMoveUses, (u32, UINT8_MAX)) \
diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h
index 9b38f52915..ec8ec676d4 100644
--- a/include/constants/battle_anim.h
+++ b/include/constants/battle_anim.h
@@ -691,6 +691,10 @@ enum SpeciesGfxChange
SPECIES_GFX_CHANGE_GHOST_UNVEIL,
};
+// Surf wave palettes
+#define ANIM_SURF_PAL_SURF 0
+#define ANIM_SURF_PAL_MUDDY_WATER 1
+
// Flags given to various functions to indicate which palettes to consider.
// Handled by UnpackSelectedBattlePalettes
#define F_PAL_BG (1 << 0)
diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h
index 1cdd150499..7f4b77a036 100644
--- a/include/constants/form_change_types.h
+++ b/include/constants/form_change_types.h
@@ -161,6 +161,8 @@ enum FormChanges
FORM_CHANGE_OVERWORLD_WEATHER,
// Form change that activates when the Pokémon is deposited into the PC or Daycare.
FORM_CHANGE_DEPOSIT,
+ // Form change for Minior, which appears unchanged when encountered in the wild
+ FORM_CHANGE_BEGIN_WILD_ENCOUNTER,
};
#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H
diff --git a/include/global.fieldmap.h b/include/global.fieldmap.h
index f71fadd26a..6ed5f37fc6 100644
--- a/include/global.fieldmap.h
+++ b/include/global.fieldmap.h
@@ -11,6 +11,15 @@
#define MAPGRID_COLLISION_SHIFT 10
#define MAPGRID_ELEVATION_SHIFT 12
+enum
+{
+ ELEVATION_TRANSITION = 0,
+ ELEVATION_SURF = 1,
+ ELEVATION_DEFAULT = 3,
+ ELEVATION_MULTI_LEVEL = 15,
+ ELEVATION_INVALID = 0xFFFF
+};
+
#define PACK_METATILE(metatileId) PACK(metatileId, MAPGRID_METATILE_ID_SHIFT, MAPGRID_METATILE_ID_MASK)
#define PACK_COLLISION(collision) PACK(collision, MAPGRID_COLLISION_SHIFT, MAPGRID_COLLISION_MASK)
#define PACK_ELEVATION(elevation) PACK(elevation, MAPGRID_ELEVATION_SHIFT, MAPGRID_ELEVATION_MASK)
diff --git a/ld_script_modern.ld b/ld_script_modern.ld
index 47989bd91f..bf1894b246 100644
--- a/ld_script_modern.ld
+++ b/ld_script_modern.ld
@@ -124,6 +124,9 @@ SECTIONS {
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
+ /* DWARF 5*/
+ .debug_line_str 0 : { *(.debug_line_str) }
+
/* Discard everything not specifically mentioned above. */
/DISCARD/ :
{
diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c
index aa16daea3a..c920689ba4 100644
--- a/src/battle_anim_effects_1.c
+++ b/src/battle_anim_effects_1.c
@@ -6717,6 +6717,10 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
SwapStructData(&gBattleStruct->illusion[battlerAtk], &gBattleStruct->illusion[battlerPartner], data, sizeof(struct Illusion));
SwapStructData(&gBattleStruct->battlerState[battlerAtk], &gBattleStruct->battlerState[battlerPartner], data, sizeof(struct BattlerState));
+ // Swap those back since they aren't affected by ally switch
+ SWAP(gBattleStruct->battlerState[battlerAtk].storedHealingWish, gBattleStruct->battlerState[battlerPartner].storedHealingWish, temp);
+ SWAP(gBattleStruct->battlerState[battlerAtk].storedLunarDance, gBattleStruct->battlerState[battlerPartner].storedLunarDance, temp);
+
SWAP(gBattleSpritesDataPtr->battlerData[battlerAtk].invisible, gBattleSpritesDataPtr->battlerData[battlerPartner].invisible, temp);
SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp);
SWAP(gTransformedShininess[battlerAtk], gTransformedShininess[battlerPartner], temp);
diff --git a/src/battle_anim_water.c b/src/battle_anim_water.c
index c866c68598..64ebf224b0 100644
--- a/src/battle_anim_water.c
+++ b/src/battle_anim_water.c
@@ -1,6 +1,7 @@
#include "global.h"
#include "battle.h"
#include "battle_anim.h"
+#include "battle_anim_internal.h"
#include "gpu_regs.h"
#include "graphics.h"
#include "palette.h"
@@ -979,6 +980,8 @@ static void AnimSmallBubblePair_Step(struct Sprite *sprite)
void AnimTask_CreateSurfWave(u8 taskId)
{
+ CMD_ARGS(palette);
+
struct BattleAnimBgData animBg;
u8 taskId2;
u16 *x;
@@ -1005,7 +1008,7 @@ void AnimTask_CreateSurfWave(u8 taskId)
AnimLoadCompressedBgTilemapHandleContest(&animBg, gBattleAnimBgTilemap_SurfContest, TRUE);
}
AnimLoadCompressedBgGfx(animBg.bgId, gBattleAnimBgImage_Surf, animBg.tilesOffset);
- switch (gBattleAnimArgs[0])
+ switch (cmd->palette)
{
case ANIM_SURF_PAL_SURF:
default:
diff --git a/src/battle_main.c b/src/battle_main.c
index 11abf82a38..133f118e79 100644
--- a/src/battle_main.c
+++ b/src/battle_main.c
@@ -617,6 +617,13 @@ static void CB2_InitBattleInternal(void)
TryFormChange(&gEnemyParty[i], FORM_CHANGE_BEGIN_BATTLE);
}
+ if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
+ {
+ TryFormChange(&gEnemyParty[0], FORM_CHANGE_BEGIN_WILD_ENCOUNTER);
+ if (IsDoubleBattle())
+ TryFormChange(&gEnemyParty[1], FORM_CHANGE_BEGIN_WILD_ENCOUNTER);
+ }
+
#if TESTING
gPlayerPartyCount = CalculatePartyCount(gPlayerParty);
gEnemyPartyCount = CalculatePartyCount(gEnemyParty);
diff --git a/src/battle_move_resolution.c b/src/battle_move_resolution.c
index 64a6d99520..48e17fce11 100644
--- a/src/battle_move_resolution.c
+++ b/src/battle_move_resolution.c
@@ -1304,8 +1304,10 @@ static enum CancelerResult CancelerMoveEffectFailureTarget(struct BattleContext
}
break;
case EFFECT_SUCKER_PUNCH:
+ {
+ u32 defMove = GetBattlerChosenMove(battlerDef);
if (HasBattlerActedThisTurn(battlerDef)
- || (IsBattleMoveStatus(GetBattlerChosenMove(battlerDef)) && !gProtectStructs[battlerDef].noValidMoves))
+ || (IsBattleMoveStatus(defMove) && !gProtectStructs[battlerDef].noValidMoves && GetMoveEffect(defMove) != EFFECT_ME_FIRST))
{
battleScript = BattleScript_ButItFailed;
}
@@ -1314,6 +1316,8 @@ static enum CancelerResult CancelerMoveEffectFailureTarget(struct BattleContext
numAffectedTargets++;
continue;
}
+
+ }
break;
case EFFECT_UPPER_HAND:
{
@@ -4056,10 +4060,22 @@ static enum Move GetAssistMove(void)
enum Move move = MOVE_NONE;
u32 chooseableMovesNo = 0;
struct Pokemon *party;
+ u8 battlerByPartyId[PARTY_SIZE];
enum Move validMoves[PARTY_SIZE * MAX_MON_MOVES] = {MOVE_NONE};
party = GetBattlerParty(gBattlerAttacker);
+ for (u32 i = 0; i < PARTY_SIZE; i++)
+ battlerByPartyId[i] = MAX_BATTLERS_COUNT;
+ for (u32 battler = 0; battler < gBattlersCount; battler++)
+ {
+ if (!IsBattlerAlly(battler, gBattlerAttacker))
+ continue;
+
+ if (gBattlerPartyIndexes[battler] < PARTY_SIZE)
+ battlerByPartyId[gBattlerPartyIndexes[battler]] = battler;
+ }
+
for (u32 monId = 0; monId < PARTY_SIZE; monId++)
{
if (monId == gBattlerPartyIndexes[gBattlerAttacker])
@@ -4071,7 +4087,12 @@ static enum Move GetAssistMove(void)
for (u32 moveId = 0; moveId < MAX_MON_MOVES; moveId++)
{
- enum Move move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
+ enum Move move;
+
+ if (battlerByPartyId[monId] != MAX_BATTLERS_COUNT)
+ move = gBattleMons[battlerByPartyId[monId]].moves[moveId];
+ else
+ move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId);
if (IsMoveAssistBanned(move))
continue;
diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c
index f96a08cc83..d8d6df5662 100644
--- a/src/battle_script_commands.c
+++ b/src/battle_script_commands.c
@@ -2362,7 +2362,67 @@ static void SetNonVolatileStatus(enum BattlerId effectBattler, enum MoveEffect e
gBattleStruct->poisonPuppeteerConfusion = TRUE;
}
-// To avoid confusion the arguments are naned battler/effectBattler since they can be different from gBattlerAttacker/gBattlerTarget
+static inline bool32 IgnoreTargetingForMoveEffect(enum MoveEffect moveEffect) // Currently only used to determine move effects which happen even if the move's defined effectbattler is fainted
+{
+ switch (moveEffect)
+ {
+ case MOVE_EFFECT_PAYDAY:
+ case MOVE_EFFECT_BUG_BITE:
+ case MOVE_EFFECT_FLAME_BURST:
+ case MOVE_EFFECT_STEALTH_ROCK:
+ case MOVE_EFFECT_STEELSURGE:
+ case MOVE_EFFECT_SUN:
+ case MOVE_EFFECT_RAIN:
+ case MOVE_EFFECT_SANDSTORM:
+ case MOVE_EFFECT_HAIL:
+ case MOVE_EFFECT_MISTY_TERRAIN:
+ case MOVE_EFFECT_GRASSY_TERRAIN:
+ case MOVE_EFFECT_ELECTRIC_TERRAIN:
+ case MOVE_EFFECT_PSYCHIC_TERRAIN:
+ case MOVE_EFFECT_DEFOG:
+ case MOVE_EFFECT_REFLECT:
+ case MOVE_EFFECT_LIGHT_SCREEN:
+ case MOVE_EFFECT_AURORA_VEIL:
+ case MOVE_EFFECT_GRAVITY:
+ case MOVE_EFFECT_HEAL_TEAM:
+ case MOVE_EFFECT_AROMATHERAPY:
+ case MOVE_EFFECT_RECYCLE_BERRIES:
+ case MOVE_EFFECT_ION_DELUGE:
+ case MOVE_EFFECT_HAZE:
+ case MOVE_EFFECT_RAISE_TEAM_ATTACK:
+ case MOVE_EFFECT_RAISE_TEAM_DEFENSE:
+ case MOVE_EFFECT_RAISE_TEAM_SPEED:
+ case MOVE_EFFECT_RAISE_TEAM_SP_ATK:
+ case MOVE_EFFECT_RAISE_TEAM_SP_DEF:
+ case MOVE_EFFECT_CRIT_PLUS_SIDE:
+ case MOVE_EFFECT_LOWER_ATTACK_SIDE:
+ case MOVE_EFFECT_LOWER_DEFENSE_SIDE:
+ case MOVE_EFFECT_LOWER_SPEED_SIDE:
+ case MOVE_EFFECT_LOWER_SP_ATK_SIDE:
+ case MOVE_EFFECT_LOWER_SP_DEF_SIDE:
+ case MOVE_EFFECT_LOWER_SPEED_2_SIDE:
+ case MOVE_EFFECT_LOWER_EVASIVENESS_SIDE:
+ case MOVE_EFFECT_VINE_LASH:
+ case MOVE_EFFECT_WILDFIRE:
+ case MOVE_EFFECT_CANNONADE:
+ case MOVE_EFFECT_VOLCALITH:
+ case MOVE_EFFECT_PREVENT_ESCAPE_SIDE:
+ case MOVE_EFFECT_SANDBLAST_SIDE:
+ case MOVE_EFFECT_FIRE_SPIN_SIDE:
+ case MOVE_EFFECT_PARALYZE_SIDE:
+ case MOVE_EFFECT_POISON_SIDE:
+ case MOVE_EFFECT_CONFUSE_PAY_DAY_SIDE:
+ case MOVE_EFFECT_POISON_PARALYZE_SIDE:
+ case MOVE_EFFECT_EFFECT_SPORE_SIDE:
+ case MOVE_EFFECT_INFATUATE_SIDE:
+ case MOVE_EFFECT_CONFUSE_SIDE:
+ case MOVE_EFFECT_TORMENT_SIDE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
void SetMoveEffect(enum BattlerId battlerAtk, enum BattlerId effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags)
{
enum Ability abilities[MAX_BATTLERS_COUNT] = {ABILITY_NONE};
@@ -2375,7 +2435,6 @@ void SetMoveEffect(enum BattlerId battlerAtk, enum BattlerId effectBattler, enum
bool32 affectsUser = (battlerAtk == effectBattler);
bool32 mirrorArmorReflected = (abilities[gBattlerTarget] == ABILITY_MIRROR_ARMOR);
union StatChangeFlags flags = {0};
- bool32 activateAfterFaint = FALSE;
if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_1ST_HIT
&& IsBattlerAlive(gBattlerTarget)
@@ -2384,19 +2443,7 @@ void SetMoveEffect(enum BattlerId battlerAtk, enum BattlerId effectBattler, enum
gBattlescriptCurrInstr = battleScript;
return;
}
-
- switch (moveEffect) // Set move effects which happen later on
- {
- case MOVE_EFFECT_STEALTH_ROCK:
- case MOVE_EFFECT_PAYDAY:
- case MOVE_EFFECT_BUG_BITE:
- case MOVE_EFFECT_FLAME_BURST:
- activateAfterFaint = TRUE;
- break;
- default:
- break;
- }
-
+
gBattleScripting.battler = battlerAtk;
gEffectBattler = effectBattler;
@@ -2406,7 +2453,7 @@ void SetMoveEffect(enum BattlerId battlerAtk, enum BattlerId effectBattler, enum
&& IsSheerForceAffected(gCurrentMove, abilities[battlerAtk])
&& !(moveEffect == MOVE_EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE))
moveEffect = MOVE_EFFECT_NONE;
- else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint)
+ else if (!IsBattlerAlive(gEffectBattler) && !IgnoreTargetingForMoveEffect(moveEffect))
moveEffect = MOVE_EFFECT_NONE;
else if (DoesSubstituteBlockMove(gBattlerAttacker, gEffectBattler, gCurrentMove) && !affectsUser)
moveEffect = MOVE_EFFECT_NONE;
@@ -4990,6 +5037,7 @@ static void PlayAnimation(enum BattlerId battler, u8 animId, const u16 *argPtr,
|| animId == B_ANIM_FORM_CHANGE
|| animId == B_ANIM_SUBSTITUTE_FADE
|| animId == B_ANIM_PRIMAL_REVERSION
+ || animId == B_ANIM_POWER_CONSTRUCT
|| animId == B_ANIM_ULTRA_BURST
|| animId == B_ANIM_TERA_CHARGE
|| animId == B_ANIM_TERA_ACTIVATE
@@ -8525,6 +8573,7 @@ static void Cmd_transformdataexecution(void)
gBattleMons[gBattlerAttacker].volatiles.transformed = TRUE;
gBattleMons[gBattlerAttacker].volatiles.disabledMove = MOVE_NONE;
gBattleMons[gBattlerAttacker].volatiles.disableTimer = 0;
+ gBattleMons[gBattlerAttacker].volatiles.transformedMonSpecies = gBattleMons[gBattlerAttacker].species;
gBattleMons[gBattlerAttacker].volatiles.transformedMonPID = gBattleMons[gBattlerTarget].personality;
if (B_TRANSFORM_SHINY >= GEN_4)
@@ -13275,6 +13324,12 @@ void BS_JumpIfAbilityCantBeReactivated(void)
enum BattlerId battler = GetBattlerForBattleScript(cmd->battler);
u32 ability = gBattleMons[battler].ability;
+ if (GetBattlerHoldEffectIgnoreAbility(battler) == HOLD_EFFECT_ABILITY_SHIELD)
+ {
+ gBattlescriptCurrInstr = cmd->jumpInstr;
+ return;
+ }
+
switch (ability)
{
case ABILITY_IMPOSTER:
diff --git a/src/battle_terastal.c b/src/battle_terastal.c
index 0a63cd6878..02504ff12e 100644
--- a/src/battle_terastal.c
+++ b/src/battle_terastal.c
@@ -163,15 +163,19 @@ uq4_12_t GetTeraMultiplier(struct BattleContext *ctx)
else
return UQ_4_12(2.0);
}
- // Base or Tera type only.
- else if ((ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
- || (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)))
+ // Tera type only (Adaptability applies).
+ else if (ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
{
if (ctx->abilityAtk == ABILITY_ADAPTABILITY)
return UQ_4_12(2.0);
else
return UQ_4_12(1.5);
}
+ // Base type only (Adaptability does not apply while Terastallized).
+ else if (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))
+ {
+ return UQ_4_12(1.5);
+ }
// Neither base or Tera type.
else
{
diff --git a/src/battle_util.c b/src/battle_util.c
index 6009f9869f..c291139947 100644
--- a/src/battle_util.c
+++ b/src/battle_util.c
@@ -5176,6 +5176,7 @@ static u32 GetStatValueWithStages(enum BattlerId battler, enum Stat stat)
enum Stat GetParadoxHighestStatId(enum BattlerId battler)
{
enum Stat highestId = STAT_ATK;
+ bool32 wonderRoom = gFieldStatuses & STATUS_FIELD_WONDER_ROOM;
u32 highestStat = GetStatValueWithStages(battler, STAT_ATK);
for (u32 stat = STAT_DEF; stat < NUM_STATS; stat++)
@@ -5183,7 +5184,23 @@ enum Stat GetParadoxHighestStatId(enum BattlerId battler)
if (stat == STAT_SPEED)
continue;
- u32 statValue = GetStatValueWithStages(battler, stat);
+ u32 statValue;
+ switch (stat)
+ {
+ case STAT_DEF:
+ statValue = wonderRoom ? gBattleMons[battler].spDefense : gBattleMons[battler].defense;
+ statValue *= gStatStageRatios[gBattleMons[battler].statStages[STAT_DEF]][0];
+ statValue /= gStatStageRatios[gBattleMons[battler].statStages[STAT_DEF]][1];
+ break;
+ case STAT_SPDEF:
+ statValue = wonderRoom ? gBattleMons[battler].defense : gBattleMons[battler].spDefense;
+ statValue *= gStatStageRatios[gBattleMons[battler].statStages[STAT_SPDEF]][0];
+ statValue /= gStatStageRatios[gBattleMons[battler].statStages[STAT_SPDEF]][1];
+ break;
+ default:
+ statValue = GetStatValueWithStages(battler, stat);
+ break;
+ }
if (statValue > highestStat)
{
highestStat = statValue;
@@ -7282,8 +7299,13 @@ static inline u32 CalcDefenseStat(struct BattleContext *ctx)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_EVIOLITE:
- if (CanEvolve(gBattleMons[battlerDef].species))
- modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
+ {
+ u16 species = gBattleMons[battlerDef].species;
+ if (gBattleMons[battlerDef].volatiles.transformed && gBattleMons[battlerDef].volatiles.transformedMonSpecies != SPECIES_NONE)
+ species = gBattleMons[battlerDef].volatiles.transformedMonSpecies;
+ if (CanEvolve(species))
+ modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
+ }
break;
case HOLD_EFFECT_ASSAULT_VEST:
if (!usesDefStat)
diff --git a/src/data/moves_info.h b/src/data/moves_info.h
index acc0a3ab38..e0a3a475db 100644
--- a/src/data/moves_info.h
+++ b/src/data/moves_info.h
@@ -440,7 +440,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
[MOVE_RAZOR_WIND] =
{
.name = COMPOUND_STRING("Razor Wind"),
- #if B_UPDATED_MOVE_DATA == GEN_3
+ #if B_UPDATED_MOVE_DATA == GEN_3 || B_UPDATED_MOVE_DATA == GEN_1
.description = COMPOUND_STRING(
"A 2-turn move that strikes\n"
"the foe on the 2nd turn."),
@@ -455,10 +455,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.accuracy = B_UPDATED_MOVE_DATA >= GEN_3 ? 100 : 75,
#if B_UPDATED_MOVE_DATA >= GEN_4
.criticalHitStage = 1,
- #elif B_UPDATED_MOVE_DATA == GEN_3
- .criticalHitStage = 0,
- #else
+ #elif B_UPDATED_MOVE_DATA == GEN_2
.criticalHitStage = 2,
+ #else
+ .criticalHitStage = 0,
#endif
.pp = 10,
.target = TARGET_BOTH,
@@ -490,6 +490,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_RESET_STATS },
+ .ignoresProtect = TRUE,
+ .mirrorMoveBanned = TRUE,
.danceMove = TRUE,
.snatchAffected = TRUE,
.contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS,
@@ -3262,6 +3264,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_ATK_UP_2 },
+ .ignoresProtect = TRUE,
+ .mirrorMoveBanned = TRUE,
.mimicBanned = TRUE,
.metronomeBanned = B_UPDATED_MOVE_FLAGS >= GEN_4,
.copycatBanned = TRUE,
@@ -4633,7 +4637,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_DEF_UP_1 },
- .ignoresProtect = (B_UPDATED_MOVE_FLAGS >= GEN_6) || (B_UPDATED_MOVE_FLAGS < GEN_3),
+ .ignoresProtect = B_UPDATED_MOVE_FLAGS < GEN_3,
.magicCoatAffected = TRUE,
.contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS,
.contestCategory = CONTEST_CATEGORY_SMART,
@@ -4810,7 +4814,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_RECOVER_HP },
- .ignoresProtect = B_UPDATED_MOVE_FLAGS >= GEN_3,
+ .ignoresProtect = TRUE,
.ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_5,
.mirrorMoveBanned = TRUE,
.contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE,
@@ -4975,6 +4979,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.category = DAMAGE_CATEGORY_STATUS,
.argument = { .protectMethod = PROTECT_NORMAL },
.zMove = { .effect = Z_EFFECT_RESET_STATS },
+ .ignoresProtect = TRUE,
+ .mirrorMoveBanned = TRUE,
.metronomeBanned = TRUE,
.copycatBanned = TRUE,
.assistBanned = TRUE,
@@ -7234,6 +7240,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.target = B_UPDATED_MOVE_FLAGS >= GEN_6 ? TARGET_SELECTED : TARGET_DEPENDS,
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
+ .ignoresProtect = TRUE,
+ .mirrorMoveBanned = TRUE,
.metronomeBanned = B_UPDATED_MOVE_FLAGS >= GEN_5,
.copycatBanned = TRUE,
.sleepTalkBanned = TRUE,
@@ -7806,6 +7814,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.priority = 4,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_SPD_UP_2 },
+ .ignoresProtect = TRUE,
+ .mirrorMoveBanned = TRUE,
.ignoresSubstitute = TRUE,
.forcePressure = TRUE,
.metronomeBanned = TRUE,
diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h
index 4bb6fdf4e2..12b9c06e79 100644
--- a/src/data/pokemon/form_change_tables.h
+++ b/src/data/pokemon/form_change_tables.h
@@ -1514,10 +1514,10 @@ static const struct FormChange sSilvallyFormChangeTable[] =
{FORM_CHANGE_TERMINATOR},
};
#endif //P_FAMILY_TYPE_NULL
-
#if P_FAMILY_MINIOR
static const struct FormChange sMiniorRedFormChangeTable[] =
{
+ {FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_RED},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_RED},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_METEOR_RED, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_CORE_RED, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@@ -1530,6 +1530,7 @@ static const struct FormChange sMiniorRedFormChangeTable[] =
};
static const struct FormChange sMiniorBlueFormChangeTable[] =
{
+ {FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_BLUE},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_BLUE},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_METEOR_BLUE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_CORE_BLUE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@@ -1542,6 +1543,7 @@ static const struct FormChange sMiniorBlueFormChangeTable[] =
};
static const struct FormChange sMiniorGreenFormChangeTable[] =
{
+ {FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_GREEN},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_GREEN},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_METEOR_GREEN, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_CORE_GREEN, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@@ -1554,6 +1556,7 @@ static const struct FormChange sMiniorGreenFormChangeTable[] =
};
static const struct FormChange sMiniorIndigoFormChangeTable[] =
{
+ {FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_INDIGO},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_INDIGO},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_METEOR_INDIGO, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_CORE_INDIGO, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@@ -1566,6 +1569,7 @@ static const struct FormChange sMiniorIndigoFormChangeTable[] =
};
static const struct FormChange sMiniorOrangeFormChangeTable[] =
{
+ {FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_ORANGE},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_ORANGE},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_METEOR_ORANGE, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_CORE_ORANGE, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@@ -1578,6 +1582,7 @@ static const struct FormChange sMiniorOrangeFormChangeTable[] =
};
static const struct FormChange sMiniorVioletFormChangeTable[] =
{
+ {FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_VIOLET},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_VIOLET},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_METEOR_VIOLET, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_CORE_VIOLET, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
@@ -1590,6 +1595,7 @@ static const struct FormChange sMiniorVioletFormChangeTable[] =
};
static const struct FormChange sMiniorYellowFormChangeTable[] =
{
+ {FORM_CHANGE_BEGIN_WILD_ENCOUNTER, SPECIES_MINIOR_METEOR_YELLOW},
{FORM_CHANGE_BEGIN_BATTLE, SPECIES_MINIOR_CORE_YELLOW},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_METEOR_YELLOW, ABILITY_SHIELDS_DOWN, HP_HIGHER_THAN, 50},
{FORM_CHANGE_BATTLE_HP_PERCENT_SEND_OUT, SPECIES_MINIOR_CORE_YELLOW, ABILITY_SHIELDS_DOWN, HP_LOWER_EQ_THAN, 50},
diff --git a/src/decoration.c b/src/decoration.c
index 9cbcfd3026..fa57f3d240 100644
--- a/src/decoration.c
+++ b/src/decoration.c
@@ -1197,7 +1197,7 @@ static void WarpToInitialPosition(u8 taskId)
static u16 GetDecorationElevation(u8 decoration, u8 tileIndex)
{
- u16 elevation = -1;
+ u16 elevation = ELEVATION_INVALID;
switch (decoration)
{
case DECOR_STAND:
@@ -1242,7 +1242,7 @@ static void ShowDecorationOnMap_(u16 mapX, u16 mapY, u8 decWidth, u8 decHeight,
overlapsWall = 0;
elevation = GetDecorationElevation(gDecorations[decoration].id, j * decWidth + i);
- if (elevation != 0xFFFF)
+ if (elevation != ELEVATION_INVALID)
MapGridSetMetatileEntryAt(x, y, (gDecorations[decoration].tiles[j * decWidth + i] + (NUM_TILES_IN_PRIMARY | overlapsWall)) | impassableFlag | elevation);
else
MapGridSetMetatileIdAt(x, y, (gDecorations[decoration].tiles[j * decWidth + i] + (NUM_TILES_IN_PRIMARY | overlapsWall)) | impassableFlag);
diff --git a/src/event_object_movement.c b/src/event_object_movement.c
index 061c594723..7f78782ca5 100644
--- a/src/event_object_movement.c
+++ b/src/event_object_movement.c
@@ -3519,7 +3519,7 @@ u8 GetObjectEventIdByPosition(u16 x, u16 y, u8 elevation)
static bool8 ObjectEventDoesElevationMatch(struct ObjectEvent *objectEvent, u8 elevation)
{
- if (objectEvent->currentElevation != 0 && elevation != 0 && objectEvent->currentElevation != elevation)
+ if (objectEvent->currentElevation != ELEVATION_TRANSITION && elevation != ELEVATION_TRANSITION && objectEvent->currentElevation != elevation)
return FALSE;
return TRUE;
@@ -9983,12 +9983,12 @@ bool8 IsElevationMismatchAt(u8 elevation, s16 x, s16 y)
{
u8 mapElevation;
- if (elevation == 0)
+ if (elevation == ELEVATION_TRANSITION)
return FALSE;
mapElevation = MapGridGetElevationAt(x, y);
- if (mapElevation == 0 || mapElevation == 15)
+ if (mapElevation == ELEVATION_TRANSITION || mapElevation == ELEVATION_MULTI_LEVEL)
return FALSE;
if (mapElevation != elevation)
@@ -10047,7 +10047,7 @@ void ObjectEventUpdateElevation(struct ObjectEvent *objEvent, struct Sprite *spr
u8 curElevation = MapGridGetElevationAt(objEvent->currentCoords.x, objEvent->currentCoords.y);
u8 prevElevation = MapGridGetElevationAt(objEvent->previousCoords.x, objEvent->previousCoords.y);
- if (curElevation == 15 || prevElevation == 15)
+ if (curElevation == ELEVATION_MULTI_LEVEL || prevElevation == ELEVATION_MULTI_LEVEL)
{
// Ignore subsprite priorities under bridges
// so all subsprites will display below it
@@ -10058,7 +10058,7 @@ void ObjectEventUpdateElevation(struct ObjectEvent *objEvent, struct Sprite *spr
objEvent->currentElevation = curElevation;
- if (curElevation != 0 && curElevation != 15)
+ if (curElevation != ELEVATION_TRANSITION && curElevation != ELEVATION_MULTI_LEVEL)
objEvent->previousElevation = curElevation;
}
@@ -10086,7 +10086,7 @@ static void ObjectEventUpdateSubpriority(struct ObjectEvent *objEvent, struct Sp
static bool8 AreElevationsCompatible(u8 a, u8 b)
{
- if (a == 0 || b == 0)
+ if (a == ELEVATION_TRANSITION || b == ELEVATION_TRANSITION)
return TRUE;
if (a != b)
diff --git a/src/fake_rtc.c b/src/fake_rtc.c
index 2024065b7d..c6b68d9105 100644
--- a/src/fake_rtc.c
+++ b/src/fake_rtc.c
@@ -50,6 +50,9 @@ void FakeRtc_TickTimeForward(void)
void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds)
{
+ if (!OW_USE_FAKE_RTC)
+ return;
+
struct DateTime dateTime;
struct SiiRtcInfo *rtc = FakeRtc_GetCurrentTime();
@@ -63,6 +66,9 @@ void FakeRtc_AdvanceTimeBy(u32 days, u32 hours, u32 minutes, u32 seconds)
void FakeRtc_ForwardTimeTo(u32 hour, u32 minute, u32 second)
{
+ if (!OW_USE_FAKE_RTC)
+ return;
+
Script_PauseFakeRtc();
struct Time diff, target;
struct SiiRtcInfo *fakeRtc = FakeRtc_GetCurrentTime();
diff --git a/src/field_control_avatar.c b/src/field_control_avatar.c
index 201ede59c9..96afec4c1f 100644
--- a/src/field_control_avatar.c
+++ b/src/field_control_avatar.c
@@ -268,10 +268,10 @@ static void GetInFrontOfPlayerPosition(struct MapPosition *position)
GetXYCoordsOneStepInFrontOfPlayer(&position->x, &position->y);
PlayerGetDestCoords(&x, &y);
- if (MapGridGetElevationAt(x, y) != 0)
+ if (MapGridGetElevationAt(x, y) != ELEVATION_TRANSITION)
position->elevation = PlayerGetElevation();
else
- position->elevation = 0;
+ position->elevation = ELEVATION_TRANSITION;
}
static u16 GetPlayerCurMetatileBehavior(int runningState)
@@ -1114,7 +1114,7 @@ static s8 GetWarpEventAtPosition(struct MapHeader *mapHeader, u16 x, u16 y, u8 e
{
if ((u16)warpEvent->x == x && (u16)warpEvent->y == y)
{
- if (warpEvent->elevation == elevation || warpEvent->elevation == 0)
+ if (warpEvent->elevation == elevation || warpEvent->elevation == ELEVATION_TRANSITION)
return i;
}
}
@@ -1161,7 +1161,7 @@ static const u8 *GetCoordEventScriptAtPosition(struct MapHeader *mapHeader, u16
{
if ((u16)coordEvents[i].x == x && (u16)coordEvents[i].y == y)
{
- if (coordEvents[i].elevation == elevation || coordEvents[i].elevation == 0)
+ if (coordEvents[i].elevation == elevation || coordEvents[i].elevation == ELEVATION_TRANSITION)
{
const u8 *script = TryRunCoordEventScript(&coordEvents[i]);
if (script != NULL)
@@ -1187,7 +1187,7 @@ static const struct BgEvent *GetBackgroundEventAtPosition(struct MapHeader *mapH
{
if ((u16)bgEvents[i].x == x && (u16)bgEvents[i].y == y)
{
- if (bgEvents[i].elevation == elevation || bgEvents[i].elevation == 0)
+ if (bgEvents[i].elevation == elevation || bgEvents[i].elevation == ELEVATION_TRANSITION)
return &bgEvents[i];
}
}
diff --git a/src/field_effect_helpers.c b/src/field_effect_helpers.c
index 336e452d96..d7c56ea289 100755
--- a/src/field_effect_helpers.c
+++ b/src/field_effect_helpers.c
@@ -1289,7 +1289,7 @@ void SynchronizeSurfPosition(struct ObjectEvent *playerObj, struct Sprite *sprit
for (i = DIR_SOUTH; i <= DIR_EAST; i++, x = sprite->sPrevX, y = sprite->sPrevY)
{
MoveCoords(i, &x, &y);
- if (MapGridGetElevationAt(x, y) == 3)
+ if (MapGridGetElevationAt(x, y) == ELEVATION_DEFAULT)
{
// While dismounting the surf blob bobs at a slower rate
sprite->sIntervalIdx++;
diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c
index 82e766703b..492a5fc7b7 100644
--- a/src/field_player_avatar.c
+++ b/src/field_player_avatar.c
@@ -1013,9 +1013,9 @@ static enum Collision CheckForObjectEventStaticCollision(struct ObjectEvent *obj
static bool8 CanStopSurfing(s16 x, s16 y, enum Direction direction)
{
if ((gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING)
- && MapGridGetElevationAt(x, y) == 3
- && (GetObjectEventIdByPosition(x, y, 3) == OBJECT_EVENTS_COUNT
- || GetObjectEventIdByPosition(x, y, 3) == GetFollowerNPCObjectId()
+ && MapGridGetElevationAt(x, y) == ELEVATION_DEFAULT
+ && (GetObjectEventIdByPosition(x, y, ELEVATION_DEFAULT) == OBJECT_EVENTS_COUNT
+ || GetObjectEventIdByPosition(x, y, ELEVATION_DEFAULT) == GetFollowerNPCObjectId()
))
{
CreateStopSurfingTask(direction);
@@ -1663,7 +1663,7 @@ bool8 IsPlayerFacingSurfableFishableWater(void)
MoveCoords(playerObjEvent->facingDirection, &x, &y);
if (GetCollisionAtCoords(playerObjEvent, x, y, playerObjEvent->facingDirection) == COLLISION_ELEVATION_MISMATCH
- && PlayerGetElevation() == 3
+ && PlayerGetElevation() == ELEVATION_DEFAULT
&& MetatileBehavior_IsSurfableFishableWater(MapGridGetMetatileBehaviorAt(x, y)))
return TRUE;
else
@@ -1724,7 +1724,7 @@ void InitPlayerAvatar(s16 x, s16 y, enum Direction direction, enum Gender gender
playerObjEventTemplate.graphicsId = GetPlayerAvatarGraphicsIdByStateIdAndGender(PLAYER_AVATAR_STATE_NORMAL, gender);
playerObjEventTemplate.x = x - MAP_OFFSET;
playerObjEventTemplate.y = y - MAP_OFFSET;
- playerObjEventTemplate.elevation = 0;
+ playerObjEventTemplate.elevation = ELEVATION_TRANSITION;
playerObjEventTemplate.movementType = MOVEMENT_TYPE_PLAYER;
playerObjEventTemplate.movementRangeX = 0;
playerObjEventTemplate.movementRangeY = 0;
diff --git a/src/field_specials.c b/src/field_specials.c
index 3d0485bcaa..10e202271d 100644
--- a/src/field_specials.c
+++ b/src/field_specials.c
@@ -1360,7 +1360,7 @@ void SpawnCameraObject(void)
LOCALID_CAMERA,
gSaveBlock1Ptr->pos.x + MAP_OFFSET,
gSaveBlock1Ptr->pos.y + MAP_OFFSET,
- 3); // elevation
+ ELEVATION_DEFAULT);
gObjectEvents[obj].invisible = TRUE;
CameraObjectSetFollowedSpriteId(gObjectEvents[obj].spriteId);
}
diff --git a/src/overworld.c b/src/overworld.c
index 3600956d85..795dfed4a7 100644
--- a/src/overworld.c
+++ b/src/overworld.c
@@ -3149,7 +3149,7 @@ static const u8 *TryInteractWithPlayer(struct CableClubPlayer *player)
otherPlayerPos = player->pos;
otherPlayerPos.x += gDirectionToVectors[player->facing].x;
otherPlayerPos.y += gDirectionToVectors[player->facing].y;
- otherPlayerPos.elevation = 0;
+ otherPlayerPos.elevation = ELEVATION_TRANSITION;
linkPlayerId = GetLinkPlayerIdAt(otherPlayerPos.x, otherPlayerPos.y);
if (linkPlayerId != MAX_LINK_PLAYERS)
diff --git a/src/pokemon.c b/src/pokemon.c
index 499997fd41..2c923a5b54 100644
--- a/src/pokemon.c
+++ b/src/pokemon.c
@@ -6692,6 +6692,7 @@ u32 GetFormChangeTargetSpecies_Internal(struct FormChangeContext ctx)
case FORM_CHANGE_DEPOSIT:
case FORM_CHANGE_FAINT:
case FORM_CHANGE_DAYS_PASSED:
+ case FORM_CHANGE_BEGIN_WILD_ENCOUNTER:
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_STATUS:
diff --git a/src/pokenav_match_call_data.c b/src/pokenav_match_call_data.c
index 2c6316146a..24546bf2c7 100644
--- a/src/pokenav_match_call_data.c
+++ b/src/pokenav_match_call_data.c
@@ -28,8 +28,8 @@ enum
typedef struct MatchCallTextDataStruct {
const u8 *text;
- u16 flag;
- u16 flag2;
+ u16 availabilityFlag;
+ u16 flagToSetOnCompletion;
} match_call_text_data_t;
struct MatchCallStructCommon {
@@ -157,21 +157,25 @@ static void MatchCall_BufferCallMessageText(const match_call_text_data_t *, u8 *
static void MatchCall_BufferCallMessageTextByRematchTeam(const match_call_text_data_t *, u16, u8 *);
static void MatchCall_GetNameAndDescByRematchIdx(u32, const u8 **, const u8 **);
+#define ALWAYS_AVAILABLE 0xFFFF
+#define NO_FLAG_TO_SET 0xFFFF
+#define MATCH_CALL_TEXT_END {NULL, ALWAYS_AVAILABLE, NO_FLAG_TO_SET}
+
// .rodata
static const match_call_text_data_t sMrStoneTextScripts[] = {
- { MatchCall_Text_MrStone1, 0xFFFF, FLAG_ENABLE_MR_STONE_POKENAV },
- { MatchCall_Text_MrStone2, FLAG_ENABLE_MR_STONE_POKENAV, 0xFFFF },
- { MatchCall_Text_MrStone3, FLAG_DELIVERED_STEVEN_LETTER, 0xFFFF },
- { MatchCall_Text_MrStone4, FLAG_RECEIVED_EXP_SHARE, 0xFFFF },
- { MatchCall_Text_MrStone5, FLAG_RECEIVED_HM_STRENGTH, 0xFFFF },
- { MatchCall_Text_MrStone6, FLAG_DEFEATED_PETALBURG_GYM, 0xFFFF },
- { MatchCall_Text_MrStone7, FLAG_RECEIVED_CASTFORM, 0xFFFF },
- { MatchCall_Text_MrStone8, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, 0xFFFF },
- { MatchCall_Text_MrStone9, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, 0xFFFF },
- { MatchCall_Text_MrStone10, FLAG_DEFEATED_SOOTOPOLIS_GYM, 0xFFFF },
- { MatchCall_Text_MrStone11, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_MrStone1, ALWAYS_AVAILABLE, FLAG_ENABLE_MR_STONE_POKENAV },
+ { MatchCall_Text_MrStone2, FLAG_ENABLE_MR_STONE_POKENAV, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone3, FLAG_DELIVERED_STEVEN_LETTER, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone4, FLAG_RECEIVED_EXP_SHARE, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone5, FLAG_RECEIVED_HM_STRENGTH, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone6, FLAG_DEFEATED_PETALBURG_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone7, FLAG_RECEIVED_CASTFORM, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone8, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone9, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone10, FLAG_DEFEATED_SOOTOPOLIS_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_MrStone11, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructNPC sMrStoneMatchCallHeader =
@@ -185,16 +189,16 @@ static const struct MatchCallStructNPC sMrStoneMatchCallHeader =
};
static const match_call_text_data_t sNormanTextScripts[] = {
- { MatchCall_Text_Norman1, FLAG_ENABLE_NORMAN_MATCH_CALL, 0xFFFF },
- { MatchCall_Text_Norman2, FLAG_DEFEATED_DEWFORD_GYM, 0xFFFF },
- { MatchCall_Text_Norman3, FLAG_DEFEATED_LAVARIDGE_GYM, 0xFFFF },
- { MatchCall_Text_Norman4, FLAG_DEFEATED_PETALBURG_GYM, 0xFFFF },
- { MatchCall_Text_Norman5, FLAG_RECEIVED_RED_OR_BLUE_ORB, 0xFFFF },
- { MatchCall_Text_Norman6, 0xFFFE, 0xFFFF },
- { MatchCall_Text_Norman7, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { MatchCall_Text_Norman8, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { MatchCall_Text_Norman9, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Norman1, FLAG_ENABLE_NORMAN_MATCH_CALL, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman2, FLAG_DEFEATED_DEWFORD_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman3, FLAG_DEFEATED_LAVARIDGE_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman4, FLAG_DEFEATED_PETALBURG_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman5, FLAG_RECEIVED_RED_OR_BLUE_ORB, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman6, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman7, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman8, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ { MatchCall_Text_Norman9, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sNormanMatchCallHeader =
@@ -218,10 +222,10 @@ static const struct MatchCallBirch sProfBirchMatchCallHeader =
};
static const match_call_text_data_t sMomTextScripts[] = {
- { MatchCall_Text_Mom1, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Mom2, FLAG_DEFEATED_PETALBURG_GYM, 0xFFFF },
- { MatchCall_Text_Mom3, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Mom1, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Mom2, FLAG_DEFEATED_PETALBURG_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Mom3, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructNPC sMomMatchCallHeader =
@@ -235,14 +239,14 @@ static const struct MatchCallStructNPC sMomMatchCallHeader =
};
static const match_call_text_data_t sStevenTextScripts[] = {
- { MatchCall_Text_Steven1, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Steven2, FLAG_RUSTURF_TUNNEL_OPENED, 0xFFFF },
- { MatchCall_Text_Steven3, FLAG_RECEIVED_RED_OR_BLUE_ORB, 0xFFFF },
- { MatchCall_Text_Steven4, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, 0xFFFF },
- { MatchCall_Text_Steven5, FLAG_DEFEATED_MOSSDEEP_GYM, 0xFFFF },
- { MatchCall_Text_Steven6, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, 0xFFFF },
- { MatchCall_Text_Steven7, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF },
+ { MatchCall_Text_Steven1, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Steven2, FLAG_RUSTURF_TUNNEL_OPENED, NO_FLAG_TO_SET },
+ { MatchCall_Text_Steven3, FLAG_RECEIVED_RED_OR_BLUE_ORB, NO_FLAG_TO_SET },
+ { MatchCall_Text_Steven4, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Steven5, FLAG_DEFEATED_MOSSDEEP_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Steven6, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, NO_FLAG_TO_SET },
+ { MatchCall_Text_Steven7, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END,
};
static const struct MatchCallStructNPC sStevenMatchCallHeader =
@@ -258,22 +262,22 @@ static const struct MatchCallStructNPC sStevenMatchCallHeader =
static const u8 gText_MayBrendanMatchCallDesc[] = _("RAD NEIGHBOR");
static const match_call_text_data_t sMayTextScripts[] = {
- { MatchCall_Text_May1, 0xFFFF, 0xFFFF },
- { MatchCall_Text_May2, FLAG_DEFEATED_DEWFORD_GYM, 0xFFFF },
- { MatchCall_Text_May3, FLAG_DELIVERED_DEVON_GOODS, 0xFFFF },
- { MatchCall_Text_May4, FLAG_HIDE_MAUVILLE_CITY_WALLY, 0xFFFF },
- { MatchCall_Text_May5, FLAG_RECEIVED_HM_STRENGTH, 0xFFFF },
- { MatchCall_Text_May6, FLAG_DEFEATED_LAVARIDGE_GYM, 0xFFFF },
- { MatchCall_Text_May7, FLAG_DEFEATED_PETALBURG_GYM, 0xFFFF },
- { MatchCall_Text_May8, FLAG_RECEIVED_CASTFORM, 0xFFFF },
- { MatchCall_Text_May9, FLAG_RECEIVED_RED_OR_BLUE_ORB, 0xFFFF },
- { MatchCall_Text_May10, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, 0xFFFF },
- { MatchCall_Text_May11, FLAG_MET_TEAM_AQUA_HARBOR, 0xFFFF },
- { MatchCall_Text_May12, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, 0xFFFF },
- { MatchCall_Text_May13, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, 0xFFFF },
- { MatchCall_Text_May14, FLAG_DEFEATED_SOOTOPOLIS_GYM, 0xFFFF },
- { MatchCall_Text_May15, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_May1, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_May2, FLAG_DEFEATED_DEWFORD_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_May3, FLAG_DELIVERED_DEVON_GOODS, NO_FLAG_TO_SET },
+ { MatchCall_Text_May4, FLAG_HIDE_MAUVILLE_CITY_WALLY, NO_FLAG_TO_SET },
+ { MatchCall_Text_May5, FLAG_RECEIVED_HM_STRENGTH, NO_FLAG_TO_SET },
+ { MatchCall_Text_May6, FLAG_DEFEATED_LAVARIDGE_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_May7, FLAG_DEFEATED_PETALBURG_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_May8, FLAG_RECEIVED_CASTFORM, NO_FLAG_TO_SET },
+ { MatchCall_Text_May9, FLAG_RECEIVED_RED_OR_BLUE_ORB, NO_FLAG_TO_SET },
+ { MatchCall_Text_May10, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, NO_FLAG_TO_SET },
+ { MatchCall_Text_May11, FLAG_MET_TEAM_AQUA_HARBOR, NO_FLAG_TO_SET },
+ { MatchCall_Text_May12, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, NO_FLAG_TO_SET },
+ { MatchCall_Text_May13, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, NO_FLAG_TO_SET },
+ { MatchCall_Text_May14, FLAG_DEFEATED_SOOTOPOLIS_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_May15, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallRival sMayMatchCallHeader =
@@ -287,22 +291,22 @@ static const struct MatchCallRival sMayMatchCallHeader =
};
static const match_call_text_data_t sBrendanTextScripts[] = {
- { MatchCall_Text_Brendan1, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Brendan2, FLAG_DEFEATED_DEWFORD_GYM, 0xFFFF },
- { MatchCall_Text_Brendan3, FLAG_DELIVERED_DEVON_GOODS, 0xFFFF },
- { MatchCall_Text_Brendan4, FLAG_HIDE_MAUVILLE_CITY_WALLY, 0xFFFF },
- { MatchCall_Text_Brendan5, FLAG_RECEIVED_HM_STRENGTH, 0xFFFF },
- { MatchCall_Text_Brendan6, FLAG_DEFEATED_LAVARIDGE_GYM, 0xFFFF },
- { MatchCall_Text_Brendan7, FLAG_DEFEATED_PETALBURG_GYM, 0xFFFF },
- { MatchCall_Text_Brendan8, FLAG_RECEIVED_CASTFORM, 0xFFFF },
- { MatchCall_Text_Brendan9, FLAG_RECEIVED_RED_OR_BLUE_ORB, 0xFFFF },
- { MatchCall_Text_Brendan10, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, 0xFFFF },
- { MatchCall_Text_Brendan11, FLAG_MET_TEAM_AQUA_HARBOR, 0xFFFF },
- { MatchCall_Text_Brendan12, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, 0xFFFF },
- { MatchCall_Text_Brendan13, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, 0xFFFF },
- { MatchCall_Text_Brendan14, FLAG_DEFEATED_SOOTOPOLIS_GYM, 0xFFFF },
- { MatchCall_Text_Brendan15, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Brendan1, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan2, FLAG_DEFEATED_DEWFORD_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan3, FLAG_DELIVERED_DEVON_GOODS, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan4, FLAG_HIDE_MAUVILLE_CITY_WALLY, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan5, FLAG_RECEIVED_HM_STRENGTH, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan6, FLAG_DEFEATED_LAVARIDGE_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan7, FLAG_DEFEATED_PETALBURG_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan8, FLAG_RECEIVED_CASTFORM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan9, FLAG_RECEIVED_RED_OR_BLUE_ORB, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan10, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan11, FLAG_MET_TEAM_AQUA_HARBOR, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan12, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan13, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan14, FLAG_DEFEATED_SOOTOPOLIS_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brendan15, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallRival sBrendanMatchCallHeader =
@@ -316,14 +320,14 @@ static const struct MatchCallRival sBrendanMatchCallHeader =
};
static const match_call_text_data_t sWallyTextScripts[] = {
- { MatchCall_Text_Wally1, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Wally2, FLAG_RUSTURF_TUNNEL_OPENED, 0xFFFF },
- { MatchCall_Text_Wally3, FLAG_DEFEATED_LAVARIDGE_GYM, 0xFFFF },
- { MatchCall_Text_Wally4, FLAG_RECEIVED_CASTFORM, 0xFFFF },
- { MatchCall_Text_Wally5, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, 0xFFFF },
- { MatchCall_Text_Wally6, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, 0xFFFF },
- { MatchCall_Text_Wally7, FLAG_DEFEATED_WALLY_VICTORY_ROAD, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Wally1, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wally2, FLAG_RUSTURF_TUNNEL_OPENED, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wally3, FLAG_DEFEATED_LAVARIDGE_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wally4, FLAG_RECEIVED_CASTFORM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wally5, FLAG_GROUDON_AWAKENED_MAGMA_HIDEOUT, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wally6, FLAG_KYOGRE_ESCAPED_SEAFLOOR_CAVERN, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wally7, FLAG_DEFEATED_WALLY_VICTORY_ROAD, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallLocationOverride sWallyLocationData[] = {
@@ -345,14 +349,14 @@ static const struct MatchCallWally sWallyMatchCallHeader =
};
static const match_call_text_data_t sScottTextScripts[] = {
- { MatchCall_Text_Scott1, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Scott2, FLAG_DEFEATED_EVIL_TEAM_MT_CHIMNEY, 0xFFFF },
- { MatchCall_Text_Scott3, FLAG_RECEIVED_CASTFORM, 0xFFFF },
- { MatchCall_Text_Scott4, FLAG_RECEIVED_RED_OR_BLUE_ORB, 0xFFFF },
- { MatchCall_Text_Scott5, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, 0xFFFF },
- { MatchCall_Text_Scott6, FLAG_DEFEATED_SOOTOPOLIS_GYM, 0xFFFF },
- { MatchCall_Text_Scott7, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Scott1, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Scott2, FLAG_DEFEATED_EVIL_TEAM_MT_CHIMNEY, NO_FLAG_TO_SET },
+ { MatchCall_Text_Scott3, FLAG_RECEIVED_CASTFORM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Scott4, FLAG_RECEIVED_RED_OR_BLUE_ORB, NO_FLAG_TO_SET },
+ { MatchCall_Text_Scott5, FLAG_TEAM_AQUA_ESCAPED_IN_SUBMARINE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Scott6, FLAG_DEFEATED_SOOTOPOLIS_GYM, NO_FLAG_TO_SET },
+ { MatchCall_Text_Scott7, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
@@ -367,11 +371,11 @@ static const struct MatchCallStructNPC sScottMatchCallHeader =
};
static const match_call_text_data_t sRoxanneTextScripts[] = {
- { MatchCall_Text_Roxanne1, 0xFFFE, 0xFFFF },
- { MatchCall_Text_Roxanne2, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Roxanne3, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Roxanne4, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Roxanne1, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Roxanne2, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Roxanne3, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Roxanne4, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sRoxanneMatchCallHeader =
@@ -386,11 +390,11 @@ static const struct MatchCallStructTrainer sRoxanneMatchCallHeader =
};
static const match_call_text_data_t sBrawlyTextScripts[] = {
- { MatchCall_Text_Brawly1, 0xFFFE, 0xFFFF },
- { MatchCall_Text_Brawly2, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Brawly3, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Brawly4, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Brawly1, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brawly2, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brawly3, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Brawly4, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sBrawlyMatchCallHeader =
@@ -405,11 +409,11 @@ static const struct MatchCallStructTrainer sBrawlyMatchCallHeader =
};
static const match_call_text_data_t sWattsonTextScripts[] = {
- { MatchCall_Text_Wattson1, 0xFFFE, 0xFFFF },
- { MatchCall_Text_Wattson2, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Wattson3, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Wattson4, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Wattson1, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wattson2, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wattson3, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Wattson4, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sWattsonMatchCallHeader =
@@ -424,11 +428,11 @@ static const struct MatchCallStructTrainer sWattsonMatchCallHeader =
};
static const match_call_text_data_t sFlanneryTextScripts[] = {
- { MatchCall_Text_Flannery1, 0xFFFE, 0xFFFF },
- { MatchCall_Text_Flannery2, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Flannery3, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Flannery4, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Flannery1, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Flannery2, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Flannery3, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Flannery4, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sFlanneryMatchCallHeader =
@@ -443,11 +447,11 @@ static const struct MatchCallStructTrainer sFlanneryMatchCallHeader =
};
static const match_call_text_data_t sWinonaTextScripts[] = {
- { MatchCall_Text_Winona1, 0xFFFE, 0xFFFF },
- { MatchCall_Text_Winona2, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Winona3, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Winona4, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Winona1, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Winona2, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Winona3, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Winona4, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sWinonaMatchCallHeader =
@@ -462,11 +466,11 @@ static const struct MatchCallStructTrainer sWinonaMatchCallHeader =
};
static const match_call_text_data_t sTateLizaTextScripts[] = {
- { MatchCall_Text_TateLiza1, 0xFFFE, 0xFFFF },
- { MatchCall_Text_TateLiza2, 0xFFFF, 0xFFFF },
- { MatchCall_Text_TateLiza3, 0xFFFF, 0xFFFF },
- { MatchCall_Text_TateLiza4, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_TateLiza1, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_TateLiza2, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_TateLiza3, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_TateLiza4, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sTateLizaMatchCallHeader =
@@ -481,11 +485,11 @@ static const struct MatchCallStructTrainer sTateLizaMatchCallHeader =
};
static const match_call_text_data_t sJuanTextScripts[] = {
- { MatchCall_Text_Juan1, 0xFFFE, 0xFFFF },
- { MatchCall_Text_Juan2, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Juan3, 0xFFFF, 0xFFFF },
- { MatchCall_Text_Juan4, FLAG_SYS_GAME_CLEAR, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Juan1, 0xFFFE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Juan2, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Juan3, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ { MatchCall_Text_Juan4, FLAG_SYS_GAME_CLEAR, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sJuanMatchCallHeader =
@@ -502,8 +506,8 @@ static const struct MatchCallStructTrainer sJuanMatchCallHeader =
static const u8 gText_EliteFourMatchCallDesc[] = _("ELITE FOUR");
static const match_call_text_data_t sSidneyTextScripts[] = {
- { MatchCall_Text_Sidney, 0xFFFF, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Sidney, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sSidneyMatchCallHeader =
@@ -518,8 +522,8 @@ static const struct MatchCallStructTrainer sSidneyMatchCallHeader =
};
static const match_call_text_data_t sPhoebeTextScripts[] = {
- { MatchCall_Text_Phoebe, 0xFFFF, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Phoebe, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sPhoebeMatchCallHeader =
@@ -534,8 +538,8 @@ static const struct MatchCallStructTrainer sPhoebeMatchCallHeader =
};
static const match_call_text_data_t sGlaciaTextScripts[] = {
- { MatchCall_Text_Glacia, 0xFFFF, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Glacia, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sGlaciaMatchCallHeader =
@@ -550,8 +554,8 @@ static const struct MatchCallStructTrainer sGlaciaMatchCallHeader =
};
static const match_call_text_data_t sDrakeTextScripts[] = {
- { MatchCall_Text_Drake, 0xFFFF, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Drake, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sDrakeMatchCallHeader =
@@ -566,8 +570,8 @@ static const struct MatchCallStructTrainer sDrakeMatchCallHeader =
};
static const match_call_text_data_t sWallaceTextScripts[] = {
- { MatchCall_Text_Wallace, 0xFFFF, 0xFFFF },
- { NULL, 0xFFFF, 0xFFFF }
+ { MatchCall_Text_Wallace, ALWAYS_AVAILABLE, NO_FLAG_TO_SET },
+ MATCH_CALL_TEXT_END
};
static const struct MatchCallStructTrainer sWallaceMatchCallHeader =
@@ -1018,12 +1022,12 @@ static void MatchCall_BufferCallMessageText(const match_call_text_data_t *textDa
i--;
while (i)
{
- if (textData[i].flag != 0xFFFF && FlagGet(textData[i].flag) == TRUE)
+ if (textData[i].availabilityFlag != ALWAYS_AVAILABLE && FlagGet(textData[i].availabilityFlag) == TRUE)
break;
i--;
}
- if (textData[i].flag2 != 0xFFFF)
- FlagSet(textData[i].flag2);
+ if (textData[i].flagToSetOnCompletion != NO_FLAG_TO_SET)
+ FlagSet(textData[i].flagToSetOnCompletion);
StringExpandPlaceholders(dest, textData[i].text);
}
@@ -1033,17 +1037,17 @@ static void MatchCall_BufferCallMessageTextByRematchTeam(const match_call_text_d
u32 i;
for (i = 0; textData[i].text != NULL; i++)
{
- if (textData[i].flag == 0xFFFE)
+ if (textData[i].availabilityFlag == 0xFFFE)
break;
- if (textData[i].flag != 0xFFFF && !FlagGet(textData[i].flag))
+ if (textData[i].availabilityFlag != ALWAYS_AVAILABLE && !FlagGet(textData[i].availabilityFlag))
break;
}
- if (textData[i].flag != 0xFFFE)
+ if (textData[i].availabilityFlag != 0xFFFE)
{
if (i)
i--;
- if (textData[i].flag2 != 0xFFFF)
- FlagSet(textData[i].flag2);
+ if (textData[i].flagToSetOnCompletion != NO_FLAG_TO_SET)
+ FlagSet(textData[i].flagToSetOnCompletion);
StringExpandPlaceholders(dest, textData[i].text);
}
else
diff --git a/src/rtc.c b/src/rtc.c
index f553092909..2a9bc4adf6 100644
--- a/src/rtc.c
+++ b/src/rtc.c
@@ -351,7 +351,8 @@ void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds)
gLocalTime.hours = hours;
gLocalTime.minutes = minutes;
gLocalTime.seconds = seconds;
- FakeRtc_ManuallySetTime(gLocalTime.days, gLocalTime.hours, gLocalTime.minutes, seconds);
+ if (!OW_USE_FAKE_RTC)
+ FakeRtc_ManuallySetTime(gLocalTime.days, gLocalTime.hours, gLocalTime.minutes, seconds);
RtcGetInfo(&sRtc);
RtcCalcTimeDifference(&sRtc, &gSaveBlock2Ptr->localTimeOffset, &gLocalTime);
}
diff --git a/src/scrcmd.c b/src/scrcmd.c
index 865b385941..ce22da1985 100644
--- a/src/scrcmd.c
+++ b/src/scrcmd.c
@@ -3257,6 +3257,9 @@ bool8 ScrCmd_fwdtime(struct ScriptContext *ctx)
bool8 ScrCmd_fwdweekday(struct ScriptContext *ctx)
{
+ if (!OW_USE_FAKE_RTC)
+ return FALSE;
+
struct SiiRtcInfo *rtc = FakeRtc_GetCurrentTime();
u32 weekdayTarget = ScriptReadWord(ctx);
diff --git a/src/trainer_hill.c b/src/trainer_hill.c
index f87100df25..12fa797d3d 100644
--- a/src/trainer_hill.c
+++ b/src/trainer_hill.c
@@ -263,7 +263,7 @@ static const u8 *const sModeStrings[NUM_TRAINER_HILL_MODES] =
static const struct ObjectEventTemplate sTrainerObjectEventTemplate =
{
.graphicsId = OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL,
- .elevation = 3,
+ .elevation = ELEVATION_DEFAULT,
.movementType = MOVEMENT_TYPE_LOOK_AROUND,
.movementRangeX = 1,
.movementRangeY = 1,
@@ -716,7 +716,7 @@ static u16 GetMapDataForFloor(u8 floorId, u32 x, u32 y, u32 floorWidth) // floor
impassable = (sHillData->floors[floorId].map.collisionData[y] >> (15 - x) & 1);
metatileId = sHillData->floors[floorId].map.metatileData[floorWidth * y + x] + NUM_METATILES_IN_PRIMARY;
- elevation = PACK_ELEVATION(3);
+ elevation = PACK_ELEVATION(ELEVATION_DEFAULT);
return PACK_COLLISION(impassable) | elevation | PACK_METATILE(metatileId);
}
diff --git a/test/battle/ability/adaptability.c b/test/battle/ability/adaptability.c
index 876dac212c..ba54590cd2 100644
--- a/test/battle/ability/adaptability.c
+++ b/test/battle/ability/adaptability.c
@@ -61,4 +61,39 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the same type with Adaptability g
}
}
-TO_DO_BATTLE_TEST("Adaptability does not affect Stellar-type moves");
+SINGLE_BATTLE_TEST("(TERA) Adaptability does not increase non-Tera base STAB beyond 1.5x", s16 damage)
+{
+ u32 move;
+ PARAMETRIZE { move = MOVE_GUST; }
+ PARAMETRIZE { move = MOVE_WATER_GUN; }
+ GIVEN {
+ PLAYER(SPECIES_CRAWDAUNT) { Ability(ABILITY_ADAPTABILITY); TeraType(TYPE_NORMAL); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(player, move, gimmick: GIMMICK_TERA); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, move, player);
+ HP_BAR(opponent, captureDamage: &results[i].damage);
+ } FINALLY {
+ // With Adaptability, non-Tera base type should still be 1.5x STAB (not 2.0x).
+ EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
+ }
+}
+
+SINGLE_BATTLE_TEST("(TERA) Adaptability does not affect Stellar-type moves", s16 damage)
+{
+ u32 ability;
+ PARAMETRIZE { ability = ABILITY_HYPER_CUTTER; }
+ PARAMETRIZE { ability = ABILITY_ADAPTABILITY; }
+ GIVEN {
+ PLAYER(SPECIES_CRAWDAUNT) { Ability(ability); TeraType(TYPE_STELLAR); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(player, MOVE_TERA_BLAST, gimmick: GIMMICK_TERA); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player);
+ HP_BAR(opponent, captureDamage: &results[i].damage);
+ } FINALLY {
+ EXPECT_EQ(results[0].damage, results[1].damage);
+ }
+}
diff --git a/test/battle/ability/hadron_engine.c b/test/battle/ability/hadron_engine.c
index e6324c0c51..0de50c94ec 100644
--- a/test/battle/ability/hadron_engine.c
+++ b/test/battle/ability/hadron_engine.c
@@ -1,4 +1,45 @@
#include "global.h"
#include "test/battle.h"
-TO_DO_BATTLE_TEST("TODO: Write Hadron Engine (Ability) test titles")
+SINGLE_BATTLE_TEST("Hadron Engine creates Electric Terrain when entering the battle")
+{
+ GIVEN {
+ PLAYER(SPECIES_MIRAIDON) { Ability(ABILITY_HADRON_ENGINE); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN {}
+ } SCENE {
+ ABILITY_POPUP(player, ABILITY_HADRON_ENGINE);
+ MESSAGE("An electric current ran across the battlefield!");
+ }
+}
+
+SINGLE_BATTLE_TEST("Hadron Engine boosts the Pokemon's Special Attack on Electric Terrain even if not grounded", s16 damage)
+{
+ bool32 overrideTerrain, airBalloon;
+
+ PARAMETRIZE { airBalloon = FALSE; overrideTerrain = TRUE; }
+ PARAMETRIZE { airBalloon = FALSE; overrideTerrain = FALSE; }
+ PARAMETRIZE { airBalloon = TRUE; overrideTerrain = TRUE; }
+ PARAMETRIZE { airBalloon = TRUE; overrideTerrain = FALSE; }
+
+ GIVEN {
+ ASSUME(gItemsInfo[ITEM_AIR_BALLOON].holdEffect == HOLD_EFFECT_AIR_BALLOON);
+ ASSUME(GetMoveEffect(MOVE_GRASSY_TERRAIN) == EFFECT_GRASSY_TERRAIN);
+ ASSUME(GetMoveCategory(MOVE_POWER_GEM) == DAMAGE_CATEGORY_SPECIAL);
+ PLAYER(SPECIES_MIRAIDON) { Ability(ABILITY_HADRON_ENGINE); Moves(MOVE_POWER_GEM, MOVE_CELEBRATE); Item(airBalloon ? ITEM_AIR_BALLOON : ITEM_NONE); Speed(1); }
+ OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_GRASSY_TERRAIN, MOVE_CELEBRATE); Speed(2); }
+ } WHEN {
+ if (overrideTerrain)
+ TURN { MOVE(opponent, MOVE_GRASSY_TERRAIN); }
+ TURN { MOVE(player, MOVE_POWER_GEM); }
+ } SCENE {
+ if (overrideTerrain)
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_GRASSY_TERRAIN, opponent);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_POWER_GEM, player);
+ HP_BAR(opponent, captureDamage: &results[i].damage);
+ } FINALLY {
+ EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.3333), results[1].damage);
+ EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.3333), results[3].damage);
+ }
+}
diff --git a/test/battle/ability/protosynthesis.c b/test/battle/ability/protosynthesis.c
index e2761724b7..9127d3fe2f 100644
--- a/test/battle/ability/protosynthesis.c
+++ b/test/battle/ability/protosynthesis.c
@@ -134,6 +134,23 @@ SINGLE_BATTLE_TEST("Protosynthesis prioritizes stats in the case of a tie in the
}
}
+SINGLE_BATTLE_TEST("Protosynthesis uses Wonder Room swapped defenses when choosing boosted stat")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_WONDER_ROOM) == EFFECT_WONDER_ROOM);
+ PLAYER(SPECIES_ROARING_MOON) { Ability(ABILITY_PROTOSYNTHESIS); Attack(50); Defense(200); SpAttack(40); SpDefense(60); Speed(70); Moves(MOVE_WONDER_ROOM); }
+ OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUNNY_DAY); Speed(60); }
+ } WHEN {
+ TURN { MOVE(player, MOVE_WONDER_ROOM); MOVE(opponent, MOVE_SUNNY_DAY); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_WONDER_ROOM, player);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
+ ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
+ MESSAGE("The harsh sunlight activated Roaring Moon's Protosynthesis!");
+ MESSAGE("Roaring Moon's Sp. Def was heightened!");
+ }
+}
+
SINGLE_BATTLE_TEST("Protosynthesis activates in Sun before Booster Energy")
{
GIVEN {
diff --git a/test/battle/ability/quark_drive.c b/test/battle/ability/quark_drive.c
index b79362d639..ae2aee388a 100644
--- a/test/battle/ability/quark_drive.c
+++ b/test/battle/ability/quark_drive.c
@@ -201,6 +201,23 @@ SINGLE_BATTLE_TEST("Quark Drive prioritizes stats in the case of a tie in the fo
}
}
+SINGLE_BATTLE_TEST("Quark Drive uses Wonder Room swapped defenses when choosing boosted stat")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_WONDER_ROOM) == EFFECT_WONDER_ROOM);
+ PLAYER(SPECIES_IRON_LEAVES) { Ability(ABILITY_QUARK_DRIVE); Attack(50); Defense(200); SpAttack(40); SpDefense(60); Speed(70); Moves(MOVE_WONDER_ROOM); }
+ OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_ELECTRIC_TERRAIN); Speed(60); }
+ } WHEN {
+ TURN { MOVE(player, MOVE_WONDER_ROOM); MOVE(opponent, MOVE_ELECTRIC_TERRAIN); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_WONDER_ROOM, player);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, opponent);
+ ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
+ MESSAGE("The Electric Terrain activated Iron Leaves's Quark Drive!");
+ MESSAGE("Iron Leaves's Sp. Def was heightened!");
+ }
+}
+
SINGLE_BATTLE_TEST("Quark Drive activates in Electric Terrain before Booster Energy")
{
GIVEN {
diff --git a/test/battle/ability/shields_down.c b/test/battle/ability/shields_down.c
index d16aa240da..ca1ade2c37 100644
--- a/test/battle/ability/shields_down.c
+++ b/test/battle/ability/shields_down.c
@@ -75,3 +75,39 @@ SINGLE_BATTLE_TEST("Shields Down protects Minior Meteor from status conditions")
EXPECT(opponent->status1 & STATUS1_BURN);
}
}
+
+WILD_BATTLE_TEST("Wild Minior appear in Meteor form without transforming")// To be replaced with WILD_DOUBLE_BATTLE_TEST when that is made possible.
+{
+ GIVEN {
+ PLAYER(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); }
+ OPPONENT(SPECIES_MINIOR_CORE) { Ability(ABILITY_SHIELDS_DOWN); }
+ } WHEN {
+ TURN {}
+ } SCENE {
+ ABILITY_POPUP(player, ABILITY_SHIELDS_DOWN);
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player);
+ NONE_OF {
+ ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN);
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
+ }
+ } THEN {
+ EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR);
+ EXPECT_EQ(player->species, SPECIES_MINIOR_METEOR);
+ }
+}
+
+SINGLE_BATTLE_TEST("Trainers' Minior appear in Core form")
+{
+ GIVEN {
+ PLAYER(SPECIES_WOBBUFFET)
+ OPPONENT(SPECIES_MINIOR_METEOR) { Ability(ABILITY_SHIELDS_DOWN); }
+ } WHEN {
+ TURN {}
+ } SCENE {
+ ABILITY_POPUP(opponent, ABILITY_SHIELDS_DOWN);
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, opponent);
+ } THEN {
+ EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR);
+ }
+}
+
diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c
index aeb95099d1..4e91eb51c8 100644
--- a/test/battle/gimmick/dynamax.c
+++ b/test/battle/gimmick/dynamax.c
@@ -997,6 +997,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Volt Crash paralyzes both opponents")
TURN { MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); }
} SCENE {
MESSAGE("Pikachu used G-Max Volt Crash!");
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_VOLT_CRASH, playerLeft);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentLeft);
MESSAGE("The opposing Wobbuffet is paralyzed, so it may be unable to move!");
STATUS_ICON(opponentLeft, paralysis: TRUE);
@@ -1309,6 +1310,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Replenish recycles allies' berries 50\% of th
PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH);
GIVEN {
ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_REPLENISH, MOVE_EFFECT_RECYCLE_BERRIES));
+ ASSUME(GetItemHoldEffect(ITEM_APICOT_BERRY) == HOLD_EFFECT_SP_DEFENSE_UP);
PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); }
PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); Ability(ABILITY_THICK_FAT); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); }
@@ -1321,12 +1323,14 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Replenish recycles allies' berries 50\% of th
TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); }
} SCENE {
// turn 1
+
MESSAGE("Using Apicot Berry, the Sp. Def of Snorlax rose!");
MESSAGE("Using Apicot Berry, the Sp. Def of Munchlax rose!");
MESSAGE("Using Apicot Berry, the Sp. Def of the opposing Wobbuffet rose!");
MESSAGE("Using Apicot Berry, the Sp. Def of the opposing Wobbuffet rose!");
// turn 2
MESSAGE("Snorlax used G-Max Replenish!");
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_REPLENISH, playerLeft);
MESSAGE("Snorlax found one Apicot Berry!");
MESSAGE("Munchlax found one Apicot Berry!");
}
@@ -1369,6 +1373,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Finale heals allies by 1/6 of their health")
TURN { MOVE(playerLeft, MOVE_MOONBLAST, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); }
} SCENE {
MESSAGE("Alcremie used G-Max Finale!");
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_FINALE, playerLeft);
HP_BAR(playerLeft, captureDamage: &damage1);
HP_BAR(playerRight, captureDamage: &damage2);
} THEN {
@@ -1713,5 +1718,81 @@ DOUBLE_BATTLE_TEST("Dynamax stat raising moves don't make stat-changing abilitie
}
}
+DOUBLE_BATTLE_TEST("Dynamax: G-Max Finale heals allies by 1/6 of their health, even if it faints the foe")
+{
+ s16 damage1, damage2;
+ GIVEN {
+ ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_FINALE, MOVE_EFFECT_HEAL_TEAM));
+ PLAYER(SPECIES_ALCREMIE) { HP(1); GigantamaxFactor(TRUE); }
+ PLAYER(SPECIES_MILCERY) { HP(1); }
+ OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
+ OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(playerLeft, MOVE_MOONBLAST, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponentLeft, 2); }
+ } SCENE {
+ MESSAGE("Alcremie used G-Max Finale!");
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_FINALE, playerLeft);
+ HP_BAR(playerLeft, captureDamage: &damage1);
+ HP_BAR(playerRight, captureDamage: &damage2);
+ } THEN {
+ EXPECT_MUL_EQ(-damage1, Q_4_12(6), playerLeft->maxHP); // heals based on Dynamax HP. Appears to have a problem with milcery in this case!?
+ }
+}
+
+DOUBLE_BATTLE_TEST("Dynamax: G-Max Replenish recycles allies' berries 50\% of the time, even if it faints the foe")
+{
+ PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH);
+ GIVEN {
+ ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_REPLENISH, MOVE_EFFECT_RECYCLE_BERRIES));
+ ASSUME(GetItemHoldEffect(ITEM_APICOT_BERRY) == HOLD_EFFECT_SP_DEFENSE_UP);
+ PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); }
+ PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); Ability(ABILITY_THICK_FAT); }
+ OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
+ OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(playerLeft, MOVE_STUFF_CHEEKS); \
+ MOVE(playerRight, MOVE_STUFF_CHEEKS); \
+ MOVE(opponentLeft, MOVE_CELEBRATE); \
+ MOVE(opponentRight, MOVE_CELEBRATE); }
+ TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponentLeft, 2);}
+ } SCENE {
+ // turn 1
+ MESSAGE("Using Apicot Berry, the Sp. Def of Snorlax rose!");
+ MESSAGE("Using Apicot Berry, the Sp. Def of Munchlax rose!");
+ // turn 2
+ MESSAGE("Snorlax used G-Max Replenish!");
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_REPLENISH, playerLeft);
+ MESSAGE("Snorlax found one Apicot Berry!");
+ MESSAGE("Munchlax found one Apicot Berry!");
+ }
+}
+
+DOUBLE_BATTLE_TEST("Dynamax: G-Max Volt Crash paralyzes other opponent even if its target faints")
+{
+ GIVEN {
+ ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_VOLT_CRASH, MOVE_EFFECT_PARALYZE_SIDE));
+ PLAYER(SPECIES_PIKACHU) { GigantamaxFactor(TRUE); }
+ PLAYER(SPECIES_PICHU);
+ OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
+ OPPONENT(SPECIES_WYNAUT);
+ OPPONENT(SPECIES_WYNAUT);
+ } WHEN {
+ TURN { MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponentLeft, 2); }
+ } SCENE {
+ MESSAGE("Pikachu used G-Max Volt Crash!");
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_VOLT_CRASH, playerLeft);
+ NONE_OF {
+ ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentLeft);
+ STATUS_ICON(opponentLeft, paralysis: TRUE);
+ }
+ ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentRight);
+ MESSAGE("The opposing Wynaut is paralyzed, so it may be unable to move!");
+ STATUS_ICON(opponentRight, paralysis: TRUE);
+ }
+}
+
TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-lowering Max Moves, without showing a message")
TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-increasing Max Moves, without showing a message")
diff --git a/test/battle/hold_effect/ability_shield.c b/test/battle/hold_effect/ability_shield.c
index 40ea3328d5..5041734b79 100644
--- a/test/battle/hold_effect/ability_shield.c
+++ b/test/battle/hold_effect/ability_shield.c
@@ -35,6 +35,38 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Neutralizing Gas")
}
}
+DOUBLE_BATTLE_TEST("Ability Shield prevents Intimidate from reactivating after Neutralizing Gas ends")
+{
+ GIVEN {
+ PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
+ PLAYER(SPECIES_WYNAUT) { Speed(4); }
+ OPPONENT(SPECIES_KOFFING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); Speed(1); }
+ OPPONENT(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); Item(ITEM_ABILITY_SHIELD); Speed(3); }
+ } WHEN {
+ TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft); }
+ } SCENE {
+ ABILITY_POPUP(opponentLeft, ABILITY_NEUTRALIZING_GAS);
+ MESSAGE("Neutralizing gas filled the area!");
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight);
+ MESSAGE("The opposing Gyarados's Ability is protected by the effects of its Ability Shield!");
+ ABILITY_POPUP(opponentRight, ABILITY_INTIMIDATE);
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
+ HP_BAR(opponentLeft);
+ MESSAGE("The effects of the neutralizing gas wore off!");
+ NONE_OF {
+ ABILITY_POPUP(opponentRight, ABILITY_INTIMIDATE);
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
+ ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
+ }
+ MESSAGE("The opposing Koffing fainted!");
+ } THEN {
+ EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
+ EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
+ }
+}
+
SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker (no message)")
{
enum Item item;
diff --git a/test/battle/hold_effect/eviolite.c b/test/battle/hold_effect/eviolite.c
index 1aa0622e43..5387d50929 100644
--- a/test/battle/hold_effect/eviolite.c
+++ b/test/battle/hold_effect/eviolite.c
@@ -1,4 +1,82 @@
#include "global.h"
#include "test/battle.h"
-TO_DO_BATTLE_TEST("TODO: Write Eviolite (Hold Effect) test titles")
+ASSUMPTIONS
+{
+ ASSUME(gItemsInfo[ITEM_EVIOLITE].holdEffect == HOLD_EFFECT_EVIOLITE);
+}
+
+SINGLE_BATTLE_TEST("Eviolite boosts Defense and Sp. Def for unevolved Pokemon", s16 damage)
+{
+ u16 move;
+ u32 item;
+
+ PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_EVIOLITE; }
+ PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_NONE; }
+ PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_EVIOLITE; }
+ PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_NONE; }
+
+ GIVEN {
+ ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL);
+ ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
+ PLAYER(SPECIES_PIKACHU) { Item(item); }
+ OPPONENT(SPECIES_MAGIKARP) { Moves(MOVE_SCRATCH, MOVE_WATER_GUN); }
+ } WHEN {
+ TURN { MOVE(opponent, move); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, move, opponent);
+ HP_BAR(player, captureDamage: &results[i].damage);
+ } FINALLY {
+ EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
+ EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[3].damage);
+ }
+}
+
+SINGLE_BATTLE_TEST("Eviolite does not boost Defense or Sp. Def for evolved Pokemon", s16 damage)
+{
+ u16 move;
+ u32 item;
+
+ PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_EVIOLITE; }
+ PARAMETRIZE { move = MOVE_SCRATCH; item = ITEM_NONE; }
+ PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_EVIOLITE; }
+ PARAMETRIZE { move = MOVE_WATER_GUN; item = ITEM_NONE; }
+
+ GIVEN {
+ ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL);
+ ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
+ PLAYER(SPECIES_RAICHU) { Item(item); }
+ OPPONENT(SPECIES_MAGIKARP) { Moves(MOVE_SCRATCH, MOVE_WATER_GUN); }
+ } WHEN {
+ TURN { MOVE(opponent, move); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, move, opponent);
+ HP_BAR(player, captureDamage: &results[i].damage);
+ } FINALLY {
+ EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.0), results[1].damage);
+ EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.0), results[3].damage);
+ }
+}
+
+SINGLE_BATTLE_TEST("Eviolite uses original species after Transform", s16 damage)
+{
+ u32 item;
+
+ PARAMETRIZE { item = ITEM_EVIOLITE; }
+ PARAMETRIZE { item = ITEM_NONE; }
+
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_TRANSFORM) == EFFECT_TRANSFORM);
+ PLAYER(SPECIES_PIKACHU) { Item(item); Moves(MOVE_TRANSFORM, MOVE_CELEBRATE); }
+ OPPONENT(SPECIES_GYARADOS) { Moves(MOVE_SCRATCH, MOVE_CELEBRATE); }
+ } WHEN {
+ TURN { MOVE(player, MOVE_TRANSFORM); MOVE(opponent, MOVE_CELEBRATE); }
+ TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SCRATCH); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, player);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
+ HP_BAR(player, captureDamage: &results[i].damage);
+ } FINALLY {
+ EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
+ }
+}
diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c
index c153ddc3a0..ce62705394 100644
--- a/test/battle/move_effect/ally_switch.c
+++ b/test/battle/move_effect/ally_switch.c
@@ -92,24 +92,24 @@ DOUBLE_BATTLE_TEST("Ally Switch does not redirect the target of Snipe Shot")
DOUBLE_BATTLE_TEST("Ally Switch does not redirect moves done by Pokémon with Stalwart and Propeller Tail")
{
+ u16 species;
enum Ability ability;
- PARAMETRIZE { ability = ABILITY_STALWART; }
- PARAMETRIZE { ability = ABILITY_PROPELLER_TAIL; }
- PARAMETRIZE { ability = ABILITY_TELEPATHY; }
+ PARAMETRIZE { species = SPECIES_DURALUDON; ability = ABILITY_STALWART; }
+ PARAMETRIZE { species = SPECIES_ARROKUDA; ability = ABILITY_PROPELLER_TAIL; }
+ PARAMETRIZE { species = SPECIES_RALTS; ability = ABILITY_TELEPATHY; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET); // Wobb is playerLeft, but it'll be Wynaut after Ally Switch
PLAYER(SPECIES_WYNAUT);
- OPPONENT(SPECIES_KADABRA) { Ability(ability); }
+ OPPONENT(species) { Ability(ability); }
OPPONENT(SPECIES_ABRA);
} WHEN {
- TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_SCRATCH, target:playerRight); } // Kadabra targets playerRight Wynaut.
+ TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_SCRATCH, target:playerRight); } // Opponent targets playerRight Wynaut.
} SCENE {
MESSAGE("Wobbuffet used Ally Switch!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft);
MESSAGE("Wobbuffet and Wynaut switched places!");
- MESSAGE("The opposing Kadabra used Scratch!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft);
HP_BAR((ability == ABILITY_STALWART || ability == ABILITY_PROPELLER_TAIL) ? playerLeft : playerRight);
}
@@ -218,6 +218,7 @@ DOUBLE_BATTLE_TEST("Ally Switch increases the Protect-like moves counter (Gen9+)
DOUBLE_BATTLE_TEST("Ally Switch works if ally used two-turn move like Dig")
{
GIVEN {
+ ASSUME(gBattleMoveEffects[GetMoveEffect(MOVE_DIG)].twoTurnEffect);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
@@ -313,9 +314,8 @@ DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is be
DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data")
{
GIVEN {
- ASSUME(GetMoveEffect(MOVE_ALLY_SWITCH) == EFFECT_ALLY_SWITCH);
PLAYER(SPECIES_HOOPA);
- PLAYER(SPECIES_ZOROARK);
+ PLAYER(SPECIES_ZOROARK) {Ability(ABILITY_ILLUSION); }
PLAYER(SPECIES_MAMOSWINE); // the third member here is required for zoroark
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@@ -329,6 +329,7 @@ DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data")
DOUBLE_BATTLE_TEST("Ally switch updates last used moves for Mimic")
{
GIVEN {
+ ASSUME(GetMoveEffect(MOVE_MIMIC) == EFFECT_MIMIC);
PLAYER(SPECIES_XATU) { Speed(100); }
PLAYER(SPECIES_RIOLU) { Speed(150); }
OPPONENT(SPECIES_FEAROW) { Speed(20); }
@@ -348,9 +349,10 @@ DOUBLE_BATTLE_TEST("Ally switch updates last used moves for Mimic")
}
}
-DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed battler")
+DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed position")
{
GIVEN {
+ ASSUME(GetMoveEffect(MOVE_LEECH_SEED) == EFFECT_LEECH_SEED);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_SOLOSIS);
OPPONENT(SPECIES_BULBASAUR) { HP(50); MaxHP(100); }
@@ -379,6 +381,114 @@ DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed battler")
}
}
+DOUBLE_BATTLE_TEST("Ally Switch does not update Future Sight target position")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT);
+ PLAYER(SPECIES_WOBBUFFET);
+ PLAYER(SPECIES_WYNAUT);
+ OPPONENT(SPECIES_ABRA);
+ OPPONENT(SPECIES_RALTS);
+ } WHEN {
+ TURN { MOVE(opponentLeft, MOVE_FUTURE_SIGHT, target: playerLeft); }
+ TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); }
+ TURN { }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponentLeft);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft);
+ MESSAGE("Wynaut took the Future Sight attack!");
+ HP_BAR(playerLeft);
+ NOT HP_BAR(playerRight);
+ }
+}
+
+DOUBLE_BATTLE_TEST("Ally Switch does not update Future Sight target position when attacker side switches")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT);
+ PLAYER(SPECIES_WOBBUFFET);
+ PLAYER(SPECIES_WYNAUT);
+ OPPONENT(SPECIES_ABRA);
+ OPPONENT(SPECIES_RALTS);
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(opponentLeft, MOVE_FUTURE_SIGHT, target: playerLeft); }
+ TURN { SWITCH(opponentLeft, 2); MOVE(opponentRight, MOVE_ALLY_SWITCH); }
+ TURN { }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponentLeft);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight);
+ MESSAGE("Wobbuffet took the Future Sight attack!");
+ HP_BAR(playerLeft);
+ NOT HP_BAR(playerRight);
+ }
+}
+
+DOUBLE_BATTLE_TEST("Ally Switch does not update Wish recovery position")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_WISH) == EFFECT_WISH);
+ PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); }
+ PLAYER(SPECIES_WYNAUT) { HP(20); MaxHP(100); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(playerLeft, MOVE_WISH); }
+ TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_WISH, playerLeft);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft);
+ HP_BAR(playerLeft);
+ NOT HP_BAR(playerRight);
+ } THEN {
+ EXPECT_EQ(playerLeft->hp, 70);
+ EXPECT_EQ(playerRight->hp, 50);
+ }
+}
+
+DOUBLE_BATTLE_TEST("Ally Switch does not update Healing Wish/Lunar Dance recovery position")
+{
+ u16 move = MOVE_NONE;
+ struct BattlePokemon *switchTarget = NULL;
+
+ PARAMETRIZE { move = MOVE_HEALING_WISH; switchTarget = playerLeft; }
+ PARAMETRIZE { move = MOVE_HEALING_WISH; switchTarget = playerRight; }
+ PARAMETRIZE { move = MOVE_LUNAR_DANCE; switchTarget = playerLeft; }
+ PARAMETRIZE { move = MOVE_LUNAR_DANCE; switchTarget = playerRight; }
+
+ GIVEN {
+ WITH_CONFIG(B_HEALING_WISH_SWITCH, GEN_8);
+ ASSUME(GetMoveEffect(MOVE_HEALING_WISH) == EFFECT_HEALING_WISH);
+ ASSUME(GetMoveEffect(MOVE_LUNAR_DANCE) == EFFECT_LUNAR_DANCE);
+ PLAYER(SPECIES_GARDEVOIR);
+ PLAYER(SPECIES_ABRA);
+ PLAYER(SPECIES_WOBBUFFET) { HP(100); MaxHP(100); }
+ PLAYER(SPECIES_WYNAUT) { HP(50); MaxHP(80); Status1(STATUS1_PARALYSIS); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(playerLeft, move); SEND_OUT(playerLeft, 2); }
+ TURN { MOVE(playerRight, MOVE_ALLY_SWITCH); }
+ TURN { SWITCH(switchTarget, 3); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
+ if (switchTarget == playerLeft) {
+ HP_BAR(playerLeft, hp: 80);
+ STATUS_ICON(playerLeft, none: TRUE);
+ } else {
+ NOT HP_BAR(playerRight);
+ }
+ } THEN {
+ if (switchTarget == playerLeft) {
+ EXPECT_EQ(playerLeft->hp, 80);
+ EXPECT_EQ(playerLeft->status1, STATUS1_NONE);
+ } else {
+ EXPECT_EQ(playerRight->hp, 50);
+ EXPECT_EQ(playerRight->status1, STATUS1_PARALYSIS);
+ }
+ }
+}
+
DOUBLE_BATTLE_TEST("Ally Switch updates attract battler")
{
GIVEN {
diff --git a/test/battle/move_effect/assist.c b/test/battle/move_effect/assist.c
index bcf362e266..2414b8da21 100644
--- a/test/battle/move_effect/assist.c
+++ b/test/battle/move_effect/assist.c
@@ -12,7 +12,6 @@ TO_DO_BATTLE_TEST("Assist can call moves with no PP left");
TO_DO_BATTLE_TEST("Assist can call moves from a fainted party member");
TO_DO_BATTLE_TEST("Assist can call moves that are blocked to its partners"); // Eg. double battle parter blocked by Disable
TO_DO_BATTLE_TEST("Assist can only call the original moves of a Transformed partner (Gen4 only)");
-TO_DO_BATTLE_TEST("Assist can only call the current moves of a Transformed partner (Gen5+)");
TO_DO_BATTLE_TEST("Assist cannot call a Mimicked move (Gen4 only)");
TO_DO_BATTLE_TEST("Assist can call a Mimicked move but not the original Mimic (Gen5+)");
TO_DO_BATTLE_TEST("Assist can call moves in unhatched Eggs (Gen5 only)");
@@ -57,3 +56,25 @@ SINGLE_BATTLE_TEST("Assisted move triggers correct weakness berry")
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, player);
}
}
+
+DOUBLE_BATTLE_TEST("Assist can only call the current moves of a Transformed partner (Gen5+)")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_TRANSFORM) == EFFECT_TRANSFORM);
+ PLAYER(SPECIES_WOBBUFFET) { Speed(3); Moves(MOVE_ASSIST); }
+ PLAYER(SPECIES_DITTO) { Speed(4); Moves(MOVE_TRANSFORM); }
+ OPPONENT(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_SCRATCH); }
+ OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
+ } WHEN {
+ TURN {
+ MOVE(playerRight, MOVE_TRANSFORM, target: opponentLeft);
+ MOVE(playerLeft, MOVE_ASSIST);
+ MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight);
+ }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, playerRight);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_ASSIST, playerLeft);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft);
+ }
+}
diff --git a/test/battle/move_effect/psyblade.c b/test/battle/move_effect/psyblade.c
new file mode 100644
index 0000000000..044597ccc5
--- /dev/null
+++ b/test/battle/move_effect/psyblade.c
@@ -0,0 +1,38 @@
+#include "global.h"
+#include "test/battle.h"
+
+ASSUMPTIONS
+{
+ ASSUME(GetMoveEffect(MOVE_PSYBLADE) == EFFECT_TERRAIN_BOOST);
+}
+
+SINGLE_BATTLE_TEST("Psyblade's power increases by 50% on Electric Terrain even if the user is not grounded", s16 damage)
+{
+ bool32 terrain, airBalloon;
+
+ PARAMETRIZE { terrain = FALSE; airBalloon = FALSE; }
+ PARAMETRIZE { terrain = TRUE; airBalloon = FALSE; }
+ PARAMETRIZE { terrain = FALSE; airBalloon = TRUE; }
+ PARAMETRIZE { terrain = TRUE; airBalloon = TRUE; }
+
+ GIVEN {
+ ASSUME(gItemsInfo[ITEM_AIR_BALLOON].holdEffect == HOLD_EFFECT_AIR_BALLOON);
+ ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN);
+ ASSUME(GetMoveTerrainBoost_Terrain(MOVE_PSYBLADE) == STATUS_FIELD_ELECTRIC_TERRAIN);
+ ASSUME(GetMoveTerrainBoost_GroundCheck(MOVE_PSYBLADE) == GROUND_CHECK_NONE);
+ PLAYER(SPECIES_SLOWKING) { Moves(MOVE_ELECTRIC_TERRAIN, MOVE_PSYBLADE); Item(airBalloon ? ITEM_AIR_BALLOON : ITEM_NONE); }
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ if (terrain)
+ TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); }
+ TURN { MOVE(player, MOVE_PSYBLADE); }
+ } SCENE {
+ if (terrain)
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player);
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYBLADE, player);
+ HP_BAR(opponent, captureDamage: &results[i].damage);
+ } FINALLY {
+ EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
+ EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[3].damage);
+ }
+}
diff --git a/test/battle/move_effect/sucker_punch.c b/test/battle/move_effect/sucker_punch.c
index 0fd2273607..039e9541ab 100644
--- a/test/battle/move_effect/sucker_punch.c
+++ b/test/battle/move_effect/sucker_punch.c
@@ -1,6 +1,11 @@
#include "global.h"
#include "test/battle.h"
+ASSUMPTIONS
+{
+ ASSUME(GetMoveEffect(MOVE_SUCKER_PUNCH) == EFFECT_SUCKER_PUNCH);
+}
+
SINGLE_BATTLE_TEST("Sucker Punch hits targets that are about to attack")
{
GIVEN {
@@ -34,6 +39,25 @@ SINGLE_BATTLE_TEST("Sucker Punch doesn't hit targets using status moves")
}
}
+SINGLE_BATTLE_TEST("Sucker Punch hits targets using Me First")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_ME_FIRST) == EFFECT_ME_FIRST);
+ ASSUME(GetMovePriority(MOVE_SUCKER_PUNCH) > GetMovePriority(MOVE_ME_FIRST));
+ PLAYER(SPECIES_WOBBUFFET);
+ OPPONENT(SPECIES_WOBBUFFET);
+ } WHEN {
+ TURN { MOVE(player, MOVE_SUCKER_PUNCH); MOVE(opponent, MOVE_ME_FIRST); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_SUCKER_PUNCH, player);
+ HP_BAR(opponent);
+ NONE_OF {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_ME_FIRST, opponent);
+ HP_BAR(player);
+ }
+ }
+}
+
SINGLE_BATTLE_TEST("Sucker Punch doesn't hit targets that has already moved")
{
GIVEN {
diff --git a/test/battle/move_effect/tickle.c b/test/battle/move_effect/tickle.c
index 3a878868fd..8513340f4b 100644
--- a/test/battle/move_effect/tickle.c
+++ b/test/battle/move_effect/tickle.c
@@ -21,3 +21,20 @@ SINGLE_BATTLE_TEST("Tickle reduces the target's Attack and Defense by 1 stage ea
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
}
}
+
+SINGLE_BATTLE_TEST("Tickle is blocked by Substitute (Gen4+)")
+{
+ GIVEN {
+ PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TICKLE, MOVE_CELEBRATE); Speed(5); }
+ OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); Speed(10); }
+ } WHEN {
+ TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_CELEBRATE); }
+ TURN { MOVE(player, MOVE_TICKLE); MOVE(opponent, MOVE_CELEBRATE); }
+ } SCENE {
+ NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TICKLE, player);
+ MESSAGE("But it failed!");
+ } THEN {
+ EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
+ EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
+ }
+}
diff --git a/test/battle/move_effect/venom_drench.c b/test/battle/move_effect/venom_drench.c
index 00dac65858..aa09061f22 100644
--- a/test/battle/move_effect/venom_drench.c
+++ b/test/battle/move_effect/venom_drench.c
@@ -1,4 +1,42 @@
#include "global.h"
#include "test/battle.h"
-TO_DO_BATTLE_TEST("TODO: Write Venom Drench (Move Effect) test titles")
+ASSUMPTIONS
+{
+ ASSUME(GetMoveEffect(MOVE_VENOM_DRENCH) == EFFECT_VENOM_DRENCH);
+}
+
+SINGLE_BATTLE_TEST("Venom Drench lowers stats of a poisoned target")
+{
+ GIVEN {
+ PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_VENOM_DRENCH); }
+ OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
+ } WHEN {
+ TURN { MOVE(player, MOVE_VENOM_DRENCH); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOM_DRENCH, player);
+ } THEN {
+ EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
+ EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE - 1);
+ EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1);
+ }
+}
+
+SINGLE_BATTLE_TEST("Venom Drench is blocked by Substitute")
+{
+ GIVEN {
+ ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE);
+ PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_VENOM_DRENCH, MOVE_CELEBRATE); }
+ OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SUBSTITUTE, MOVE_CELEBRATE); Status1(STATUS1_POISON); }
+ } WHEN {
+ TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_CELEBRATE); }
+ TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_VENOM_DRENCH); }
+ } SCENE {
+ ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
+ NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOM_DRENCH, player);
+ } THEN {
+ EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
+ EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE);
+ EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
+ }
+}