Merge branch '_RHH/master' into _RHH/upcoming

This commit is contained in:
Eduardo Quezada 2025-01-11 08:07:15 -03:00
commit 8821779815
29 changed files with 417 additions and 83 deletions

View File

@ -29,6 +29,9 @@ endif
ifeq (debug,$(MAKECMDGOALS)) ifeq (debug,$(MAKECMDGOALS))
DEBUG := 1 DEBUG := 1
endif endif
ifeq ($(TESTELF),$(MAKECMDGOALS))
TEST := 1
endif
# Default make rule # Default make rule
all: rom all: rom

View File

@ -385,6 +385,18 @@ EventScript_UseDig::
lockall lockall
goto EventScript_DigCommon goto EventScript_DigCommon
EventScript_CutGrassCommon:
isfollowerfieldmoveuser VAR_0x8004
setfieldeffectargument 3, VAR_0x8004 @ skip pose if true
dofieldeffect FLDEFF_USE_CUT_ON_GRASS
waitstate
@ Use Cut grass from party menu
EventScript_UseCutGrass::
lockall
goto EventScript_CutGrassCommon
Text_CantDive: Text_CantDive:
.string "The sea is deep here. A POKéMON\n" .string "The sea is deep here. A POKéMON\n"
.string "may be able to go underwater.$" .string "may be able to go underwater.$"

View File

@ -42,9 +42,9 @@ A pull request meets the scope criteria if:
4. **Non-SS Items**: Adds Items that have NOT appeared in a Showdown-supported title 4. **Non-SS Items**: Adds Items that have NOT appeared in a Showdown-supported title
5. **Non-SS Gimmicks**: Adds Gimmicks that have NOT appeared in a Showdown-supported title (Showdown's Other Metagames, etc.) 5. **Non-SS Gimmicks**: Adds Gimmicks that have NOT appeared in a Showdown-supported title (Showdown's Other Metagames, etc.)
6. **Non-SS Battle Types**: Adds Special Battle Types that have NOT appeared in a Showdown-supported title 6. **Non-SS Battle Types**: Adds Special Battle Types that have NOT appeared in a Showdown-supported title
7. **Non-SS or SS Overworld Maps**: Adds overworld maps from either Showdown-supported titles or non-Showdown-supported titles 7. **Overworld Maps**: Adds overworld maps from either Showdown-supported titles or non-Showdown-supported titles
7. **Duplicate Feature UI**: Adds functionality that duplicates the core functionality of an existing vanilla feature 8. **Duplicate UIs**: Adds additional user interface that covers the same functionality of an existing feature (HGSS Pokédex, BW Summary Screen, etc.)
8. **Vanilla Link Compatibility**: The ability for Base Expansion Version and Vanilla Emerald Version to connect, trade, and battle one another 9. **Vanilla Link Compatibility**: The ability for Base Expansion Version and Vanilla Emerald Version to connect, trade, and battle one another
## Discussion Required Categories ## Discussion Required Categories

View File

@ -67,7 +67,7 @@ AI will generally behave more recklessly. This AI enables the following behaviou
* Switch offensively mid battle rather than defensively (if using `AI_FLAG_SMART_MON_CHOICES`) * Switch offensively mid battle rather than defensively (if using `AI_FLAG_SMART_MON_CHOICES`)
* Prioritize Explosion moves * Prioritize Explosion moves
## `AI_FLAG_PREFER_STRONGEST_MOVE` ## `AI_FLAG_TRY_TO_2HKO`
Adds score bonus to any move the AI has that either OHKOs or 2HKOs the player. Adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.
Keep in mind that this is a weaker form of `AI_FLAG_TRY_TO_FAINT` at scoring OHKOs as it does not take into account who is attacking first, it does however handle 2HKOs. Keep in mind that this is a weaker form of `AI_FLAG_TRY_TO_FAINT` at scoring OHKOs as it does not take into account who is attacking first, it does however handle 2HKOs.

View File

@ -28,7 +28,7 @@ Let's look at an example:
```c ```c
[MOVE_THUNDER_SHOCK] = [MOVE_THUNDER_SHOCK] =
{ {
.name = HANDLE_EXPANDED_MOVE_NAME("ThunderShock", "Thunder Shock"), .name = COMPOUND_STRING("Thunder Shock"),
.description = COMPOUND_STRING( .description = COMPOUND_STRING(
"An electrical attack that\n" "An electrical attack that\n"
"may paralyze the foe."), "may paralyze the foe."),
@ -51,7 +51,7 @@ Let's look at an example:
.contestComboMoves = {COMBO_STARTER_CHARGE}, .contestComboMoves = {COMBO_STARTER_CHARGE},
}, },
``` ```
The `HANDLE_EXPANDED_MOVE_NAME` allows the usage of a name of extended character length, so long as the `B_EXPANDED_MOVE_NAMES` is set to `TRUE`, whereas by default it's limited in Gen 3 to 12 characters. Most of the fields here are obvious, but the two important ones for determining what a move actually *does* are `effect` and `additionalEffects`. Most of the fields here are obvious, but the two important ones for determining what a move actually *does* are `effect` and `additionalEffects`.
The `effect` represents how the move actually works when called in battle - it can be a two turn move, or a move that only works if the target is holding an item, for example. How each effect works is pretty much unique, but the way a move of a particular effect is executed is defined by a script [`data/battle_scripts_1.s`](#databattle_scripts_1s), and any *variable* characteristics such as typing or power are defined in either [`src/battle_script_commands.c`](#srcbattle_script_commandsc) or [`src/battle_util.c`](#srcbattle_utilc), depending on the effect. The vast majority of non-status moves are simply `EFFECT_HIT`, in that they deal damage and apply `additionalEffects` (if defined). The `effect` represents how the move actually works when called in battle - it can be a two turn move, or a move that only works if the target is holding an item, for example. How each effect works is pretty much unique, but the way a move of a particular effect is executed is defined by a script [`data/battle_scripts_1.s`](#databattle_scripts_1s), and any *variable* characteristics such as typing or power are defined in either [`src/battle_script_commands.c`](#srcbattle_script_commandsc) or [`src/battle_util.c`](#srcbattle_utilc), depending on the effect. The vast majority of non-status moves are simply `EFFECT_HIT`, in that they deal damage and apply `additionalEffects` (if defined).

View File

@ -297,6 +297,7 @@ struct WishFutureKnock
u8 wishPartyId[MAX_BATTLERS_COUNT]; u8 wishPartyId[MAX_BATTLERS_COUNT];
u8 weatherDuration; u8 weatherDuration;
u8 knockedOffMons[NUM_BATTLE_SIDES]; // Each battler is represented by a bit. u8 knockedOffMons[NUM_BATTLE_SIDES]; // Each battler is represented by a bit.
s16 futureSightDmg;
}; };
struct AI_SavedBattleMon struct AI_SavedBattleMon
@ -575,7 +576,6 @@ struct DynamaxData
u8 dynamaxTurns[MAX_BATTLERS_COUNT]; u8 dynamaxTurns[MAX_BATTLERS_COUNT];
u16 baseMoves[MAX_BATTLERS_COUNT]; // base move of Max Move u16 baseMoves[MAX_BATTLERS_COUNT]; // base move of Max Move
u16 lastUsedBaseMove; u16 lastUsedBaseMove;
u16 levelUpHP;
}; };
struct BattleGimmickData struct BattleGimmickData

View File

@ -58,7 +58,7 @@ enum MaxMoveEffect
bool32 CanDynamax(u32 battler); bool32 CanDynamax(u32 battler);
bool32 IsGigantamaxed(u32 battler); bool32 IsGigantamaxed(u32 battler);
void ApplyDynamaxHPMultiplier(u32 battler, struct Pokemon* mon); void ApplyDynamaxHPMultiplier(struct Pokemon* mon);
void ActivateDynamax(u32 battler); void ActivateDynamax(u32 battler);
u16 GetNonDynamaxHP(u32 battler); u16 GetNonDynamaxHP(u32 battler);
u16 GetNonDynamaxMaxHP(u32 battler); u16 GetNonDynamaxMaxHP(u32 battler);

View File

@ -296,7 +296,7 @@ u32 GetBattlerMoveTargetType(u32 battler, u32 move);
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move); bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move);
void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon); void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon);
void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon); void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon);
void RecalcBattlerStats(u32 battler, struct Pokemon *mon); void RecalcBattlerStats(u32 battler, struct Pokemon *mon, bool32 isDynamaxing);
bool32 IsAlly(u32 battlerAtk, u32 battlerDef); bool32 IsAlly(u32 battlerAtk, u32 battlerDef);
bool32 IsGen6ExpShareEnabled(void); bool32 IsGen6ExpShareEnabled(void);
bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect); bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect);

View File

@ -31,7 +31,7 @@
#define AI_FLAG_CHECK_VIABILITY (1 << 2) // AI damaging moves and move effects to determine the best available move in the current situation. #define AI_FLAG_CHECK_VIABILITY (1 << 2) // AI damaging moves and move effects to determine the best available move in the current situation.
#define AI_FLAG_FORCE_SETUP_FIRST_TURN (1 << 3) // AI will prioritize using setup moves on the first turn at the expensve of all else. AI_FLAG_CHECK_VIABILITY will instead do this when the AI determines it makes sense. #define AI_FLAG_FORCE_SETUP_FIRST_TURN (1 << 3) // AI will prioritize using setup moves on the first turn at the expensve of all else. AI_FLAG_CHECK_VIABILITY will instead do this when the AI determines it makes sense.
#define AI_FLAG_RISKY (1 << 4) // AI will generally behave more recklessly, prioritizing damage over accuracy, explosions, etc. #define AI_FLAG_RISKY (1 << 4) // AI will generally behave more recklessly, prioritizing damage over accuracy, explosions, etc.
#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player. #define AI_FLAG_TRY_TO_2HKO (1 << 5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.
#define AI_FLAG_PREFER_BATON_PASS (1 << 6) // AI prefers raising its own stats and setting for / using Baton Pass. #define AI_FLAG_PREFER_BATON_PASS (1 << 6) // AI prefers raising its own stats and setting for / using Baton Pass.
#define AI_FLAG_DOUBLE_BATTLE (1 << 7) // Automatically set for double battles, handles AI behaviour with partner. #define AI_FLAG_DOUBLE_BATTLE (1 << 7) // Automatically set for double battles, handles AI behaviour with partner.
#define AI_FLAG_HP_AWARE (1 << 8) // AI will favour certain move effects based on how much remaining HP it and the player's mon have. #define AI_FLAG_HP_AWARE (1 << 8) // AI will favour certain move effects based on how much remaining HP it and the player's mon have.

View File

@ -406,6 +406,7 @@ extern const u8 EventScript_UseFlash[];
extern const u8 EventScript_UseCut[]; extern const u8 EventScript_UseCut[];
extern const u8 EventScript_UseRockSmash[]; extern const u8 EventScript_UseRockSmash[];
extern const u8 EventScript_UseDig[]; extern const u8 EventScript_UseDig[];
extern const u8 EventScript_UseCutGrass[];
//player pc //player pc
extern const u8 LittlerootTown_BrendansHouse_2F_EventScript_TurnOffPlayerPC[]; extern const u8 LittlerootTown_BrendansHouse_2F_EventScript_TurnOffPlayerPC[];

View File

@ -804,5 +804,6 @@ void HealBoxPokemon(struct BoxPokemon *boxMon);
void UpdateDaysPassedSinceFormChange(u16 days); void UpdateDaysPassedSinceFormChange(u16 days);
void TrySetDayLimitToFormChange(struct Pokemon *mon); void TrySetDayLimitToFormChange(struct Pokemon *mon);
u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler); u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler);
uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier);
#endif // GUARD_POKEMON_H #endif // GUARD_POKEMON_H

View File

@ -48,7 +48,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
@ -66,7 +66,7 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) =
[2] = AI_CheckViability, // AI_FLAG_CHECK_VIABILITY [2] = AI_CheckViability, // AI_FLAG_CHECK_VIABILITY
[3] = AI_ForceSetupFirstTurn, // AI_FLAG_FORCE_SETUP_FIRST_TURN [3] = AI_ForceSetupFirstTurn, // AI_FLAG_FORCE_SETUP_FIRST_TURN
[4] = AI_Risky, // AI_FLAG_RISKY [4] = AI_Risky, // AI_FLAG_RISKY
[5] = AI_PreferStrongestMove, // AI_FLAG_PREFER_STRONGEST_MOVE [5] = AI_TryTo2HKO, // AI_FLAG_TRY_TO_2HKO
[6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS [6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS
[7] = AI_DoubleBattle, // AI_FLAG_DOUBLE_BATTLE [7] = AI_DoubleBattle, // AI_FLAG_DOUBLE_BATTLE
[8] = AI_HPAware, // AI_FLAG_HP_AWARE [8] = AI_HPAware, // AI_FLAG_HP_AWARE
@ -136,7 +136,7 @@ static u32 GetWildAiFlags(void)
if (avgLevel >= 20) if (avgLevel >= 20)
flags |= AI_FLAG_CHECK_VIABILITY; flags |= AI_FLAG_CHECK_VIABILITY;
if (avgLevel >= 60) if (avgLevel >= 60)
flags |= AI_FLAG_PREFER_STRONGEST_MOVE; flags |= AI_FLAG_TRY_TO_2HKO;
if (avgLevel >= 80) if (avgLevel >= 80)
flags |= AI_FLAG_HP_AWARE; flags |= AI_FLAG_HP_AWARE;
@ -4919,7 +4919,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
} }
// Adds score bonus to best powered move // Adds score bonus to best powered move
static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{ {
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
return score; return score;

View File

@ -1410,6 +1410,14 @@ void Task_PlayerController_RestoreBgmAfterCry(u8 taskId)
#define tExpTask_gainedExp_2 data[4] // Stored as two half-words containing a word. #define tExpTask_gainedExp_2 data[4] // Stored as two half-words containing a word.
#define tExpTask_frames data[10] #define tExpTask_frames data[10]
static void DynamaxModifyHPLevelUp(struct Pokemon *mon, u32 battler, u32 oldMaxHP)
{
ApplyDynamaxHPMultiplier(mon);
gBattleScripting.levelUpHP = GetMonData(mon, MON_DATA_MAX_HP) - oldMaxHP; // overwrite levelUpHP since it overflows
gBattleMons[battler].hp += gBattleScripting.levelUpHP;
SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp);
}
static s32 GetTaskExpValue(u8 taskId) static s32 GetTaskExpValue(u8 taskId)
{ {
return (u16)(gTasks[taskId].tExpTask_gainedExp_1) | (gTasks[taskId].tExpTask_gainedExp_2 << 16); return (u16)(gTasks[taskId].tExpTask_gainedExp_1) | (gTasks[taskId].tExpTask_gainedExp_2 << 16);
@ -1428,21 +1436,16 @@ static void Task_GiveExpToMon(u8 taskId)
u8 level = GetMonData(mon, MON_DATA_LEVEL); u8 level = GetMonData(mon, MON_DATA_LEVEL);
u32 currExp = GetMonData(mon, MON_DATA_EXP); u32 currExp = GetMonData(mon, MON_DATA_EXP);
u32 nextLvlExp = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1]; u32 nextLvlExp = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1];
u32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP);
if (currExp + gainedExp >= nextLvlExp) if (currExp + gainedExp >= nextLvlExp)
{ {
SetMonData(mon, MON_DATA_EXP, &nextLvlExp); SetMonData(mon, MON_DATA_EXP, &nextLvlExp);
gBattleStruct->dynamax.levelUpHP = GetMonData(mon, MON_DATA_HP) \
+ UQ_4_12_TO_INT((gBattleScripting.levelUpHP * UQ_4_12(1.5)) + UQ_4_12_ROUND);
CalculateMonStats(mon); CalculateMonStats(mon);
// Reapply Dynamax HP multiplier after stats are recalculated. // Reapply Dynamax HP multiplier after stats are recalculated.
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler]) if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler])
{ DynamaxModifyHPLevelUp(mon, battler, oldMaxHP);
ApplyDynamaxHPMultiplier(battler, mon);
gBattleMons[battler].hp = gBattleStruct->dynamax.levelUpHP;
SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp);
}
gainedExp -= nextLvlExp - currExp; gainedExp -= nextLvlExp - currExp;
BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp); BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp);
@ -1491,6 +1494,7 @@ static void Task_GiveExpWithExpBar(u8 taskId)
{ {
u8 level; u8 level;
u16 species; u16 species;
u32 oldMaxHP;
s32 currExp, expOnNextLvl, newExpPoints; s32 currExp, expOnNextLvl, newExpPoints;
if (gTasks[taskId].tExpTask_frames < 13) if (gTasks[taskId].tExpTask_frames < 13)
@ -1502,31 +1506,27 @@ static void Task_GiveExpWithExpBar(u8 taskId)
u8 monId = gTasks[taskId].tExpTask_monId; u8 monId = gTasks[taskId].tExpTask_monId;
s32 gainedExp = GetTaskExpValue(taskId); s32 gainedExp = GetTaskExpValue(taskId);
u8 battler = gTasks[taskId].tExpTask_battler; u8 battler = gTasks[taskId].tExpTask_battler;
struct Pokemon *mon = &gPlayerParty[monId];
newExpPoints = MoveBattleBar(battler, gHealthboxSpriteIds[battler], EXP_BAR, 0); newExpPoints = MoveBattleBar(battler, gHealthboxSpriteIds[battler], EXP_BAR, 0);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
if (newExpPoints == -1) // The bar has been filled with given exp points. if (newExpPoints == -1) // The bar has been filled with given exp points.
{ {
m4aSongNumStop(SE_EXP); m4aSongNumStop(SE_EXP);
level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL); level = GetMonData(mon, MON_DATA_LEVEL);
currExp = GetMonData(&gPlayerParty[monId], MON_DATA_EXP); currExp = GetMonData(mon, MON_DATA_EXP);
species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); species = GetMonData(mon, MON_DATA_SPECIES);
oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP);
expOnNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1]; expOnNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1];
if (currExp + gainedExp >= expOnNextLvl) if (currExp + gainedExp >= expOnNextLvl)
{ {
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &expOnNextLvl); SetMonData(mon, MON_DATA_EXP, &expOnNextLvl);
gBattleStruct->dynamax.levelUpHP = GetMonData(&gPlayerParty[monId], MON_DATA_HP) \ CalculateMonStats(mon);
+ UQ_4_12_TO_INT((gBattleScripting.levelUpHP * UQ_4_12(1.5)) + UQ_4_12_ROUND);
CalculateMonStats(&gPlayerParty[monId]);
// Reapply Dynamax HP multiplier after stats are recalculated. // Reapply Dynamax HP multiplier after stats are recalculated.
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler]) if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler])
{ DynamaxModifyHPLevelUp(mon, battler, oldMaxHP);
ApplyDynamaxHPMultiplier(battler, &gPlayerParty[monId]);
gBattleMons[battler].hp = gBattleStruct->dynamax.levelUpHP;
SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleMons[battler].hp);
}
gainedExp -= expOnNextLvl - currExp; gainedExp -= expOnNextLvl - currExp;
BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp); BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp);
@ -1535,7 +1535,7 @@ static void Task_GiveExpWithExpBar(u8 taskId)
else else
{ {
currExp += gainedExp; currExp += gainedExp;
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &currExp); SetMonData(mon, MON_DATA_EXP, &currExp);
gBattlerControllerFuncs[battler] = Controller_WaitForString; gBattlerControllerFuncs[battler] = Controller_WaitForString;
DestroyTask(taskId); DestroyTask(taskId);
} }
@ -2042,7 +2042,6 @@ static void PlayerHandleChooseAction(u32 battler)
ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]); PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]);
BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo); BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo);
BreakStringAutomatic(gDisplayedStringBattle, WindowWidthPx(B_WIN_ACTION_PROMPT), 2, FONT_NORMAL);
if (B_SHOW_PARTNER_TARGET && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && IsBattlerAlive(B_POSITION_PLAYER_RIGHT)) if (B_SHOW_PARTNER_TARGET && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && IsBattlerAlive(B_POSITION_PLAYER_RIGHT))
{ {
@ -2236,7 +2235,7 @@ void PlayerHandleExpUpdate(u32 battler)
static void PlayerHandleStatusXor(u32 battler) static void PlayerHandleStatusXor(u32 battler)
{ {
u8 val = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS) ^ gBattleResources->bufferA[battler][1]; u32 val = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS) ^ gBattleResources->bufferA[battler][1];
SetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS, &val); SetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS, &val);
PlayerBufferExecCompleted(battler); PlayerBufferExecCompleted(battler);

View File

@ -299,7 +299,6 @@ static void SafariHandleChooseAction(u32 battler)
ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0); ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo2); BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo2);
BreakStringAutomatic(gDisplayedStringBattle, WindowWidthPx(B_WIN_ACTION_PROMPT), 2, FONT_NORMAL);
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_ACTION_PROMPT); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_ACTION_PROMPT);
} }

View File

@ -220,7 +220,7 @@ enum
LIST_AI_CHECK_VIABILITY, LIST_AI_CHECK_VIABILITY,
LIST_AI_SETUP_FIRST_TURN, LIST_AI_SETUP_FIRST_TURN,
LIST_AI_RISKY, LIST_AI_RISKY,
LIST_AI_PREFER_STRONGEST_MOVE, LIST_AI_TRY_TO_2HKO,
LIST_AI_PREFER_BATON_PASS, LIST_AI_PREFER_BATON_PASS,
LIST_AI_DOUBLE_BATTLE, LIST_AI_DOUBLE_BATTLE,
LIST_AI_HP_AWARE, LIST_AI_HP_AWARE,
@ -385,7 +385,7 @@ static const u8 sText_TryToFaint[] = _("Try to Faint");
static const u8 sText_CheckViability[] = _("Check Viability"); static const u8 sText_CheckViability[] = _("Check Viability");
static const u8 sText_SetUpFirstTurn[] = _("Setup First Turn"); static const u8 sText_SetUpFirstTurn[] = _("Setup First Turn");
static const u8 sText_Risky[] = _("Risky"); static const u8 sText_Risky[] = _("Risky");
static const u8 sText_PreferStrongestMove[] = _("Prefer Strongest Move"); static const u8 sText_TryTo2HKO[] = _("Try to 2HKO");
static const u8 sText_PreferBatonPass[] = _("Prefer Baton Pass"); static const u8 sText_PreferBatonPass[] = _("Prefer Baton Pass");
static const u8 sText_DoubleBattle[] = _("Double Battle"); static const u8 sText_DoubleBattle[] = _("Double Battle");
static const u8 sText_HpAware[] = _("HP Aware"); static const u8 sText_HpAware[] = _("HP Aware");
@ -628,7 +628,7 @@ static const struct ListMenuItem sAIListItems[] =
{sText_CheckViability, LIST_AI_CHECK_VIABILITY}, {sText_CheckViability, LIST_AI_CHECK_VIABILITY},
{sText_SetUpFirstTurn, LIST_AI_SETUP_FIRST_TURN}, {sText_SetUpFirstTurn, LIST_AI_SETUP_FIRST_TURN},
{sText_Risky, LIST_AI_RISKY}, {sText_Risky, LIST_AI_RISKY},
{sText_PreferStrongestMove, LIST_AI_PREFER_STRONGEST_MOVE}, {sText_TryTo2HKO, LIST_AI_TRY_TO_2HKO},
{sText_PreferBatonPass, LIST_AI_PREFER_BATON_PASS}, {sText_PreferBatonPass, LIST_AI_PREFER_BATON_PASS},
{sText_DoubleBattle, LIST_AI_DOUBLE_BATTLE}, {sText_DoubleBattle, LIST_AI_DOUBLE_BATTLE},
{sText_HpAware, LIST_AI_HP_AWARE}, {sText_HpAware, LIST_AI_HP_AWARE},

View File

@ -123,22 +123,22 @@ bool32 CanDynamax(u32 battler)
// Returns whether a battler is transformed into a Gigantamax form. // Returns whether a battler is transformed into a Gigantamax form.
bool32 IsGigantamaxed(u32 battler) bool32 IsGigantamaxed(u32 battler)
{ {
struct Pokemon *mon = &GetSideParty(GetBattlerSide(battler))[gBattlerPartyIndexes[battler]]; struct Pokemon *mon = GetPartyBattlerData(battler);
if ((gSpeciesInfo[gBattleMons[battler].species].isGigantamax) && GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR)) if ((gSpeciesInfo[gBattleMons[battler].species].isGigantamax) && GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR))
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
// Applies the HP Multiplier for Dynamaxed Pokemon and Raid Bosses. // Applies the HP Multiplier for Dynamaxed Pokemon and Raid Bosses.
void ApplyDynamaxHPMultiplier(u32 battler, struct Pokemon* mon) void ApplyDynamaxHPMultiplier(struct Pokemon* mon)
{ {
if (GetMonData(mon, MON_DATA_SPECIES) == SPECIES_SHEDINJA) if (GetMonData(mon, MON_DATA_SPECIES) == SPECIES_SHEDINJA)
return; return;
else else
{ {
u32 scale = 150 + 5 * GetMonData(mon, MON_DATA_DYNAMAX_LEVEL); uq4_12_t multiplier = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), FALSE);
u32 hp = (GetMonData(mon, MON_DATA_HP) * scale + 99) / 100; u32 hp = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_HP) * multiplier) + UQ_4_12_ROUND);
u32 maxHP = (GetMonData(mon, MON_DATA_MAX_HP) * scale + 99) / 100; u32 maxHP = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_MAX_HP) * multiplier) + UQ_4_12_ROUND);
SetMonData(mon, MON_DATA_HP, &hp); SetMonData(mon, MON_DATA_HP, &hp);
SetMonData(mon, MON_DATA_MAX_HP, &maxHP); SetMonData(mon, MON_DATA_MAX_HP, &maxHP);
} }
@ -151,8 +151,9 @@ u16 GetNonDynamaxHP(u32 battler)
return gBattleMons[battler].hp; return gBattleMons[battler].hp;
else else
{ {
u16 mult = UQ_4_12_FLOORED(1.0/1.5); // placeholder struct Pokemon *mon = GetPartyBattlerData(battler);
u16 hp = UQ_4_12_TO_INT((gBattleMons[battler].hp * mult) + UQ_4_12_ROUND); uq4_12_t mult = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), TRUE);
u32 hp = UQ_4_12_TO_INT((gBattleMons[battler].hp * mult) + UQ_4_12_ROUND);
return hp; return hp;
} }
} }
@ -164,8 +165,9 @@ u16 GetNonDynamaxMaxHP(u32 battler)
return gBattleMons[battler].maxHP; return gBattleMons[battler].maxHP;
else else
{ {
u16 mult = UQ_4_12_FLOORED(1.0/1.5); // placeholder struct Pokemon *mon = GetPartyBattlerData(battler);
u16 maxHP = UQ_4_12_TO_INT((gBattleMons[battler].maxHP * mult) + UQ_4_12_ROUND); uq4_12_t mult = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), TRUE);
u32 maxHP = UQ_4_12_TO_INT((gBattleMons[battler].maxHP * mult) + UQ_4_12_ROUND);
return maxHP; return maxHP;
} }
} }
@ -202,7 +204,7 @@ void UndoDynamax(u32 battler)
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX) if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX)
{ {
struct Pokemon *mon = (side == B_SIDE_PLAYER) ? &gPlayerParty[monId] : &gEnemyParty[monId]; struct Pokemon *mon = (side == B_SIDE_PLAYER) ? &gPlayerParty[monId] : &gEnemyParty[monId];
u16 mult = UQ_4_12_FLOORED(1.0/1.5); // placeholder uq4_12_t mult = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), TRUE);
gBattleMons[battler].hp = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_HP) * mult + 1) + UQ_4_12_ROUND); // round up gBattleMons[battler].hp = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_HP) * mult + 1) + UQ_4_12_ROUND); // round up
SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp); SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp);
CalculateMonStats(mon); CalculateMonStats(mon);
@ -510,10 +512,10 @@ void BS_UpdateDynamax(void)
{ {
NATIVE_ARGS(); NATIVE_ARGS();
u32 battler = gBattleScripting.battler; u32 battler = gBattleScripting.battler;
struct Pokemon *mon = &GetSideParty(GetBattlerSide(battler))[gBattlerPartyIndexes[battler]]; struct Pokemon *mon = GetPartyBattlerData(battler);
if (!IsGigantamaxed(battler)) // RecalcBattlerStats will get called on form change. if (!IsGigantamaxed(battler)) // RecalcBattlerStats will get called on form change.
RecalcBattlerStats(battler, mon); RecalcBattlerStats(battler, mon, GetActiveGimmick(battler) == GIMMICK_DYNAMAX);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL); UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL);
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;

View File

@ -1399,8 +1399,8 @@ const u8 gText_PkmnIsEvolving[] = _("What?\n{STR_VAR_1} is evolving!");
const u8 gText_CongratsPkmnEvolved[] = _("Congratulations! Your {STR_VAR_1}\nevolved into {STR_VAR_2}!{WAIT_SE}\p"); const u8 gText_CongratsPkmnEvolved[] = _("Congratulations! Your {STR_VAR_1}\nevolved into {STR_VAR_2}!{WAIT_SE}\p");
const u8 gText_PkmnStoppedEvolving[] = _("Huh? {STR_VAR_1}\nstopped evolving!\p"); const u8 gText_PkmnStoppedEvolving[] = _("Huh? {STR_VAR_1}\nstopped evolving!\p");
const u8 gText_EllipsisQuestionMark[] = _("……?\p"); const u8 gText_EllipsisQuestionMark[] = _("……?\p");
const u8 gText_WhatWillPkmnDo[] = _("What will {B_BUFF1} do?"); const u8 gText_WhatWillPkmnDo[] = _("What will\n{B_BUFF1} do?");
const u8 gText_WhatWillPkmnDo2[] = _("What will {B_PLAYER_NAME} do?"); const u8 gText_WhatWillPkmnDo2[] = _("What will\n{B_PLAYER_NAME} do?");
const u8 gText_WhatWillWallyDo[] = _("What will\nWALLY do?"); const u8 gText_WhatWillWallyDo[] = _("What will\nWALLY do?");
const u8 gText_LinkStandby[] = _("{PAUSE 16}Link standby…"); const u8 gText_LinkStandby[] = _("{PAUSE 16}Link standby…");
const u8 gText_BattleMenu[] = _("Battle{CLEAR_TO 56}Bag\nPokémon{CLEAR_TO 56}Run"); const u8 gText_BattleMenu[] = _("Battle{CLEAR_TO 56}Bag\nPokémon{CLEAR_TO 56}Run");

View File

@ -2647,6 +2647,9 @@ static void Cmd_datahpupdate(void)
u32 effect = GetMoveEffect(gCurrentMove); u32 effect = GetMoveEffect(gCurrentMove);
// Record damage for foreseen moves
gWishFutureKnock.futureSightDmg = gBattleStruct->moveDamage[battler];
// Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are
// used in combination as general damage trackers for other purposes. specialDmg is additionally used // used in combination as general damage trackers for other purposes. specialDmg is additionally used
// to help determine if a fire move should defrost the target. // to help determine if a fire move should defrost the target.
@ -6701,18 +6704,22 @@ static void Cmd_moveend(void)
gLastUsedItem = gBattleMons[battler].item; gLastUsedItem = gBattleMons[battler].item;
if (moveEffect == EFFECT_HIT_ESCAPE) if (moveEffect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
effect = TRUE;
BattleScriptPushCursor();
gBattleStruct->battlerState[battler].usedEjectItem = TRUE;
if (ejectButtonBattlers & (1u << battler)) if (ejectButtonBattlers & (1u << battler))
{ {
effect = TRUE;
gBattleStruct->battlerState[battler].usedEjectItem = TRUE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; gBattlescriptCurrInstr = BattleScript_EjectButtonActivates;
AI_DATA->ejectButtonSwitch = TRUE; AI_DATA->ejectButtonSwitch = TRUE;
} }
else // Eject Pack else // Eject Pack
{ {
if (!(gBattleResources->flags->flags[gBattlerTarget] & RESOURCE_FLAG_EMERGENCY_EXIT)) if (!(gBattleResources->flags->flags[gBattlerTarget] & RESOURCE_FLAG_EMERGENCY_EXIT)
&& !(gMovesInfo[gCurrentMove].effect == EFFECT_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker)))
{ {
effect = TRUE;
gBattleStruct->battlerState[battler].usedEjectItem = TRUE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_EjectPackActivates; gBattlescriptCurrInstr = BattleScript_EjectPackActivates;
AI_DATA->ejectPackSwitch = TRUE; AI_DATA->ejectPackSwitch = TRUE;
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE; gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE;
@ -10446,7 +10453,7 @@ static void Cmd_various(void)
// Change stats. // Change stats.
else if (cmd->case_ == 1) else if (cmd->case_ == 1)
{ {
RecalcBattlerStats(battler, mon); RecalcBattlerStats(battler, mon, FALSE);
} }
// Update healthbox. // Update healthbox.
else else
@ -14233,6 +14240,7 @@ static void Cmd_trysetfutureattack(void)
gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker; gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker;
gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker]; gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker];
gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3; gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3;
gWishFutureKnock.futureSightDmg = 0;
if (gCurrentMove == MOVE_DOOM_DESIRE) if (gCurrentMove == MOVE_DOOM_DESIRE)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE;

View File

@ -1569,7 +1569,7 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32
{ {
u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball; u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball;
u16 move; u16 move;
u32 personality, ability, friendship, j; u32 personality = 0, ability, friendship, j;
if (fmon->gender == TRAINER_MON_MALE) if (fmon->gender == TRAINER_MON_MALE)
{ {

View File

@ -5887,10 +5887,27 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& !IsBattlerAlive(gBattlerTarget) && !IsBattlerAlive(gBattlerTarget)
&& IsBattlerAlive(gBattlerAttacker)) && IsBattlerAlive(gBattlerAttacker))
{ {
gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget]; //special Future Sight handling
BattleScriptPushCursor(); if (gMovesInfo[gWishFutureKnock.futureSightMove[battler]].effect == EFFECT_FUTURE_SIGHT)
gBattlescriptCurrInstr = BattleScript_AftermathDmg; {
effect++; //no Innards Out effect if Future Sight user is currently not on field
if (gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] == gBattlerPartyIndexes[gBattlerAttacker]
|| gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] == BATTLE_PARTNER(gBattlerPartyIndexes[gBattlerAttacker]))
{
gBattleStruct->moveDamage[gBattlerAttacker] = gWishFutureKnock.futureSightDmg;
gWishFutureKnock.futureSightDmg = 0;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AftermathDmg;
effect++;
}
}
else
{
gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget];
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AftermathDmg;
effect++;
}
} }
break; break;
case ABILITY_EFFECT_SPORE: case ABILITY_EFFECT_SPORE:
@ -11188,7 +11205,7 @@ bool32 TryBattleFormChange(u32 battler, u32 method)
TryToSetBattleFormChangeMoves(&party[monId], method); TryToSetBattleFormChangeMoves(&party[monId], method);
SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies); SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies);
gBattleMons[battler].species = targetSpecies; gBattleMons[battler].species = targetSpecies;
RecalcBattlerStats(battler, &party[monId]); RecalcBattlerStats(battler, &party[monId], method == FORM_CHANGE_BATTLE_GIGANTAMAX);
return TRUE; return TRUE;
} }
else if (gBattleStruct->changedSpecies[side][monId] != SPECIES_NONE) else if (gBattleStruct->changedSpecies[side][monId] != SPECIES_NONE)
@ -11213,7 +11230,7 @@ bool32 TryBattleFormChange(u32 battler, u32 method)
// Reverts the original species // Reverts the original species
TryToSetBattleFormChangeMoves(&party[monId], method); TryToSetBattleFormChangeMoves(&party[monId], method);
SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[side][monId]); SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[side][monId]);
RecalcBattlerStats(battler, &party[monId]); RecalcBattlerStats(battler, &party[monId], method == FORM_CHANGE_BATTLE_GIGANTAMAX);
// Battler data is not updated with regular form's ability, not doing so could cause wrong ability activation. // Battler data is not updated with regular form's ability, not doing so could cause wrong ability activation.
if (method == FORM_CHANGE_FAINT) if (method == FORM_CHANGE_FAINT)
gBattleMons[battler].ability = abilityForm; gBattleMons[battler].ability = abilityForm;
@ -11803,11 +11820,28 @@ void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon)
gBattleMons[battler].types[2] = TYPE_MYSTERY; gBattleMons[battler].types[2] = TYPE_MYSTERY;
} }
void RecalcBattlerStats(u32 battler, struct Pokemon *mon) void RecalcBattlerStats(u32 battler, struct Pokemon *mon, bool32 isDynamaxing)
{ {
u32 hp = GetMonData(mon, MON_DATA_HP);
u32 oldMaxHp = GetMonData(mon, MON_DATA_MAX_HP);
CalculateMonStats(mon); CalculateMonStats(mon);
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gChosenActionByBattler[battler] != B_ACTION_SWITCH) if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gChosenActionByBattler[battler] != B_ACTION_SWITCH)
ApplyDynamaxHPMultiplier(battler, mon); {
ApplyDynamaxHPMultiplier(mon);
u32 newMaxHp = GetMonData(mon, MON_DATA_MAX_HP);
if (!isDynamaxing)
{
if (newMaxHp > oldMaxHp) // restore hp gained from changing form, without this, dynamaxed form changes are calculated incorrectly
{
hp += (newMaxHp - oldMaxHp);
SetMonData(mon, MON_DATA_HP, &hp);
}
else
{
SetMonData(mon, MON_DATA_HP, &hp);
}
}
}
CopyMonLevelAndBaseStatsToBattleMon(battler, mon); CopyMonLevelAndBaseStatsToBattleMon(battler, mon);
CopyMonAbilityAndTypesToBattleMon(battler, mon); CopyMonAbilityAndTypesToBattleMon(battler, mon);
} }

View File

@ -1654,6 +1654,24 @@ const struct BerryCrushBerryData gBerryCrush_BerryData[] = {
[ITEM_WATMEL_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250}, [ITEM_WATMEL_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250},
[ITEM_DURIN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250}, [ITEM_DURIN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250},
[ITEM_BELUE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250}, [ITEM_BELUE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250},
[ITEM_CHILAN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 80, .powder = 70},
[ITEM_OCCA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 100, .powder = 100},
[ITEM_PASSHO_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 60, .powder = 30},
[ITEM_WACAN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_RINDO_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_YACHE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_CHOPLE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_KEBIA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_SHUCA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 20},
[ITEM_COBA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_PAYAPA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_TANGA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_CHARTI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_KASIB_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_HABAN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30},
[ITEM_COLBUR_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 60, .powder = 50},
[ITEM_BABIRI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 80, .powder = 50},
[ITEM_ROSELI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 60, .powder = 50},
[ITEM_LIECHI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, [ITEM_LIECHI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500},
[ITEM_GANLON_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, [ITEM_GANLON_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500},
[ITEM_SALAC_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, [ITEM_SALAC_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500},
@ -1661,6 +1679,13 @@ const struct BerryCrushBerryData gBerryCrush_BerryData[] = {
[ITEM_APICOT_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, [ITEM_APICOT_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500},
[ITEM_LANSAT_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750}, [ITEM_LANSAT_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750},
[ITEM_STARF_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750}, [ITEM_STARF_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750},
[ITEM_ENIGMA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 150, .powder = 200},
[ITEM_MICLE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 130, .powder = 250},
[ITEM_CUSTAP_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750},
[ITEM_JABOCA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 130, .powder = 250},
[ITEM_ROWAP_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 130, .powder = 250},
[ITEM_KEE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 500},
[ITEM_MARANGA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 500},
[ITEM_ENIGMA_BERRY_E_READER - FIRST_BERRY_INDEX] = {.difficulty = 150, .powder = 200} [ITEM_ENIGMA_BERRY_E_READER - FIRST_BERRY_INDEX] = {.difficulty = 150, .powder = 200}
}; };

View File

@ -277,8 +277,8 @@ bool8 SetUpFieldMove_Cut(void)
static void FieldCallback_CutGrass(void) static void FieldCallback_CutGrass(void)
{ {
FieldEffectStart(FLDEFF_USE_CUT_ON_GRASS);
gFieldEffectArguments[0] = GetCursorSelectionMonId(); gFieldEffectArguments[0] = GetCursorSelectionMonId();
ScriptContext_SetupScript(EventScript_UseCutGrass);
} }
bool8 FldEff_UseCutOnGrass(void) bool8 FldEff_UseCutOnGrass(void)

View File

@ -1007,7 +1007,6 @@ void MoveRelearnerShowHideCategoryIcon(s32 moveId)
DestroySprite(&gSprites[sMoveRelearnerStruct->categoryIconSpriteId]); DestroySprite(&gSprites[sMoveRelearnerStruct->categoryIconSpriteId]);
sMoveRelearnerStruct->categoryIconSpriteId = 0xFF; sMoveRelearnerStruct->categoryIconSpriteId = 0xFF;
gSprites[sMoveRelearnerStruct->categoryIconSpriteId].invisible = TRUE;
} }
else else
{ {

View File

@ -7000,3 +7000,10 @@ u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler)
return moveType; return moveType;
return GetMoveType(move); return GetMoveType(move);
} }
uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier)
{
if (inverseMultiplier)
return UQ_4_12(1.0/(1.5 + 0.05 * dynamaxLevel));
return UQ_4_12(1.5 + 0.05 * dynamaxLevel);
}

View File

@ -65,3 +65,66 @@ SINGLE_BATTLE_TEST("Innards Out does not damage Magic Guard Pokemon")
NOT HP_BAR(opponent); NOT HP_BAR(opponent);
} }
} }
SINGLE_BATTLE_TEST("Innards Out uses correct damage amount for Future Sight")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT);
PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); }
TURN { }
TURN { SEND_OUT(player, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent);
MESSAGE("Pyukumuku took the Future Sight attack!");
HP_BAR(player);
ABILITY_POPUP(player, ABILITY_INNARDS_OUT);
HP_BAR(opponent, damage: 1);
}
}
SINGLE_BATTLE_TEST("Innards Out doesn't trigger if Future Sight user is not on field")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT);
PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); }
TURN { SWITCH(opponent, 1); }
TURN { SEND_OUT(player, 1); } //SEND_OUT(opponent, 0); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent);
MESSAGE("Pyukumuku took the Future Sight attack!");
HP_BAR(player);
NONE_OF {
ABILITY_POPUP(player, ABILITY_INNARDS_OUT);
HP_BAR(opponent);
}
}
}
SINGLE_BATTLE_TEST("Innards Out triggers if Future Sight user is back on the field")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT);
PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); }
TURN { SWITCH(opponent, 1); }
TURN { SWITCH(opponent, 0); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent);
MESSAGE("Pyukumuku took the Future Sight attack!");
HP_BAR(player);
ABILITY_POPUP(player, ABILITY_INNARDS_OUT);
HP_BAR(opponent);
}
}

View File

@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x", u16 hp)
u32 dynamax; u32 dynamax;
PARAMETRIZE { dynamax = GIMMICK_NONE; } PARAMETRIZE { dynamax = GIMMICK_NONE; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; }
GIVEN { // TODO: Dynamax level GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);
} WHEN { } WHEN {
@ -25,6 +25,49 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x", u16 hp)
} }
} }
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax Level increases HP and max HP multipliers by 0.05 for each level", u16 hp)
{
u32 dynamax, level;
PARAMETRIZE { dynamax = GIMMICK_NONE; level = 0; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 0; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 1; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 2; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 3; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 4; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 5; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 6; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 7; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 8; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 9; }
PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 10; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { DynamaxLevel(level); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, gimmick: dynamax); MOVE(opponent, MOVE_CELEBRATE); }
} SCENE {
if (dynamax) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player);
MESSAGE("Wobbuffet used Max Strike!");
}
MESSAGE("The opposing Wobbuffet used Celebrate!");
} THEN {
results[i].hp = player->hp;
} FINALLY {
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.5), results[1].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.55), results[2].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.6), results[3].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.65), results[4].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.7), results[5].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.75), results[6].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.8), results[7].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.85), results[8].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.9), results[9].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.95), results[10].hp);
EXPECT_MUL_EQ(results[0].hp, Q_4_12(2.0), results[11].hp);
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp) SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp)
{ {
u32 dynamax; u32 dynamax;
@ -38,8 +81,8 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp)
TURN { MOVE(player, MOVE_TACKLE); } // 2nd max move TURN { MOVE(player, MOVE_TACKLE); } // 2nd max move
TURN { MOVE(player, MOVE_TACKLE); } // 3rd max move TURN { MOVE(player, MOVE_TACKLE); } // 3rd max move
} SCENE { } SCENE {
int i; int j;
for (i = 0; i < DYNAMAX_TURNS_COUNT; ++i) { for (j = 0; j < DYNAMAX_TURNS_COUNT; ++j) {
if (dynamax) if (dynamax)
MESSAGE("Wobbuffet used Max Strike!"); MESSAGE("Wobbuffet used Max Strike!");
else else
@ -55,6 +98,49 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp)
} }
} }
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns and correctly converts HP according to Dynamax Level")
{
u32 dynamaxLevel, dynamax;
u16 capturedHP, finalHP;
s16 capturedDamage;
PARAMETRIZE { dynamaxLevel = 0; dynamax = GIMMICK_NONE; }
PARAMETRIZE { dynamaxLevel = 0; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 1; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 2; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 3; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 4; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 5; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 6; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 7; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 8; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 9; dynamax = GIMMICK_DYNAMAX; }
PARAMETRIZE { dynamaxLevel = 10; dynamax = GIMMICK_DYNAMAX; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { DynamaxLevel(dynamaxLevel); HP(200); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CELEBRATE, gimmick: dynamax); }
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE); }
TURN { }
} SCENE {
if (dynamax)
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
if (dynamax)
HP_BAR(player, captureHP: &capturedHP);
else
HP_BAR(player, captureDamage: &capturedDamage);
if (dynamax)
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player);
} THEN {
finalHP = player->hp;
if (dynamax)
EXPECT_MUL_EQ(finalHP, GetDynamaxLevelHPMultiplier(dynamaxLevel, FALSE), capturedHP);
EXPECT_LE(finalHP, 200);
EXPECT_GE(finalHP, 200 - capturedDamage);
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be flinched") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be flinched")
{ {
GIVEN { GIVEN {
@ -311,6 +397,47 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon lose their substitutes")
} }
} }
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon that changes forms does not gain HP")
{
u16 capturedHP, finalHP;
GIVEN {
PLAYER(SPECIES_GRENINJA_BATTLE_BOND) { Ability(ABILITY_BATTLE_BOND); HP(100); Speed(100); }
OPPONENT(SPECIES_CATERPIE) { HP(1); Speed(1000); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(10); }
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponent, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
HP_BAR(player, captureHP: &capturedHP);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAX_STRIKE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player);
} THEN {
finalHP = player->hp;
EXPECT_EQ(capturedHP, finalHP);
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon that changes forms does not gain HP unless the new form gains Max HP")
{
u32 hp = 1, maxHP = 200;
u32 species;
PARAMETRIZE { species = SPECIES_ZYGARDE_10_POWER_CONSTRUCT; }
PARAMETRIZE { species = SPECIES_ZYGARDE_50_POWER_CONSTRUCT; }
GIVEN {
PLAYER(species) { Ability(ABILITY_POWER_CONSTRUCT); HP(hp); MaxHP(maxHP); DynamaxLevel(0); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MAX_STRIKE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player);
} THEN {
EXPECT_MUL_EQ(maxHP - hp, GetDynamaxLevelHPMultiplier(0, FALSE), player->maxHP - player->hp);
}
}
SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves deal 1/4 damage through protect", s16 damage) SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves deal 1/4 damage through protect", s16 damage)
{ {
bool32 protected; bool32 protected;

View File

@ -102,3 +102,22 @@ SINGLE_BATTLE_TEST("Eject Pack activates once intimidate mon switches in")
MESSAGE("Wobbuffet is switched out with the Eject Pack!"); MESSAGE("Wobbuffet is switched out with the Eject Pack!");
} }
} }
SINGLE_BATTLE_TEST("Eject Pack will not activate if Parting Shot user can switch out")
{
ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK);
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_PARTING_SHOT); SEND_OUT(opponent, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, opponent);
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Wobbuffet is switched out with the Eject Pack!");
}
}
}

View File

@ -116,6 +116,41 @@ SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original
} }
} }
SINGLE_BATTLE_TEST("Shell Bell restores 1/8 HP of damage dealt")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Level(16); Item(ITEM_SHELL_BELL); HP(10); }
OPPONENT(SPECIES_WOBBUFFET) { Level(16); };
} WHEN {
TURN { MOVE(player, MOVE_SEISMIC_TOSS); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, player);
HP_BAR(opponent);
HP_BAR(player, damage: -2);
}
}
SINGLE_BATTLE_TEST("Shell Bell doesn't restore HP for damage dealt by a foreseen move")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT);
PLAYER(SPECIES_WOBBUFFET) { Level(16); Item(ITEM_SHELL_BELL); HP(10); }
OPPONENT(SPECIES_WOBBUFFET) { Level(16); };
} WHEN {
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
TURN { }
TURN { }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
MESSAGE("The opposing Wobbuffet took the Future Sight attack!");
HP_BAR(opponent);
NONE_OF {
HP_BAR(player);
}
}
}
SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is not on the field") SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is not on the field")
{ {
GIVEN { GIVEN {

View File

@ -6,7 +6,7 @@ ASSUMPTIONS
ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE);
} }
SINGLE_BATTLE_TEST("U-turn switches the user out") SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("U-turn switches the user out")
} }
} }
SINGLE_BATTLE_TEST("U-turn does not switch the user out if the battle ends") SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if the battle ends")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if the battle ends")
} }
} }
SINGLE_BATTLE_TEST("U-turn does not switch the user out if no replacements") SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if no replacements")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
@ -48,7 +48,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if no replacements")
} }
} }
SINGLE_BATTLE_TEST("U-turn does not switch the user out if replacements fainted") SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if replacements fainted")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
@ -62,7 +62,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if replacements fainted"
} }
} }
SINGLE_BATTLE_TEST("U-turn does not switch the user out if Wimp Out activates") SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if Wimp Out activates")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
@ -79,7 +79,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if Wimp Out activates")
} }
} }
SINGLE_BATTLE_TEST("U-turn switches the user out if Wimp Out fails to activate") SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out if Wimp Out fails to activate")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
@ -95,7 +95,7 @@ SINGLE_BATTLE_TEST("U-turn switches the user out if Wimp Out fails to activate")
} }
} }
SINGLE_BATTLE_TEST("U-turn switches the user out after Ice Face activates") SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out after Ice Face activates")
{ {
GIVEN { GIVEN {
ASSUME(GetMoveCategory(MOVE_U_TURN) == DAMAGE_CATEGORY_PHYSICAL); ASSUME(GetMoveCategory(MOVE_U_TURN) == DAMAGE_CATEGORY_PHYSICAL);
@ -113,7 +113,7 @@ SINGLE_BATTLE_TEST("U-turn switches the user out after Ice Face activates")
} }
} }
SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: player side") SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: player side")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
@ -136,7 +136,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
} }
} }
SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side") SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
@ -159,7 +159,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in
} }
} }
SINGLE_BATTLE_TEST("Electric Seed boost is received by the right pokemon after U-turn and Intimidate") SINGLE_BATTLE_TEST("Hit Escape: Electric Seed boost is received by the right pokemon after U-turn and Intimidate")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };