25-03-25 master to upcoming merge
This commit is contained in:
commit
ae640f0714
@ -16762,6 +16762,7 @@ gBattleAnimMove_JetPunch::
|
||||
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 2, 0, 9, RGB_BLUE
|
||||
delay 8
|
||||
createvisualtask AnimTask_ExtremeSpeedMonReappear, 2
|
||||
setarg 0x7, 0x1000
|
||||
createsprite gSmallBubblePairSpriteTemplate, ANIM_TARGET, 2, 0x14, 0xffec, 0x14, ANIM_TARGET
|
||||
createsprite gSmallBubblePairSpriteTemplate, ANIM_TARGET, 2, 0xa, 0xa, 0x14, ANIM_TARGET
|
||||
createsprite gFistFootSpriteTemplate, ANIM_TARGET, 3, 0, 0, 8, 1, 0
|
||||
|
||||
@ -810,7 +810,8 @@ struct BattleStruct
|
||||
u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party
|
||||
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
|
||||
u8 redCardActivates:1;
|
||||
u8 padding2:2; // padding in the middle so pursuit fields are together
|
||||
u8 cheekPouchActivated:1;
|
||||
u8 padding2:1; // padding in the middle so pursuit fields are together
|
||||
u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch
|
||||
s32 battlerExpReward;
|
||||
u16 prevTurnSpecies[MAX_BATTLERS_COUNT]; // Stores species the AI has in play at start of turn
|
||||
@ -832,6 +833,9 @@ struct BattleStruct
|
||||
u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT];
|
||||
u8 embodyAspectBoost[NUM_BATTLE_SIDES];
|
||||
u16 savedMove; // backup current move for mid-turn switching, e.g. Red Card
|
||||
u16 opponentMonCanTera:6;
|
||||
u16 opponentMonCanDynamax:6;
|
||||
u16 padding:4;
|
||||
};
|
||||
|
||||
struct AiBattleData
|
||||
|
||||
@ -218,9 +218,11 @@
|
||||
// Ingame partner flag
|
||||
#define B_SHOW_PARTNER_TARGET FALSE // Shows the battler partner will target.
|
||||
|
||||
// Move description menu
|
||||
#define B_SHOW_MOVE_DESCRIPTION TRUE // Shows move information in battler
|
||||
|
||||
// Weather settings
|
||||
// Search for 'rain', 'sunny day', and 'hail' for move-specific or species-specific weather interactions.
|
||||
|
||||
#define B_ICE_WEATHER_BOTH 0
|
||||
#define B_ICE_WEATHER_HAIL 1
|
||||
#define B_ICE_WEATHER_SNOW 2
|
||||
|
||||
@ -66,12 +66,12 @@
|
||||
void EndDexNavSearch(u8 taskId);
|
||||
void Task_OpenDexNavFromStartMenu(u8 taskId);
|
||||
bool8 TryStartDexNavSearch(void);
|
||||
void TryIncrementSpeciesSearchLevel(u16 dexNum);
|
||||
void TryIncrementSpeciesSearchLevel(void);
|
||||
void ResetDexNavSearch(void);
|
||||
bool8 TryFindHiddenPokemon(void);
|
||||
u32 CalculateDexNavShinyRolls(void);
|
||||
void IncrementDexNavChain(void);
|
||||
|
||||
extern bool8 gDexNavBattle;
|
||||
extern u16 gDexNavSpecies;
|
||||
|
||||
#endif // GUARD_DEXNAV_H
|
||||
|
||||
@ -86,6 +86,7 @@ static void MoveSelectionDisplayPpNumber(u32 battler);
|
||||
static void MoveSelectionDisplayPpString(u32 battler);
|
||||
static void MoveSelectionDisplayMoveType(u32 battler);
|
||||
static void MoveSelectionDisplayMoveNames(u32 battler);
|
||||
static void TryMoveSelectionDisplayMoveDescription(u32 battler);
|
||||
static void MoveSelectionDisplayMoveDescription(u32 battler);
|
||||
static void SwitchIn_HandleSoundAndEnd(u32 battler);
|
||||
static void WaitForMonSelection(u32 battler);
|
||||
@ -786,8 +787,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (gBattleStruct->descriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryMoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZTrigger(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
@ -802,8 +802,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (gBattleStruct->descriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryMoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZTrigger(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
@ -817,8 +816,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (gBattleStruct->descriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryMoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZTrigger(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
@ -833,8 +831,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (gBattleStruct->descriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryMoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZTrigger(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
@ -876,7 +873,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
else if (JOY_NEW(B_MOVE_DESCRIPTION_BUTTON))
|
||||
{
|
||||
gBattleStruct->descriptionSubmenu = TRUE;
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryMoveSelectionDisplayMoveDescription(battler);
|
||||
}
|
||||
else if (JOY_NEW(START_BUTTON))
|
||||
{
|
||||
@ -1745,6 +1742,15 @@ static void MoveSelectionDisplayMoveType(u32 battler)
|
||||
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MOVE_TYPE);
|
||||
}
|
||||
|
||||
static void TryMoveSelectionDisplayMoveDescription(u32 battler)
|
||||
{
|
||||
if (!B_SHOW_MOVE_DESCRIPTION)
|
||||
return;
|
||||
|
||||
if (gBattleStruct->descriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
}
|
||||
|
||||
static void MoveSelectionDisplayMoveDescription(u32 battler)
|
||||
{
|
||||
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleResources->bufferA[battler][4]);
|
||||
|
||||
@ -218,7 +218,7 @@ enum
|
||||
LIST_AI_CHECK_BAD_MOVE,
|
||||
LIST_AI_TRY_TO_FAINT,
|
||||
LIST_AI_CHECK_VIABILITY,
|
||||
LIST_AI_SETUP_FIRST_TURN,
|
||||
LIST_AI_FORCE_SETUP_FIRST_TURN,
|
||||
LIST_AI_RISKY,
|
||||
LIST_AI_TRY_TO_2HKO,
|
||||
LIST_AI_PREFER_BATON_PASS,
|
||||
@ -227,13 +227,20 @@ enum
|
||||
LIST_AI_POWERFUL_STATUS,
|
||||
LIST_AI_NEGATE_UNAWARE,
|
||||
LIST_AI_WILL_SUICIDE,
|
||||
LIST_AI_HELP_PARTNER,
|
||||
LIST_AI_PREFER_STATUS_MOVES,
|
||||
LIST_AI_STALL,
|
||||
LIST_AI_SMART_SWITCHING,
|
||||
LIST_AI_ACE_POKEMON,
|
||||
LIST_AI_OMNISCIENT,
|
||||
LIST_AI_SMART_MON_CHOICES,
|
||||
LIST_AI_CONSERVATIVE,
|
||||
LIST_AI_SEQUENCE_SWITCHING,
|
||||
LIST_AI_DOUBLE_ACE_POKEMON,
|
||||
LIST_AI_WEIGH_ABILITY_PREDICTION,
|
||||
LIST_AI_PREFER_HIGHEST_DAMAGE_MOVE,
|
||||
LIST_AI_PREDICT_SWITCH,
|
||||
LIST_AI_PREDICT_INCOMING_MON,
|
||||
LIST_AI_DYNAMIC_FUNC,
|
||||
LIST_AI_ROAMING,
|
||||
LIST_AI_SAFARI,
|
||||
LIST_AI_FIRST_BATTLE,
|
||||
@ -383,7 +390,7 @@ static const u8 sText_Swamp[] = _("Swamp");
|
||||
static const u8 sText_CheckBadMove[] = _("Check Bad Move");
|
||||
static const u8 sText_TryToFaint[] = _("Try to Faint");
|
||||
static const u8 sText_CheckViability[] = _("Check Viability");
|
||||
static const u8 sText_SetUpFirstTurn[] = _("Setup First Turn");
|
||||
static const u8 sText_ForceSetupFirstTurn[] = _("Force Setup First Turn");
|
||||
static const u8 sText_Risky[] = _("Risky");
|
||||
static const u8 sText_TryTo2HKO[] = _("Try to 2HKO");
|
||||
static const u8 sText_PreferBatonPass[] = _("Prefer Baton Pass");
|
||||
@ -392,13 +399,20 @@ static const u8 sText_HpAware[] = _("HP Aware");
|
||||
static const u8 sText_PowerfulStatus[] = _("Powerful Status");
|
||||
static const u8 sText_NegateUnaware[] = _("Negate Unaware");
|
||||
static const u8 sText_WillSuicide[] = _("Will Suicide");
|
||||
static const u8 sText_HelpPartner[] = _("Help Partner");
|
||||
static const u8 sText_PreferStatusMoves[] = _("Prefer Status Moves");
|
||||
static const u8 sText_Stall[] = _("Stall");
|
||||
static const u8 sText_SmartSwitching[] = _("Smart Switching");
|
||||
static const u8 sText_AcePokemon[] = _("Ace Pokemon");
|
||||
static const u8 sText_AcePokemon[] = _("Ace Pokémon");
|
||||
static const u8 sText_Omniscient[] = _("Omniscient");
|
||||
static const u8 sText_SmartMonChoices[] = _("Smart Mon Choices");
|
||||
static const u8 sText_Conservative[] = _("Conservative");
|
||||
static const u8 sText_SequenceSwitching[] = _("Sequence Switching");
|
||||
static const u8 sText_DoubleAcePokemon[] = _("Double Ace Pokémon");
|
||||
static const u8 sText_WeighAbilityPrediction[] = _("Weigh Ability Prediction");
|
||||
static const u8 sText_PreferHighestDamageMove[] = _("Prefer Highest Damage Move");
|
||||
static const u8 sText_PredictSwitch[] = _("Predict Switch");
|
||||
static const u8 sText_PredictIncomingMon[] = _("Predict Incoming Mon");
|
||||
static const u8 sText_DynamicFunc[] = _("Dynamic Func");
|
||||
static const u8 sText_Roaming[] = _("Roaming");
|
||||
static const u8 sText_Safari[] = _("Safari");
|
||||
static const u8 sText_FirstBattle[] = _("First Battle");
|
||||
@ -479,7 +493,7 @@ static const struct BitfieldInfo sAIBitfield[] =
|
||||
{/*Check Bad Move*/ 1, 0},
|
||||
{/*Try to Faint*/ 1, 1},
|
||||
{/*Check Viability*/ 1, 2},
|
||||
{/*Setup First Turn*/ 1, 3},
|
||||
{/*Force Setup First Turn*/ 1, 3},
|
||||
{/*Risky*/ 1, 4},
|
||||
{/*Prefer Strongest Move*/ 1, 5},
|
||||
{/*Prefer Baton Pass*/ 1, 6},
|
||||
@ -488,16 +502,20 @@ static const struct BitfieldInfo sAIBitfield[] =
|
||||
{/*Powerful Status*/ 1, 9},
|
||||
{/*Negate Unaware*/ 1, 10},
|
||||
{/*Will Suicide*/ 1, 11},
|
||||
{/*Help Partner*/ 1, 12},
|
||||
{/*Prefer Status Moves*/ 1, 13},
|
||||
{/*Stall*/ 1, 14},
|
||||
{/*Smart Switching*/ 1, 15},
|
||||
{/*Ace Pokemon*/ 1, 16},
|
||||
{/*Omniscient*/ 1, 17},
|
||||
{/*Smart Mon Choices*/ 1, 18},
|
||||
{/*Ace Pokemon*/ 1, 16},
|
||||
{/*Omniscient*/ 1, 17},
|
||||
{/*Smart Mon Choices*/ 1, 18},
|
||||
{/*Prefer Status Moves*/ 1, 12},
|
||||
{/*Stall*/ 1, 13},
|
||||
{/*Smart Switching*/ 1, 14},
|
||||
{/*Ace Pokemon*/ 1, 15},
|
||||
{/*Omniscient*/ 1, 16},
|
||||
{/*Smart Mon Choices*/ 1, 17},
|
||||
{/*Conservative*/ 1, 18},
|
||||
{/*Sequence Switching*/ 1, 19},
|
||||
{/*Double Ace Pokemon*/ 1, 20},
|
||||
{/*Weigh Ability Prediction*/ 1, 21},
|
||||
{/*Prefer Highest Damage Move*/ 1, 22},
|
||||
{/*Predict Switch*/ 1, 23},
|
||||
{/*Predict Incoming Mon*/ 1, 24},
|
||||
{/*Dynamic Func*/ 1, 28},
|
||||
{/*Roaming*/ 1, 29},
|
||||
{/*Safari*/ 1, 30},
|
||||
{/*First Battle*/ 1, 31},
|
||||
@ -626,7 +644,7 @@ static const struct ListMenuItem sAIListItems[] =
|
||||
{sText_CheckBadMove, LIST_AI_CHECK_BAD_MOVE},
|
||||
{sText_TryToFaint, LIST_AI_TRY_TO_FAINT},
|
||||
{sText_CheckViability, LIST_AI_CHECK_VIABILITY},
|
||||
{sText_SetUpFirstTurn, LIST_AI_SETUP_FIRST_TURN},
|
||||
{sText_ForceSetupFirstTurn, LIST_AI_FORCE_SETUP_FIRST_TURN},
|
||||
{sText_Risky, LIST_AI_RISKY},
|
||||
{sText_TryTo2HKO, LIST_AI_TRY_TO_2HKO},
|
||||
{sText_PreferBatonPass, LIST_AI_PREFER_BATON_PASS},
|
||||
@ -635,13 +653,20 @@ static const struct ListMenuItem sAIListItems[] =
|
||||
{sText_PowerfulStatus, LIST_AI_POWERFUL_STATUS},
|
||||
{sText_NegateUnaware, LIST_AI_NEGATE_UNAWARE},
|
||||
{sText_WillSuicide, LIST_AI_WILL_SUICIDE},
|
||||
{sText_HelpPartner, LIST_AI_HELP_PARTNER},
|
||||
{sText_PreferStatusMoves, LIST_AI_PREFER_STATUS_MOVES},
|
||||
{sText_Stall, LIST_AI_STALL},
|
||||
{sText_SmartSwitching, LIST_AI_SMART_SWITCHING},
|
||||
{sText_AcePokemon, LIST_AI_ACE_POKEMON},
|
||||
{sText_Omniscient, LIST_AI_OMNISCIENT},
|
||||
{sText_SmartMonChoices, LIST_AI_SMART_MON_CHOICES},
|
||||
{sText_Conservative, LIST_AI_CONSERVATIVE},
|
||||
{sText_SequenceSwitching, LIST_AI_SEQUENCE_SWITCHING},
|
||||
{sText_DoubleAcePokemon, LIST_AI_DOUBLE_ACE_POKEMON},
|
||||
{sText_WeighAbilityPrediction, LIST_AI_WEIGH_ABILITY_PREDICTION},
|
||||
{sText_PreferHighestDamageMove, LIST_AI_PREFER_HIGHEST_DAMAGE_MOVE},
|
||||
{sText_PredictSwitch, LIST_AI_PREDICT_SWITCH},
|
||||
{sText_PredictIncomingMon, LIST_AI_PREDICT_INCOMING_MON},
|
||||
{sText_DynamicFunc, LIST_AI_DYNAMIC_FUNC},
|
||||
{sText_Roaming, LIST_AI_ROAMING},
|
||||
{sText_Safari, LIST_AI_SAFARI},
|
||||
{sText_FirstBattle, LIST_AI_FIRST_BATTLE},
|
||||
@ -2580,8 +2605,8 @@ static const u8 *const sHoldEffectNames[] =
|
||||
[HOLD_EFFECT_COVERT_CLOAK] = sText_HoldEffectCovertCloak,
|
||||
[HOLD_EFFECT_LOADED_DICE] = sText_HoldEffectLoadedDice,
|
||||
[HOLD_EFFECT_BOOSTER_ENERGY] = sText_HoldEffectBoosterEnergy,
|
||||
[HOLD_EFFECT_BERSERK_GENE] = sText_HoldEffectBerserkGene,
|
||||
[HOLD_EFFECT_OGERPON_MASK] = sText_HoldEffectOgerponMask,
|
||||
[HOLD_EFFECT_BERSERK_GENE] = sText_HoldEffectBerserkGene,
|
||||
};
|
||||
static const u8 *GetHoldEffectName(u16 holdEffect)
|
||||
{
|
||||
|
||||
@ -79,13 +79,9 @@ bool32 ShouldTrainerBattlerUseGimmick(u32 battler, enum Gimmick gimmick)
|
||||
// Check the trainer party data to see if a gimmick is intended.
|
||||
else
|
||||
{
|
||||
bool32 isSecondTrainer = (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT;
|
||||
u16 trainerId = isSecondTrainer ? TRAINER_BATTLE_PARAM.opponentB : TRAINER_BATTLE_PARAM.opponentA;
|
||||
const struct TrainerMon *mon = &GetTrainerPartyFromId(trainerId)[isSecondTrainer ? gBattlerPartyIndexes[battler] - MULTI_PARTY_SIZE : gBattlerPartyIndexes[battler]];
|
||||
|
||||
if (gimmick == GIMMICK_TERA && mon->teraType != TYPE_NONE)
|
||||
if (gimmick == GIMMICK_TERA && gBattleStruct->opponentMonCanTera & 1 << gBattlerPartyIndexes[battler])
|
||||
return TRUE;
|
||||
if (gimmick == GIMMICK_DYNAMAX && mon->shouldUseDynamax)
|
||||
if (gimmick == GIMMICK_DYNAMAX && gBattleStruct->opponentMonCanDynamax & 1 << gBattlerPartyIndexes[battler])
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@ -3042,6 +3042,9 @@ static void DestroyLastUsedBallGfx(struct Sprite *sprite)
|
||||
|
||||
void TryToAddMoveInfoWindow(void)
|
||||
{
|
||||
if (!B_SHOW_MOVE_DESCRIPTION)
|
||||
return;
|
||||
|
||||
LoadSpritePalette(&sSpritePalette_AbilityPopUp);
|
||||
if (GetSpriteTileStartByTag(MOVE_INFO_WINDOW_TAG) == 0xFFFF)
|
||||
LoadSpriteSheet(&sSpriteSheet_MoveInfoWindow);
|
||||
@ -3104,7 +3107,7 @@ static void SpriteCB_LastUsedBall(struct Sprite *sprite)
|
||||
}
|
||||
|
||||
static void SpriteCB_MoveInfoWin(struct Sprite *sprite)
|
||||
{
|
||||
{
|
||||
if (sprite->sHide)
|
||||
{
|
||||
if (sprite->x != LAST_BALL_WIN_X_0)
|
||||
|
||||
@ -1969,6 +1969,8 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer
|
||||
if (partyData[monIndex].dynamaxLevel > 0)
|
||||
{
|
||||
u32 data = partyData[monIndex].dynamaxLevel;
|
||||
if (partyData[monIndex].shouldUseDynamax)
|
||||
gBattleStruct->opponentMonCanDynamax |= 1 << i;
|
||||
SetMonData(&party[i], MON_DATA_DYNAMAX_LEVEL, &data);
|
||||
}
|
||||
if (partyData[monIndex].gigantamaxFactor)
|
||||
@ -1978,6 +1980,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer
|
||||
}
|
||||
if (partyData[monIndex].teraType > 0)
|
||||
{
|
||||
gBattleStruct->opponentMonCanTera |= 1 << i;
|
||||
u32 data = partyData[monIndex].teraType;
|
||||
SetMonData(&party[i], MON_DATA_TERA_TYPE, &data);
|
||||
}
|
||||
@ -5631,12 +5634,15 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void)
|
||||
{
|
||||
gIsFishingEncounter = FALSE;
|
||||
gIsSurfingEncounter = FALSE;
|
||||
if (gDexNavBattle && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT))
|
||||
if (gDexNavSpecies && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT))
|
||||
{
|
||||
IncrementDexNavChain();
|
||||
TryIncrementSpeciesSearchLevel();
|
||||
}
|
||||
else
|
||||
gSaveBlock3Ptr->dexNavChain = 0;
|
||||
|
||||
gDexNavBattle = FALSE;
|
||||
gDexNavSpecies = SPECIES_NONE;
|
||||
ResetSpriteData();
|
||||
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
|
||||
@ -344,6 +344,7 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
|
||||
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove);
|
||||
static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move);
|
||||
static void ResetValuesForCalledMove(void);
|
||||
static void TryRestoreDamageAfterCheeckPouch(u32 battler);
|
||||
|
||||
static void Cmd_attackcanceler(void);
|
||||
static void Cmd_accuracycheck(void);
|
||||
@ -2650,6 +2651,7 @@ static void Cmd_datahpupdate(void)
|
||||
}
|
||||
}
|
||||
|
||||
TryRestoreDamageAfterCheeckPouch(battler);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -6153,6 +6155,20 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent)
|
||||
return battler;
|
||||
}
|
||||
|
||||
static inline bool32 IsProtectivePadsProtected(u32 battler, u32 move)
|
||||
{
|
||||
if (!IsMoveMakingContact(move, battler))
|
||||
return FALSE;
|
||||
|
||||
if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_PROTECTIVE_PADS)
|
||||
{
|
||||
RecordItemEffectBattle(battler, HOLD_EFFECT_PROTECTIVE_PADS);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void Cmd_moveend(void)
|
||||
{
|
||||
CMD_ARGS(u8 endMode, u8 endState);
|
||||
@ -6190,6 +6206,7 @@ static void Cmd_moveend(void)
|
||||
{
|
||||
if (gProtectStructs[gBattlerTarget].spikyShielded
|
||||
&& moveEffect != EFFECT_COUNTER
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove)
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
@ -6201,7 +6218,8 @@ static void Cmd_moveend(void)
|
||||
gBattlescriptCurrInstr = BattleScript_SpikyShieldEffect;
|
||||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].kingsShielded)
|
||||
else if (gProtectStructs[gBattlerTarget].kingsShielded
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
i = gBattlerAttacker;
|
||||
@ -6215,7 +6233,8 @@ static void Cmd_moveend(void)
|
||||
gBattlescriptCurrInstr = BattleScript_KingsShieldEffect;
|
||||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].banefulBunkered)
|
||||
else if (gProtectStructs[gBattlerTarget].banefulBunkered
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_POISON | MOVE_EFFECT_AFFECTS_USER;
|
||||
@ -6225,7 +6244,9 @@ static void Cmd_moveend(void)
|
||||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].obstructed
|
||||
&& moveEffect != EFFECT_SUCKER_PUNCH && moveEffect != EFFECT_UPPER_HAND)
|
||||
&& moveEffect != EFFECT_SUCKER_PUNCH
|
||||
&& moveEffect != EFFECT_UPPER_HAND
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
i = gBattlerAttacker;
|
||||
@ -6236,7 +6257,8 @@ static void Cmd_moveend(void)
|
||||
gBattlescriptCurrInstr = BattleScript_KingsShieldEffect;
|
||||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].silkTrapped)
|
||||
else if (gProtectStructs[gBattlerTarget].silkTrapped
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
i = gBattlerAttacker;
|
||||
@ -6247,7 +6269,8 @@ static void Cmd_moveend(void)
|
||||
gBattlescriptCurrInstr = BattleScript_KingsShieldEffect;
|
||||
effect = 1;
|
||||
}
|
||||
else if (gProtectStructs[gBattlerTarget].burningBulwarked)
|
||||
else if (gProtectStructs[gBattlerTarget].burningBulwarked
|
||||
&& !IsProtectivePadsProtected(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_BURN | MOVE_EFFECT_AFFECTS_USER;
|
||||
@ -6463,9 +6486,10 @@ static void Cmd_moveend(void)
|
||||
{
|
||||
u16 *choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker];
|
||||
if (gHitMarker & HITMARKER_OBEYS
|
||||
&& (HOLD_EFFECT_CHOICE(holdEffectAtk) || GetBattlerAbility(gBattlerAttacker) == ABILITY_GORILLA_TACTICS)
|
||||
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
&& gChosenMove != MOVE_STRUGGLE
|
||||
&& (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE))
|
||||
&& (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE)
|
||||
&& (HOLD_EFFECT_CHOICE(holdEffectAtk) || GetBattlerAbility(gBattlerAttacker) == ABILITY_GORILLA_TACTICS))
|
||||
{
|
||||
if ((moveEffect == EFFECT_BATON_PASS || moveEffect == EFFECT_HEALING_WISH)
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED))
|
||||
@ -8918,6 +8942,8 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId)
|
||||
&& gBattleStruct->ateBerry[GetBattlerSide(battler)] & (1u << gBattlerPartyIndexes[battler])
|
||||
&& !IsBattlerAtMaxHp(battler))
|
||||
{
|
||||
gBattleStruct->cheekPouchActivated = TRUE;
|
||||
gBattleScripting.savedDmg = gBattleStruct->moveDamage[battler];
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 3;
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
@ -8930,6 +8956,16 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// When Cheek Pouch activates mid-battle it overwrites the current damage, so restore it
|
||||
static void TryRestoreDamageAfterCheeckPouch(u32 battler)
|
||||
{
|
||||
if (gBattleStruct->cheekPouchActivated)
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = gBattleScripting.savedDmg;
|
||||
gBattleStruct->cheekPouchActivated = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Used by Bestow and Symbiosis to take an item from one battler and give to another.
|
||||
static void BestowItem(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
@ -10602,7 +10638,7 @@ static void Cmd_various(void)
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else if (IsBattleMoveStatus(gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]]))
|
||||
else if (IsBattleMoveStatus(gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]]) && !gProtectStructs[gBattlerTarget].noValidMoves)
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
|
||||
18
src/dexnav.c
18
src/dexnav.c
@ -134,7 +134,7 @@ struct DexNavGUI
|
||||
EWRAM_DATA static struct DexNavSearch *sDexNavSearchDataPtr = NULL;
|
||||
EWRAM_DATA static struct DexNavGUI *sDexNavUiDataPtr = NULL;
|
||||
EWRAM_DATA static u8 *sBg1TilemapBuffer = NULL;
|
||||
EWRAM_DATA bool8 gDexNavBattle = FALSE;
|
||||
EWRAM_DATA u16 gDexNavSpecies = SPECIES_NONE;
|
||||
|
||||
//// Function Declarations
|
||||
//GUI
|
||||
@ -807,11 +807,11 @@ static void LoadSearchIconData(void)
|
||||
LoadCompressedSpriteSheetUsingHeap(&sHiddenMonIconSpriteSheet);
|
||||
}
|
||||
|
||||
static u8 GetSearchLevel(u16 dexNum)
|
||||
static u8 GetSearchLevel(u16 species)
|
||||
{
|
||||
u8 searchLevel;
|
||||
#if USE_DEXNAV_SEARCH_LEVELS == TRUE
|
||||
searchLevel = gSaveBlock3Ptr->dexNavSearchLevels[dexNum];
|
||||
searchLevel = gSaveBlock3Ptr->dexNavSearchLevels[species];
|
||||
#else
|
||||
searchLevel = 0;
|
||||
#endif
|
||||
@ -829,7 +829,7 @@ static void Task_SetUpDexNavSearch(u8 taskId)
|
||||
struct Task *task = &gTasks[taskId];
|
||||
|
||||
u16 species = sDexNavSearchDataPtr->species;
|
||||
u8 searchLevel = GetSearchLevel(SpeciesToNationalPokedexNum(species));
|
||||
u8 searchLevel = GetSearchLevel(species);
|
||||
|
||||
// init sprites
|
||||
sDexNavSearchDataPtr->iconSpriteId = MAX_SPRITES;
|
||||
@ -1110,7 +1110,7 @@ static void Task_DexNavSearch(u8 taskId)
|
||||
|
||||
if (sDexNavSearchDataPtr->proximity < 1)
|
||||
{
|
||||
gDexNavBattle = TRUE;
|
||||
gDexNavSpecies = sDexNavSearchDataPtr->species;
|
||||
CreateDexNavWildMon(sDexNavSearchDataPtr->species, sDexNavSearchDataPtr->potential, sDexNavSearchDataPtr->monLevel,
|
||||
sDexNavSearchDataPtr->abilityNum, sDexNavSearchDataPtr->heldItem, sDexNavSearchDataPtr->moves);
|
||||
|
||||
@ -2143,7 +2143,7 @@ static void PrintCurrentSpeciesInfo(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertIntToDecimalStringN(gStringVar4, GetSearchLevel(dexNum), 0, 4);
|
||||
ConvertIntToDecimalStringN(gStringVar4, GetSearchLevel(species), 0, 4);
|
||||
AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, SEARCH_LEVEL_Y, sFontColor_Black, 0, gStringVar4);
|
||||
}
|
||||
|
||||
@ -2666,11 +2666,11 @@ u32 CalculateDexNavShinyRolls(void)
|
||||
return chainBonus + rndBonus;
|
||||
}
|
||||
|
||||
void TryIncrementSpeciesSearchLevel(u16 dexNum)
|
||||
void TryIncrementSpeciesSearchLevel()
|
||||
{
|
||||
#if USE_DEXNAV_SEARCH_LEVELS == TRUE
|
||||
if (gMapHeader.regionMapSectionId != MAPSEC_BATTLE_FRONTIER && gSaveBlock3Ptr->dexNavSearchLevels[dexNum] < 255)
|
||||
gSaveBlock3Ptr->dexNavSearchLevels[dexNum]++;
|
||||
if (gMapHeader.regionMapSectionId != MAPSEC_BATTLE_FRONTIER && gSaveBlock3Ptr->dexNavSearchLevels[gDexNavSpecies] < 255)
|
||||
gSaveBlock3Ptr->dexNavSearchLevels[gDexNavSpecies]++;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1163,7 +1163,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
|
||||
totalRerolls += 1;
|
||||
if (I_FISHING_CHAIN && gIsFishingEncounter)
|
||||
totalRerolls += CalculateChainFishingShinyRolls();
|
||||
if (gDexNavBattle)
|
||||
if (gDexNavSpecies)
|
||||
totalRerolls += CalculateDexNavShinyRolls();
|
||||
|
||||
while (GET_SHINY_VALUE(value, personality) >= SHINY_ODDS && totalRerolls > 0)
|
||||
|
||||
21
test/battle/ability/cheeck_pouch.c
Normal file
21
test/battle/ability/cheeck_pouch.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Cheek Pouch activation doesn't mutate damage when restoring HP mid battle")
|
||||
{
|
||||
s16 damage;
|
||||
s16 healing;
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GREEDENT) { Ability(ABILITY_CHEEK_POUCH); Item(ITEM_CHOPLE_BERRY); HP(100); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_KARATE_CHOP); }
|
||||
ABILITY_POPUP(player, ABILITY_CHEEK_POUCH);
|
||||
HP_BAR(player, captureDamage: &healing);
|
||||
HP_BAR(player, captureDamage: &damage);
|
||||
} THEN {
|
||||
EXPECT_LT(healing, 0);
|
||||
EXPECT_GT(damage, 0);
|
||||
}
|
||||
}
|
||||
@ -73,3 +73,40 @@ SINGLE_BATTLE_TEST("Protective Pads protects from Rocly Helmet Damage")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Protective Pads protects from Protect's secondary effects")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_SPIKY_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_BANEFUL_BUNKER; }
|
||||
PARAMETRIZE { move = MOVE_BURNING_BULWARK; }
|
||||
PARAMETRIZE { move = MOVE_KINGS_SHIELD; }
|
||||
PARAMETRIZE { move = MOVE_SILK_TRAP; }
|
||||
PARAMETRIZE { move = MOVE_OBSTRUCT; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PROTECTIVE_PADS); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
if (move == MOVE_SPIKY_SHIELD) {
|
||||
HP_BAR(player);
|
||||
} else if (move == MOVE_BANEFUL_BUNKER) {
|
||||
STATUS_ICON(player, STATUS1_BURN);
|
||||
} else if (move == MOVE_BURNING_BULWARK) {
|
||||
STATUS_ICON(player, STATUS1_POISON);
|
||||
} else if (move == MOVE_KINGS_SHIELD) {
|
||||
MESSAGE("Wobbuffet's Attack fell!");
|
||||
} else if (move == MOVE_SILK_TRAP) {
|
||||
MESSAGE("Wobbuffet's Speed fell!");
|
||||
} else if (move == MOVE_OBSTRUCT) {
|
||||
MESSAGE("Wobbuffet's Defense harshly fell!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
53
test/battle/move_effect/sucker_punch.c
Normal file
53
test/battle/move_effect/sucker_punch.c
Normal file
@ -0,0 +1,53 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Sucker Punch hits targets that are about to attack")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_TACKLE) != DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SUCKER_PUNCH); MOVE(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUCKER_PUNCH, player);
|
||||
HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sucker Punch doesn't hit targets using status moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_GROWL) == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SUCKER_PUNCH); MOVE(opponent, MOVE_GROWL); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUCKER_PUNCH, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GROWL, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sucker Punch doesn't hit targets that has already moved")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == GetMovePriority(MOVE_SUCKER_PUNCH));
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_QUICK_ATTACK); MOVE(player, MOVE_SUCKER_PUNCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponent);
|
||||
HP_BAR(player);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUCKER_PUNCH, player);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user