Fixes Magician for spread moves (#8170)

This commit is contained in:
Alex 2025-11-09 18:10:11 +01:00 committed by GitHub
parent 43f9a78da5
commit 6c383fac96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 88 additions and 26 deletions

View File

@ -7111,7 +7111,7 @@ BattleScript_RecoilEnd::
return
BattleScript_ItemSteal::
playanimation BS_TARGET, B_ANIM_ITEM_STEAL
playanimation BS_EFFECT_BATTLER, B_ANIM_ITEM_STEAL
printstring STRINGID_PKMNSTOLEITEM
waitmessage B_WAIT_TIME_LONG
return
@ -9122,6 +9122,7 @@ BattleScript_Pickpocket::
call BattleScript_AbilityPopUp
jumpifability BS_ATTACKER, ABILITY_STICKY_HOLD, BattleScript_PickpocketPrevented
swapattackerwithtarget
copybyte gEffectBattler, gBattlerTarget
call BattleScript_ItemSteal
swapattackerwithtarget
activateitemeffects

View File

@ -303,7 +303,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_PKMNTRYINGTOTAKEFOE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is hoping to take its attacker down with it!"),
[STRINGID_PKMNTOOKFOE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} took its attacker down with it!"),
[STRINGID_PKMNREDUCEDPP] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s PP was reduced!"),
[STRINGID_PKMNSTOLEITEM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stole {B_DEF_NAME_WITH_PREFIX2}'s {B_LAST_ITEM}!"),
[STRINGID_PKMNSTOLEITEM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stole {B_EFF_NAME_WITH_PREFIX2}'s {B_LAST_ITEM}!"),
[STRINGID_TARGETCANTESCAPENOW] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} can no longer escape!"),
[STRINGID_PKMNFELLINTONIGHTMARE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} began having a nightmare!"),
[STRINGID_PKMNLOCKEDINNIGHTMARE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is locked in a nightmare!"),

View File

@ -2831,11 +2831,11 @@ static void CheckSetUnburden(u8 battler)
gDisableStructs[battler].unburdenActive = TRUE;
}
// battlerStealer steals the item of battlerItem
void StealTargetItem(u8 battlerStealer, u8 battlerItem)
// battlerStealer steals the item of itemBattler
void StealTargetItem(u8 battlerStealer, u8 itemBattler)
{
gLastUsedItem = gBattleMons[battlerItem].item;
gBattleMons[battlerItem].item = ITEM_NONE;
gLastUsedItem = gBattleMons[itemBattler].item;
gBattleMons[itemBattler].item = ITEM_NONE;
if (GetGenConfig(GEN_STEAL_WILD_ITEMS) >= GEN_9
&& !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE))
@ -2854,16 +2854,16 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem)
MarkBattlerForControllerExec(battlerStealer);
}
RecordItemEffectBattle(battlerItem, ITEM_NONE);
CheckSetUnburden(battlerItem);
RecordItemEffectBattle(itemBattler, ITEM_NONE);
CheckSetUnburden(itemBattler);
BtlController_EmitSetMonData(battlerItem, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[battlerItem].item); // remove target item
MarkBattlerForControllerExec(battlerItem);
BtlController_EmitSetMonData(itemBattler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[itemBattler].item), &gBattleMons[itemBattler].item); // remove target item
MarkBattlerForControllerExec(itemBattler);
if (GetBattlerAbility(gBattlerTarget) != ABILITY_GORILLA_TACTICS)
gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE;
if (GetBattlerAbility(itemBattler) != ABILITY_GORILLA_TACTICS)
gBattleStruct->choicedMove[itemBattler] = MOVE_NONE;
TrySaveExchangedItem(battlerItem, gLastUsedItem);
TrySaveExchangedItem(itemBattler, gLastUsedItem);
}
static inline bool32 TrySetReflect(u32 battler)
@ -5597,22 +5597,54 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
switch (abilityAtk)
{
case ABILITY_MAGICIAN:
if (move != MOVE_FLING && move != MOVE_NATURAL_GIFT
if (GetMoveEffect(move) != EFFECT_FLING
&& GetMoveEffect(move) != EFFECT_NATURAL_GIFT
&& gBattleMons[battlerAtk].item == ITEM_NONE
&& gBattleMons[battlerDef].item != ITEM_NONE
&& IsBattlerAlive(battlerAtk)
&& IsBattlerTurnDamaged(battlerDef)
&& CanStealItem(battlerAtk, battlerDef, gBattleMons[battlerDef].item)
&& !gSpecialStatuses[battlerAtk].gemBoost // In base game, gems are consumed after magician would activate.
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(battlerDef)] & (1u << gBattlerPartyIndexes[battlerDef]))
&& !DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
&& (GetBattlerAbility(battlerDef) != ABILITY_STICKY_HOLD || !IsBattlerAlive(battlerDef)))
&& !gSpecialStatuses[battlerAtk].gemBoost) // In base game, gems are consumed after magician would activate.
{
StealTargetItem(battlerAtk, battlerDef);
gBattleScripting.battler = gBattlerAbility = battlerAtk;
gEffectBattler = battlerDef;
BattleScriptCall(BattleScript_MagicianActivates);
effect = TRUE;
u32 numMagicianTargets = 0;
u32 magicianTargets = 0;
for (u32 i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].item != ITEM_NONE
&& i != battlerAtk
&& IsBattlerTurnDamaged(i)
&& CanStealItem(battlerAtk, i, gBattleMons[i].item)
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(i)] & (1u << gBattlerPartyIndexes[i]))
&& !DoesSubstituteBlockMove(battlerAtk, i, move)
&& (GetBattlerAbility(i) != ABILITY_STICKY_HOLD || !IsBattlerAlive(i)))
{
magicianTargets |= 1u << i;
numMagicianTargets++;
}
}
if (numMagicianTargets == 0)
{
effect = FALSE;
break;
}
u8 battlers[4] = {0, 1, 2, 3};
if (numMagicianTargets > 1)
SortBattlersBySpeed(battlers, FALSE);
for (u32 i = 0; i < gBattlersCount; i++)
{
u32 battler = battlers[i];
if (!(magicianTargets & 1u << battler))
continue;
StealTargetItem(battlerAtk, battler);
gBattlerAbility = battlerAtk;
gEffectBattler = battler;
BattleScriptCall(BattleScript_MagicianActivates);
effect = TRUE;
break; // found target to steal from
}
}
break;
case ABILITY_MOXIE:
@ -5775,6 +5807,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
gBattleMons[gBattlerAttacker].item = ITEM_NONE; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS)
gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // Stolen item to be assigned later
}
gEffectBattler = gBattlerTarget;
BattleScriptCall(BattleScript_ItemSteal);
effect = TRUE;
}

View File

@ -25,3 +25,31 @@ SINGLE_BATTLE_TEST("Magician gets self-damage recoil after stealing Life Orb")
}
}
DOUBLE_BATTLE_TEST("Magician steal the item from the fastest possible target")
{
u32 playerRightSpeed = 0;
u32 opponentLeftSpeed = 0;
u32 opponentRightSpeed = 0;
PARAMETRIZE { playerRightSpeed = 4; opponentLeftSpeed = 2; opponentRightSpeed = 3; }
PARAMETRIZE { playerRightSpeed = 3; opponentLeftSpeed = 4; opponentRightSpeed = 2; }
PARAMETRIZE { playerRightSpeed = 2; opponentLeftSpeed = 3; opponentRightSpeed = 4; }
GIVEN {
PLAYER(SPECIES_DELPHOX) { Speed(1); Ability(ABILITY_MAGICIAN); Item(ITEM_NONE); }
PLAYER(SPECIES_WOBBUFFET) { Speed(playerRightSpeed); Item(ITEM_POKE_BALL); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(opponentLeftSpeed); Item(ITEM_GREAT_BALL); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(opponentRightSpeed); Item(ITEM_ULTRA_BALL); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_SURF); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_MAGICIAN);
} THEN {
if (playerRightSpeed == 4)
EXPECT(playerLeft->item == ITEM_POKE_BALL);
else if (opponentLeftSpeed == 4)
EXPECT(playerLeft->item == ITEM_GREAT_BALL);
else if (playerRightSpeed == 4)
EXPECT(playerLeft->item == ITEM_ULTRA_BALL);
}
}