Stockpile / WishFutureKnock / Order up clean up (#8528)

This commit is contained in:
Alex 2025-12-22 19:57:54 +01:00 committed by GitHub
parent 42d968ebfb
commit 4d69a7274f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 133 additions and 119 deletions

View File

@ -746,9 +746,8 @@
.4byte \jumpInstr
.endm
.macro stockpile id:req
.macro stockpile
.byte 0x85
.byte \id
.endm
.macro stockpiletobasedamage

View File

@ -3741,17 +3741,16 @@ BattleScript_NotAffectedAbilityPopUp::
BattleScript_EffectStockpile::
attackcanceler
stockpile 0
stockpile
attackanimation
waitanimation
printstring STRINGID_PKMNSTOCKPILED
waitmessage B_WAIT_TIME_LONG
.if B_STOCKPILE_RAISES_DEFS < GEN_4
goto BattleScript_EffectStockpileEnd
goto BattleScript_MoveEnd
.endif
jumpifmovehadnoeffect BattleScript_EffectStockpileEnd
jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_DEF, MAX_STAT_STAGE, BattleScript_EffectStockpileDef
jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPDEF, MAX_STAT_STAGE, BattleScript_EffectStockpileEnd
jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPDEF, MAX_STAT_STAGE, BattleScript_MoveEnd
BattleScript_EffectStockpileDef:
setstatchanger STAT_DEF, 1, FALSE
statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectStockpileSpDef, BIT_SPDEF
@ -3760,12 +3759,10 @@ BattleScript_EffectStockpileDef:
waitmessage B_WAIT_TIME_LONG
BattleScript_EffectStockpileSpDef::
setstatchanger STAT_SPDEF, 1, FALSE
statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectStockpileEnd
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectStockpileEnd
statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_MoveEnd
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_MoveEnd
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_EffectStockpileEnd:
stockpile 1
goto BattleScript_MoveEnd
BattleScript_MoveEffectStockpileWoreOff::

View File

@ -183,18 +183,6 @@ struct FieldTimer
u16 fairyLockTimer;
};
struct WishFutureKnock
{
u16 futureSightCounter[MAX_BATTLERS_COUNT];
u8 futureSightBattlerIndex[MAX_BATTLERS_COUNT];
u8 futureSightPartyIndex[MAX_BATTLERS_COUNT];
u16 futureSightMove[MAX_BATTLERS_COUNT];
u16 wishCounter[MAX_BATTLERS_COUNT];
u8 wishPartyId[MAX_BATTLERS_COUNT];
u8 weatherDuration;
u8 knockedOffMons[NUM_BATTLE_SIDES]; // Each battler is represented by a bit.
};
struct AI_SavedBattleMon
{
enum Ability ability;
@ -443,7 +431,8 @@ struct LinkBattlerHeader
struct BattleEnigmaBerry battleEnigmaBerry;
};
enum IllusionState {
enum IllusionState
{
ILLUSION_NOT_SET,
ILLUSION_OFF,
ILLUSION_ON
@ -493,6 +482,20 @@ struct BattleVideo {
rng_value_t rngSeed;
};
struct Wish
{
u16 counter[MAX_BATTLERS_COUNT];
u8 partyId[MAX_BATTLERS_COUNT];
};
struct FutureSight
{
u16 move;
u16 counter:10;
u16 battlerIndex:3;
u16 partyIndex:3;
};
struct BattlerState
{
u8 targetsDone[MAX_BATTLERS_COUNT];
@ -534,7 +537,8 @@ struct PartyState
u32 timesGotHit:5;
u32 changedSpecies:11; // For forms when multiple mons can change into the same pokemon.
u32 sentOut:1;
u32 padding:9;
u32 knockedOffItem;
u32 padding:8;
u16 usedHeldItem;
};
@ -562,9 +566,12 @@ struct BattleStruct
struct BattlerState battlerState[MAX_BATTLERS_COUNT];
struct PartyState partyState[NUM_BATTLE_SIDES][PARTY_SIZE];
struct EventStates eventState;
struct FutureSight futureSight[MAX_BATTLERS_COUNT];
struct Wish wish;
u16 moveTarget[MAX_BATTLERS_COUNT];
u32 expShareExpValue;
u32 expValue;
u8 weatherDuration;
u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share
u8 expGetterMonId;
u8 expOrderId:3;
@ -1016,7 +1023,6 @@ extern u8 gBattleOutcome;
extern struct ProtectStruct gProtectStructs[MAX_BATTLERS_COUNT];
extern struct SpecialStatus gSpecialStatuses[MAX_BATTLERS_COUNT];
extern u16 gBattleWeather;
extern struct WishFutureKnock gWishFutureKnock;
extern u16 gIntroSlideFlags;
extern u8 gSentPokesToOpponent[2];
extern struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT];

View File

@ -335,7 +335,6 @@ enum __attribute__((packed)) BattleMoveEffects
EFFECT_TERA_STARSTORM,
EFFECT_DRAGON_DARTS,
EFFECT_SHELL_SIDE_ARM,
EFFECT_ORDER_UP,
EFFECT_RAPID_SPIN,
EFFECT_SPECTRAL_THIEF,
EFFECT_RECOIL,

View File

@ -2116,8 +2116,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_FUTURE_SIGHT:
if (gWishFutureKnock.futureSightCounter[LEFT_FOE(battlerAtk)] > 0
|| gWishFutureKnock.futureSightCounter[RIGHT_FOE(battlerAtk)] > 0)
if (gBattleStruct->futureSight[LEFT_FOE(battlerAtk)].counter > 0
|| gBattleStruct->futureSight[RIGHT_FOE(battlerAtk)].counter > 0)
ADJUST_SCORE(-12);
else
ADJUST_SCORE(GOOD_EFFECT);
@ -2585,7 +2585,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_WISH:
if (gWishFutureKnock.wishCounter[battlerAtk] > 0)
if (gBattleStruct->wish.counter[battlerAtk] > 0)
ADJUST_SCORE(-10);
break;
case EFFECT_ASSIST:
@ -4617,7 +4617,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
|| HasUsableWhileAsleepMove(battlerAtk)
|| aiData->abilities[battlerAtk] == ABILITY_SHED_SKIN
|| aiData->abilities[battlerAtk] == ABILITY_EARLY_BIRD
|| (AI_GetWeather() & B_WEATHER_RAIN && gWishFutureKnock.weatherDuration != 1 && aiData->abilities[battlerAtk] == ABILITY_HYDRATION && aiData->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA))
|| (AI_GetWeather() & B_WEATHER_RAIN && gBattleStruct->weatherDuration != 1 && aiData->abilities[battlerAtk] == ABILITY_HYDRATION && aiData->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA))
ADJUST_SCORE(GOOD_EFFECT);
}
break;

View File

@ -64,15 +64,15 @@ static u32 GetWishHealAmountForBattler(u32 battler)
{
u32 wishHeal = 0;
if (gWishFutureKnock.wishCounter[battler] == 0)
if (gBattleStruct->wish.counter[battler] == 0)
return wishHeal;
if (B_WISH_HP_SOURCE >= GEN_5)
{
if (IsOnPlayerSide(battler))
wishHeal = GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2;
wishHeal = GetMonData(&gPlayerParty[gBattleStruct->wish.partyId[battler]], MON_DATA_MAX_HP) / 2;
else
wishHeal = GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2;
wishHeal = GetMonData(&gEnemyParty[gBattleStruct->wish.partyId[battler]], MON_DATA_MAX_HP) / 2;
}
else
{
@ -108,11 +108,11 @@ static void GetIncomingHealInfo(u32 battler, struct IncomingHealInfo *healInfo)
}
// Wish heals at end of turn
if (gWishFutureKnock.wishCounter[battler] > 0)
if (gBattleStruct->wish.counter[battler] > 0)
{
healInfo->hasHealing = TRUE;
healInfo->healEndOfTurn = TRUE;
healInfo->wishCounter = gWishFutureKnock.wishCounter[battler];
healInfo->wishCounter = gBattleStruct->wish.counter[battler];
healInfo->healAmount = GetWishHealAmountForBattler(battler);
}
}
@ -1758,7 +1758,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler, const struct Incomi
u32 statusDamage = GetSwitchinStatusDamage(battler);
u32 hitsToKO = 0;
u16 maxHP = gBattleMons[battler].maxHP, item = gAiLogicData->items[battler], heldItemEffect = GetItemHoldEffect(item);
u8 weatherDuration = gWishFutureKnock.weatherDuration, holdEffectParam = GetItemHoldEffectParam(item);
u8 weatherDuration = gBattleStruct->weatherDuration, holdEffectParam = GetItemHoldEffectParam(item);
u32 opposingBattler = GetOppositeBattler(battler);
enum Ability opposingAbility = gAiLogicData->abilities[opposingBattler], ability = gAiLogicData->abilities[battler];
bool32 usedSingleUseHealingItem = FALSE, opponentCanBreakMold = IsMoldBreakerTypeAbility(opposingBattler, opposingAbility);

View File

@ -6601,34 +6601,34 @@ static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner)
u32 i, temp;
// if used future sight on opposing side, properly track who used it
if (gWishFutureKnock.futureSightCounter[LEFT_FOE(battlerAtk)] > 0
|| gWishFutureKnock.futureSightCounter[RIGHT_FOE(battlerAtk)] > 0)
if (gBattleStruct->futureSight[LEFT_FOE(battlerAtk)].counter > 0
|| gBattleStruct->futureSight[RIGHT_FOE(battlerAtk)].counter > 0)
{
for (i = 0; i < gBattlersCount; i++)
{
if (IsBattlerAlly(i, battlerAtk))
continue; // only on opposing side
if (gWishFutureKnock.futureSightBattlerIndex[i] == battlerAtk)
if (gBattleStruct->futureSight[i].battlerIndex == battlerAtk)
{
// if target was attacked with future sight from us, now they'll be the partner slot
gWishFutureKnock.futureSightBattlerIndex[i] = battlerPartner;
gWishFutureKnock.futureSightPartyIndex[i] = gBattlerPartyIndexes[battlerPartner];
gBattleStruct->futureSight[i].battlerIndex = battlerPartner;
gBattleStruct->futureSight[i].partyIndex = gBattlerPartyIndexes[battlerPartner];
break;
}
else if (gWishFutureKnock.futureSightBattlerIndex[i] == battlerPartner)
else if (gBattleStruct->futureSight[i].battlerIndex == battlerPartner)
{
gWishFutureKnock.futureSightBattlerIndex[i] = battlerAtk;
gWishFutureKnock.futureSightPartyIndex[i] = gBattlerPartyIndexes[battlerAtk];
gBattleStruct->futureSight[i].battlerIndex = battlerAtk;
gBattleStruct->futureSight[i].partyIndex = gBattlerPartyIndexes[battlerAtk];
break;
}
}
}
// swap wish party indices
if (gWishFutureKnock.wishCounter[battlerAtk] > 0
|| gWishFutureKnock.wishCounter[battlerPartner] > 0)
SWAP(gWishFutureKnock.wishPartyId[battlerAtk], gWishFutureKnock.wishPartyId[battlerPartner], temp);
if (gBattleStruct->wish.counter[battlerAtk] > 0
|| gBattleStruct->wish.counter[battlerPartner] > 0)
SWAP(gBattleStruct->wish.partyId[battlerAtk], gBattleStruct->wish.partyId[battlerPartner], temp);
}
static void TrySwapAttractBattlerIds(u32 battlerAtk, u32 battlerPartner)

View File

@ -229,21 +229,22 @@ static bool32 HandleEndTurnFutureSight(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gWishFutureKnock.futureSightCounter[battler] > 0 && --gWishFutureKnock.futureSightCounter[battler] == 0)
if (gBattleStruct->futureSight[battler].counter > 0
&& --gBattleStruct->futureSight[battler].counter == 0)
{
if (!IsBattlerAlive(battler))
return effect;
if (gWishFutureKnock.futureSightMove[battler] == MOVE_FUTURE_SIGHT)
if (gBattleStruct->futureSight[battler].move == MOVE_FUTURE_SIGHT)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FUTURE_SIGHT;
else
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gWishFutureKnock.futureSightMove[battler]);
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->futureSight[battler].move);
gBattlerTarget = battler;
gBattlerAttacker = gWishFutureKnock.futureSightBattlerIndex[battler];
gCurrentMove = gWishFutureKnock.futureSightMove[battler];
gBattlerAttacker = gBattleStruct->futureSight[battler].battlerIndex;
gCurrentMove = gBattleStruct->futureSight[battler].move;
if (!IsFutureSightAttackerInParty(gBattlerAttacker, gBattlerTarget, gCurrentMove))
SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker);
@ -261,15 +262,13 @@ static bool32 HandleEndTurnWish(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gWishFutureKnock.wishCounter[battler] > 0 && --gWishFutureKnock.wishCounter[battler] == 0 && IsBattlerAlive(battler))
if (gBattleStruct->wish.counter[battler] > 0 && --gBattleStruct->wish.counter[battler] == 0 && IsBattlerAlive(battler))
{
s32 wishHeal = 0;
gBattlerTarget = battler;
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gWishFutureKnock.wishPartyId[battler])
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gBattleStruct->wish.partyId[battler])
if (GetConfig(CONFIG_WISH_HP_SOURCE) >= GEN_5)
{
wishHeal = GetMonData(&GetBattlerParty(battler)[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2;
}
wishHeal = GetMonData(&GetBattlerParty(battler)[gBattleStruct->wish.partyId[battler]], MON_DATA_MAX_HP) / 2;
else
wishHeal = GetNonDynamaxMaxHP(battler) / 2;

View File

@ -202,7 +202,6 @@ EWRAM_DATA u8 gBattleOutcome = 0;
EWRAM_DATA struct ProtectStruct gProtectStructs[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA struct SpecialStatus gSpecialStatuses[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gBattleWeather = 0;
EWRAM_DATA struct WishFutureKnock gWishFutureKnock = {0};
EWRAM_DATA u16 gIntroSlideFlags = 0;
EWRAM_DATA u8 gSentPokesToOpponent[2] = {0};
EWRAM_DATA struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT] = {0};
@ -3021,7 +3020,6 @@ static void BattleStartClearSetData(void)
memset(&gFieldTimers, 0, sizeof(gFieldTimers));
memset(&gSideStatuses, 0, sizeof(gSideStatuses));
memset(&gSideTimers, 0, sizeof(gSideTimers));
memset(&gWishFutureKnock, 0, sizeof(gWishFutureKnock));
memset(&gBattleResults, 0, sizeof(gBattleResults));
ClearSetBScriptingStruct();

View File

@ -2873,7 +2873,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
moveEffect = MOVE_EFFECT_NONE;
else if (!primary
&& TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)
&& !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE))
&& !(moveEffect == MOVE_EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE))
moveEffect = MOVE_EFFECT_NONE;
else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint)
moveEffect = MOVE_EFFECT_NONE;
@ -5469,7 +5469,7 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
&& i != battlerAtk
&& IsBattlerTurnDamaged(i)
&& CanStealItem(battlerAtk, i, gBattleMons[i].item)
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(i)] & (1u << gBattlerPartyIndexes[i]))
&& !GetBattlerPartyState(i)->knockedOffItem
&& !DoesSubstituteBlockMove(battlerAtk, i, move)
&& (GetBattlerAbility(i) != ABILITY_STICKY_HOLD || !IsBattlerAlive(i)))
{
@ -5648,7 +5648,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
}
else
{
gWishFutureKnock.knockedOffMons[side] |= 1u << gBattlerPartyIndexes[gBattlerTarget];
GetBattlerPartyState(gBattlerTarget)->knockedOffItem = TRUE;
}
BattleScriptCall(BattleScript_KnockedOff);
@ -6781,10 +6781,10 @@ static void Cmd_moveend(void)
break;
case MOVEEND_PICKPOCKET:
if (IsBattlerAlive(gBattlerAttacker)
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker])) // But not knocked off
&& IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) // Pickpocket requires contact
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item
&& !GetBattlerPartyState(gBattlerAttacker)->knockedOffItem // But not knocked off
&& IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) // Pickpocket requires contact
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked
{
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE); // Pickpocket activates for fastest mon without item
@ -7137,9 +7137,7 @@ static void Cmd_switchindataupdate(void)
}
#endif
// check knocked off item
i = GetBattlerSide(battler);
if (gWishFutureKnock.knockedOffMons[i] & (1u << gBattlerPartyIndexes[battler]))
if (GetBattlerPartyState(battler)->knockedOffItem)
{
gBattleMons[battler].item = ITEM_NONE;
}
@ -8849,7 +8847,7 @@ bool32 CanUseLastResort(u8 battler)
static void RemoveAllWeather(void)
{
gWishFutureKnock.weatherDuration = 0;
gBattleStruct->weatherDuration = 0;
if (gBattleWeather & B_WEATHER_RAIN)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_RAIN;
@ -9559,25 +9557,31 @@ static void Cmd_jumpifuproarwakes(void)
static void Cmd_stockpile(void)
{
CMD_ARGS(u8 id);
CMD_ARGS();
switch (cmd->id)
gBattleMons[gBattlerAttacker].volatiles.stockpileCounter++;
if (B_STOCKPILE_RAISES_DEFS >= GEN_4)
{
case 0:
gBattleMons[gBattlerAttacker].volatiles.stockpileCounter++;
gBattleMons[gBattlerAttacker].volatiles.stockpileBeforeDef = gBattleMons[gBattlerAttacker].statStages[STAT_DEF];
gBattleMons[gBattlerAttacker].volatiles.stockpileBeforeSpDef = gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF];
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gBattleMons[gBattlerAttacker].volatiles.stockpileCounter);
break;
case 1: // Save def/sp def stats.
if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
{
gBattleMons[gBattlerAttacker].volatiles.stockpileDef += gBattleMons[gBattlerAttacker].statStages[STAT_DEF] - gBattleMons[gBattlerAttacker].volatiles.stockpileBeforeDef;
gBattleMons[gBattlerAttacker].volatiles.stockpileSpDef += gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF] - gBattleMons[gBattlerAttacker].volatiles.stockpileBeforeSpDef;
}
break;
if (ChangeStatBuffs(
gBattlerAttacker,
SET_STAT_BUFF_VALUE(1),
STAT_DEF,
STAT_CHANGE_ONLY_CHECKING,
0, 0) != STAT_CHANGE_DIDNT_WORK)
gBattleMons[gBattlerAttacker].volatiles.stockpileDef++;
if (ChangeStatBuffs(
gBattlerAttacker,
SET_STAT_BUFF_VALUE(1),
STAT_SPDEF,
STAT_CHANGE_ONLY_CHECKING,
0, 0) != STAT_CHANGE_DIDNT_WORK)
gBattleMons[gBattlerAttacker].volatiles.stockpileSpDef++;
}
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gBattleMons[gBattlerAttacker].volatiles.stockpileCounter);
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -11910,10 +11914,10 @@ static void Cmd_setfutureattack(void)
{
CMD_ARGS();
gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove;
gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker;
gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker];
gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3;
gBattleStruct->futureSight[gBattlerTarget].move = gCurrentMove;
gBattleStruct->futureSight[gBattlerTarget].battlerIndex = gBattlerAttacker;
gBattleStruct->futureSight[gBattlerTarget].partyIndex = gBattlerPartyIndexes[gBattlerAttacker];
gBattleStruct->futureSight[gBattlerTarget].counter = 3;
if (gCurrentMove == MOVE_DOOM_DESIRE)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE;
@ -12178,17 +12182,13 @@ static void Cmd_tryswapitems(void)
}
else
{
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
u8 sideTarget = GetBattlerSide(gBattlerTarget);
// You can't swap items if they were knocked off in regular battles
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_SECRET_BASE
| BATTLE_TYPE_RECORDED_LINK))
&& (gWishFutureKnock.knockedOffMons[sideAttacker] & (1u << gBattlerPartyIndexes[gBattlerAttacker])
|| gWishFutureKnock.knockedOffMons[sideTarget] & (1u << gBattlerPartyIndexes[gBattlerTarget])))
&& (GetBattlerPartyState(gBattlerAttacker)->knockedOffItem || GetBattlerPartyState(gBattlerTarget)->knockedOffItem))
{
gBattlescriptCurrInstr = cmd->failInstr;
}
@ -12244,7 +12244,7 @@ static void Cmd_tryswapitems(void)
PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk)
PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk)
if (!(sideAttacker == sideTarget && IsPartnerMonFromSameTrainer(gBattlerAttacker)))
if (!(IsBattlerAlly(gBattlerAttacker, gBattlerTarget) && IsPartnerMonFromSameTrainer(gBattlerAttacker)))
{
// if targeting your own side and you aren't in a multi battle, don't save items as stolen
if (IsOnPlayerSide(gBattlerAttacker))
@ -12325,10 +12325,10 @@ static void Cmd_trywish(void)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gWishFutureKnock.wishCounter[gBattlerAttacker] == 0)
else if (gBattleStruct->wish.counter[gBattlerAttacker] == 0)
{
gWishFutureKnock.wishCounter[gBattlerAttacker] = 2;
gWishFutureKnock.wishPartyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
gBattleStruct->wish.counter[gBattlerAttacker] = 2;
gBattleStruct->wish.partyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker];
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
@ -16902,7 +16902,7 @@ void BS_TryBestow(void)
|| !CanBattlerGetOrLoseItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerAttacker].item)
|| !CanBattlerGetOrLoseItem(gBattlerTarget, gBattlerAttacker, gBattleMons[gBattlerAttacker].item)
|| GetBattlerAbility(gBattlerAttacker) == ABILITY_STICKY_HOLD
|| gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerTarget)] & (1u << gBattlerPartyIndexes[gBattlerTarget]))
|| GetBattlerPartyState(gBattlerTarget)->knockedOffItem)
{
gBattlescriptCurrInstr = cmd->failInstr;
}

View File

@ -255,7 +255,7 @@ bool32 EndOrContinueWeather(void)
if (currBattleWeather == 0xFF)
return FALSE;
if (gWishFutureKnock.weatherDuration > 0 && --gWishFutureKnock.weatherDuration == 0)
if (gBattleStruct->weatherDuration > 0 && --gBattleStruct->weatherDuration == 0)
{
gBattleWeather = B_WEATHER_NONE;
for (u32 battler = 0; battler < gBattlersCount; battler++)
@ -2737,7 +2737,7 @@ static enum MoveCanceler CancelerMoveFailure(struct BattleContext *ctx)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_FUTURE_SIGHT:
if (gWishFutureKnock.futureSightCounter[ctx->battlerDef] > 0)
if (gBattleStruct->futureSight[ctx->battlerDef].counter > 0)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_LAST_RESORT:
@ -3305,11 +3305,11 @@ bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability)
u32 rock = sBattleWeatherInfo[battleWeatherId].rock;
gBattleWeather = sBattleWeatherInfo[battleWeatherId].flag;
if (gBattleWeather & B_WEATHER_PRIMAL_ANY)
gWishFutureKnock.weatherDuration = 0;
gBattleStruct->weatherDuration = 0;
else if (rock != 0 && GetBattlerHoldEffect(battler) == rock)
gWishFutureKnock.weatherDuration = 8;
gBattleStruct->weatherDuration = 8;
else
gWishFutureKnock.weatherDuration = 5;
gBattleStruct->weatherDuration = 5;
for (u32 i = 0; i < gBattlersCount; i++)
{
gBattleMons[i].volatiles.weatherAbilityDone = FALSE;
@ -8848,7 +8848,7 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct BattleContext *ctx)
enum Type moveType = ctx->moveType;
struct Pokemon *party = GetBattlerParty(battlerAtk);
struct Pokemon *partyMon = &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]];
struct Pokemon *partyMon = &party[gBattleStruct->futureSight[battlerDef].partyIndex];
u32 partyMonLevel = GetMonData(partyMon, MON_DATA_LEVEL, NULL);
u32 partyMonSpecies = GetMonData(partyMon, MON_DATA_SPECIES, NULL);
gBattleMovePower = GetMovePower(move);
@ -8898,11 +8898,11 @@ bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move)
struct Pokemon *party = GetBattlerParty(battlerAtk);
if (IsDoubleBattle())
{
return &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]] != &party[gBattlerPartyIndexes[battlerAtk]]
&& &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]] != &party[gBattlerPartyIndexes[BATTLE_PARTNER(battlerAtk)]];
return &party[gBattleStruct->futureSight[battlerDef].partyIndex] != &party[gBattlerPartyIndexes[battlerAtk]]
&& &party[gBattleStruct->futureSight[battlerDef].partyIndex] != &party[gBattlerPartyIndexes[BATTLE_PARTNER(battlerAtk)]];
}
return &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]] != &party[gBattlerPartyIndexes[battlerAtk]];
return &party[gBattleStruct->futureSight[battlerDef].partyIndex] != &party[gBattlerPartyIndexes[battlerAtk]];
}
@ -8965,7 +8965,7 @@ s32 CalcCritChanceStage(struct BattleContext *ctx)
{
s32 critChance = 0;
if (gSideStatuses[ctx->battlerDef] & SIDE_STATUS_LUCKY_CHANT)
if (gSideStatuses[GetBattlerSide(ctx->battlerDef)] & SIDE_STATUS_LUCKY_CHANT)
{
critChance = CRITICAL_HIT_BLOCKED;
}
@ -10302,7 +10302,7 @@ bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item)
| BATTLE_TYPE_LINK
| BATTLE_TYPE_RECORDED_LINK
| BATTLE_TYPE_SECRET_BASE))
&& (gWishFutureKnock.knockedOffMons[stealerSide] & (1u << gBattlerPartyIndexes[battlerStealing])))
&& GetBattlerPartyState(battlerStealing)->knockedOffItem)
{
return FALSE;
}

View File

@ -2251,12 +2251,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_ORDER_UP] =
{
.battleScript = BattleScript_EffectHit,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_RAPID_SPIN] =
{
.battleScript = BattleScript_EffectHit,

View File

@ -19956,7 +19956,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
"Boosts a user's stats\n"
"depending on Tatsugiri."),
.effect = EFFECT_ORDER_UP,
.effect = EFFECT_HIT,
.power = 80,
.type = TYPE_DRAGON,
.accuracy = 100,

View File

@ -68,7 +68,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Present", s16 damage)
} WHEN {
//Test will fail if present heals because the hp change would be 0
//so we want a damaging version of present
TURN { MOVE(player, MOVE_PRESENT, WITH_RNG(RNG_PRESENT, 1)); }
TURN { MOVE(player, MOVE_PRESENT, WITH_RNG(RNG_PRESENT, 1)); }
} SCENE {
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
@ -969,7 +969,7 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to
{
s16 damage1, damage2;
u32 move = 0;
for (u32 j = MOVE_HONE_CLAWS; j < MOVES_COUNT_GEN5; j++)
for (u32 j = MOVE_HONE_CLAWS + 12; j < MOVES_COUNT_GEN5; j++)
{
if (GetMoveCategory(j) != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j))
PARAMETRIZE { move = j; }

View File

@ -34,6 +34,28 @@ SINGLE_BATTLE_TEST("Stockpile's count can go up only to 3")
}
}
SINGLE_BATTLE_TEST("Stockpile's def and spDef stat increases aren't incremented by other stat stage changes")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_STOCKPILE); }
TURN { MOVE(player, MOVE_COSMIC_POWER); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_COSMIC_POWER, player);
} THEN {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 2);
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 2);
u32 stockpileDef = gBattleMons[0].volatiles.stockpileDef;
u32 stockpileSpDef = gBattleMons[0].volatiles.stockpileSpDef;
EXPECT_EQ(stockpileDef, 1);
EXPECT_EQ(stockpileSpDef, 1);
}
}
SINGLE_BATTLE_TEST("Spit Up and Swallow don't work if used without Stockpile")
{
u32 move;