mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 11:44:17 +01:00
move pickpocket to back of moveend sequence
This commit is contained in:
parent
e585be6f2e
commit
64bcac4589
@ -1756,6 +1756,14 @@
|
||||
.4byte \ptr
|
||||
.endm
|
||||
|
||||
.macro activateitemeffects battler:req
|
||||
various \battler, VARIOUS_MOVEEND_ITEM_EFFECTS
|
||||
.endm
|
||||
|
||||
.macro pickpocketsteal
|
||||
various 0, VARIOUS_PICKPOCKET
|
||||
.endm
|
||||
|
||||
@ helpful macros
|
||||
.macro setstatchanger stat:req, stages:req, down:req
|
||||
setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7
|
||||
|
@ -7691,7 +7691,11 @@ BattleScript_PrintPlayerForfeitedLinkBattle::
|
||||
|
||||
BattleScript_Pickpocket::
|
||||
call BattleScript_AbilityPopUp
|
||||
setmoveeffect MOVE_EFFECT_STEAL_ITEM
|
||||
swapattackerwithtarget
|
||||
seteffectsecondary
|
||||
pickpocketsteal
|
||||
call BattleScript_ItemSteal
|
||||
swapattackerwithtarget
|
||||
activateitemeffects BS_TARGET
|
||||
return
|
||||
|
||||
|
@ -557,6 +557,7 @@ struct BattleStruct
|
||||
|
||||
#define BATTLER_MAX_HP(battlerId)(gBattleMons[battlerId].hp == gBattleMons[battlerId].maxHP)
|
||||
#define TARGET_TURN_DAMAGED ((gSpecialStatuses[gBattlerTarget].physicalDmg != 0 || gSpecialStatuses[gBattlerTarget].specialDmg != 0))
|
||||
#define BATTLER_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0))
|
||||
|
||||
#define IS_BATTLER_OF_TYPE(battlerId, type)((gBattleMons[battlerId].type1 == type || gBattleMons[battlerId].type2 == type || gBattleMons[battlerId].type3 == type))
|
||||
#define SET_BATTLER_TYPE(battlerId, type) \
|
||||
|
@ -130,5 +130,8 @@ void ClearIllusionMon(u32 battlerId);
|
||||
bool32 SetIllusionMon(struct Pokemon *mon, u32 battlerId);
|
||||
bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId);
|
||||
u8 GetBattleMoveSplit(u32 moveId);
|
||||
void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast);
|
||||
bool32 TestSheerForceFlag(u8 battler, u16 move);
|
||||
bool32 ItemCanBeStolen(u16 item, u8 battlerId);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
@ -165,6 +165,8 @@
|
||||
#define VARIOUS_SET_LAST_USED_ITEM 99
|
||||
#define VARIOUS_PARALYZE_TYPE_IMMUNITY 100
|
||||
#define VARIOUS_JUMP_IF_ABSENT 101
|
||||
#define VARIOUS_MOVEEND_ITEM_EFFECTS 102
|
||||
#define VARIOUS_PICKPOCKET 103
|
||||
|
||||
// Cmd_manipulatedamage
|
||||
#define DMG_CHANGE_SIGN 0
|
||||
@ -189,7 +191,7 @@
|
||||
#define STAT_CHANGE_ONLY_MULTIPLE 0x4
|
||||
#define STAT_CHANGE_CANT_PREVENT 0x8
|
||||
|
||||
// cases for Cmd_moveend
|
||||
// cases for Cmd_moveend - reference https://bulbapedia.bulbagarden.net/wiki/User:FIQ/Turn_sequence
|
||||
#define MOVEEND_PROTECT_LIKE_EFFECT 0
|
||||
#define MOVEEND_RAGE 1
|
||||
#define MOVEEND_DEFROST 2
|
||||
@ -212,10 +214,11 @@
|
||||
#define MOVEEND_MIRROR_MOVE 19
|
||||
#define MOVEEND_NEXT_TARGET 20
|
||||
#define MOVEEND_LIFE_ORB 21
|
||||
#define MOVEEND_DANCER 22
|
||||
#define MOVEEND_EMERGENCY_EXIT 23
|
||||
#define MOVEEND_CLEAR_BITS 24
|
||||
#define MOVEEND_COUNT 25
|
||||
#define MOVEEND_PICKPOCKET 22
|
||||
#define MOVEEND_DANCER 23
|
||||
#define MOVEEND_EMERGENCY_EXIT 24
|
||||
#define MOVEEND_CLEAR_BITS 25
|
||||
#define MOVEEND_COUNT 26
|
||||
|
||||
// stat flags for Cmd_playstatchangeanimation
|
||||
#define BIT_HP 0x1
|
||||
|
@ -2419,9 +2419,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
|
||||
&& !primary && gBattleScripting.moveEffect <= 7)
|
||||
INCREMENT_RESET_RETURN
|
||||
|
||||
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE
|
||||
&& gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST
|
||||
&& affectsUser != MOVE_EFFECT_AFFECTS_USER)
|
||||
if (TestSheerForceFlag(gBattlerAttacker, gCurrentMove) && affectsUser != MOVE_EFFECT_AFFECTS_USER)
|
||||
INCREMENT_RESET_RETURN
|
||||
|
||||
if (gBattleMons[gEffectBattler].hp == 0
|
||||
@ -2924,36 +2922,12 @@ void SetMoveEffect(bool32 primary, u32 certain)
|
||||
break;
|
||||
case MOVE_EFFECT_STEAL_ITEM:
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL)
|
||||
if (!ItemCanBeStolen(gBattleMons[gBattlerTarget].item, gBattlerAttacker))
|
||||
{
|
||||
gBattlescriptCurrInstr++;
|
||||
break;
|
||||
}
|
||||
|
||||
side = GetBattlerSide(gBattlerAttacker);
|
||||
if (gLastUsedAbility != ABILITY_PICKPOCKET //we need to swap attacker and target so this check otherwise fails
|
||||
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT
|
||||
&& !(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_FRONTIER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_x2000000
|
||||
| BATTLE_TYPE_SECRET_BASE)))
|
||||
{
|
||||
gBattlescriptCurrInstr++;
|
||||
}
|
||||
else if (!(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_FRONTIER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_x2000000
|
||||
| BATTLE_TYPE_SECRET_BASE))
|
||||
&& (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]))
|
||||
{
|
||||
gBattlescriptCurrInstr++;
|
||||
}
|
||||
else if (gBattleMons[gBattlerTarget].item
|
||||
&& gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD)
|
||||
else if (gBattleMons[gBattlerTarget].item && gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD)
|
||||
{
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_NoItemSteal;
|
||||
@ -2973,6 +2947,10 @@ void SetMoveEffect(bool32 primary, u32 certain)
|
||||
gLastUsedItem = gBattleStruct->changedItems[gBattlerAttacker] = gBattleMons[gBattlerTarget].item;
|
||||
gBattleMons[gBattlerTarget].item = 0;
|
||||
|
||||
RecordItemEffectBattle(gBattlerTarget, 0);
|
||||
RecordItemEffectBattle(gBattlerAttacker, ItemId_GetHoldEffect(gLastUsedItem));
|
||||
//item assignment doesn't happen yet
|
||||
|
||||
CheckSetUnburden(gBattlerTarget);
|
||||
gBattleResources->flags->flags[gBattlerAttacker] &= ~(RESOURCE_FLAG_UNBURDEN);
|
||||
|
||||
@ -5010,7 +4988,7 @@ static void Cmd_moveend(void)
|
||||
case MOVEEND_LIFE_ORB:
|
||||
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIFE_ORB
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& !(GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE && gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST)
|
||||
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
|
||||
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
|
||||
{
|
||||
@ -5024,6 +5002,38 @@ static void Cmd_moveend(void)
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_PICKPOCKET:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD
|
||||
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE //attacker must be holding an item
|
||||
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)) //pickpocket doesn't activate for sheer force
|
||||
&& IsMoveMakingContact(gCurrentMove, gBattlerAttacker) //pickpocket requires contact
|
||||
&& !(gMoveResultFlags & 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
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
u8 battler = battlers[i];
|
||||
|
||||
if (battler != gBattlerAttacker //cannot pickpocket yourself
|
||||
&& GetBattlerAbility(battler) == ABILITY_PICKPOCKET //'target' must have pickpocket ability
|
||||
&& BATTLER_DAMAGED(battler) //obviously battler needs to have been damaged as well
|
||||
&& !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler) //subsitute unaffected
|
||||
&& IsBattlerAlive(battler) //battler must be alive to be pickpocketed
|
||||
&& gBattleMons[battler].item == ITEM_NONE //pickpocketer can't have an item already
|
||||
&& ItemCanBeStolen(gBattleMons[gBattlerAttacker].item, battler)) //cannot steal plates, mega stones, etc
|
||||
{
|
||||
gBattlerTarget = gBattlerAbility = battler;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_Pickpocket;
|
||||
effect = TRUE;
|
||||
break; // pickpocket activates on fastest mon, so exit loop.
|
||||
}
|
||||
}
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_DANCER: // Special case because it's so annoying
|
||||
if (gBattleMoves[gCurrentMove].flags & FLAG_DANCE)
|
||||
{
|
||||
@ -8301,6 +8311,35 @@ static void Cmd_various(void)
|
||||
gBattlescriptCurrInstr += 7;
|
||||
}
|
||||
return;
|
||||
case VARIOUS_MOVEEND_ITEM_EFFECTS:
|
||||
ItemBattleEffects(1, gActiveBattler, FALSE);
|
||||
break;
|
||||
case VARIOUS_PICKPOCKET:
|
||||
{
|
||||
// different from MOVE_EFFECT_STEAL_ITEM in that it immediately assigns the stolen item to the 'attacker'
|
||||
gEffectBattler = gBattlerTarget;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
gLastUsedItem = gBattleMons[gEffectBattler].item;
|
||||
gBattleMons[gEffectBattler].item = 0;
|
||||
gBattleMons[gBattlerAttacker].item = gLastUsedItem;
|
||||
|
||||
RecordItemEffectBattle(gBattlerTarget, 0);
|
||||
RecordItemEffectBattle(gBattlerAttacker, ItemId_GetHoldEffect(gLastUsedItem));
|
||||
|
||||
CheckSetUnburden(gEffectBattler); //Give target Unburden boost
|
||||
gBattleResources->flags->flags[gBattlerTarget] &= ~(RESOURCE_FLAG_UNBURDEN); //remove attacker boost
|
||||
|
||||
gActiveBattler = gBattlerAttacker;
|
||||
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem);
|
||||
MarkBattlerForControllerExec(gActiveBattler);
|
||||
|
||||
gActiveBattler = gEffectBattler;
|
||||
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBattler].item);
|
||||
MarkBattlerForControllerExec(gActiveBattler);
|
||||
|
||||
gBattleStruct->choicedMove[gEffectBattler] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
gBattlescriptCurrInstr += 3;
|
||||
|
@ -4227,7 +4227,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
|
||||
&& gBattleStruct->hpBefore[battler] > gBattleMons[battler].maxHP / 2
|
||||
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
|
||||
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
|
||||
&& !(GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE && gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST)
|
||||
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
|
||||
&& gBattleMons[battler].statStages[STAT_SPATK] != 12)
|
||||
{
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
@ -4245,7 +4245,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
|
||||
&& gBattleStruct->hpBefore[battler] > gBattleMons[battler].maxHP / 2
|
||||
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
|
||||
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
|
||||
&& !(GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE && gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST)
|
||||
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
|
||||
&& (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
|
||||
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA))
|
||||
{
|
||||
@ -4518,24 +4518,6 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
case ABILITY_PICKPOCKET:
|
||||
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
|
||||
&& TARGET_TURN_DAMAGED
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE
|
||||
&& gBattleMons[gBattlerTarget].item == ITEM_NONE
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD)
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_STEAL_ITEM;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_Pickpocket;
|
||||
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
|
||||
effect++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ABILITYEFFECT_MOVE_END_ATTACKER: // Same as above, but for attacker
|
||||
@ -7762,3 +7744,110 @@ u8 GetBattleMoveSplit(u32 moveId)
|
||||
else
|
||||
return SPLIT_SPECIAL;
|
||||
}
|
||||
|
||||
// sort an array of battlers by speed
|
||||
// useful for effects like pickpocket, eject button, red card, dancer
|
||||
void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast)
|
||||
{
|
||||
int i, j, key, keyBank;
|
||||
u16 speeds[4] = {0};
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
speeds[i] = GetBattlerTotalSpeedStat(battlers[i]);
|
||||
|
||||
for (i = 1; i < gBattlersCount; i++)
|
||||
{
|
||||
keyBank = battlers[i];
|
||||
key = speeds[i];
|
||||
j = i - 1;
|
||||
|
||||
if (slowToFast)
|
||||
{
|
||||
while (j >= 0 && speeds[j] > key)
|
||||
{
|
||||
battlers[j + 1] = battlers[j];
|
||||
speeds[j + 1] = speeds[j];
|
||||
j = j - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (j >= 0 && speeds[j] < key)
|
||||
{
|
||||
battlers[j + 1] = battlers[j];
|
||||
speeds[j + 1] = speeds[j];
|
||||
j = j - 1;
|
||||
}
|
||||
}
|
||||
|
||||
battlers[j + 1] = keyBank;
|
||||
speeds[j + 1] = key;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 TestSheerForceFlag(u8 battler, u16 move)
|
||||
{
|
||||
if (GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && gBattleMoves[move].flags & FLAG_SHEER_FORCE_BOOST)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ItemCanBeStolen(u16 item, u8 battlerId)
|
||||
{
|
||||
u8 effect = ItemId_GetHoldEffect(item);
|
||||
|
||||
if (item == ITEM_ENIGMA_BERRY)
|
||||
return FALSE;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL)
|
||||
return FALSE;
|
||||
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT
|
||||
&& !(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_FRONTIER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_x2000000
|
||||
| BATTLE_TYPE_SECRET_BASE)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (!(gBattleTypeFlags &
|
||||
(BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_FRONTIER
|
||||
| BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_x2000000
|
||||
| BATTLE_TYPE_SECRET_BASE))
|
||||
&& (gWishFutureKnock.knockedOffMons[GetBattlerSide(battlerId)] & gBitTable[gBattlerPartyIndexes[battlerId]]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (IS_ITEM_MAIL(item))
|
||||
return FALSE;
|
||||
|
||||
switch (effect)
|
||||
{
|
||||
case HOLD_EFFECT_MEGA_STONE:
|
||||
#ifdef HOLD_EFFECT_MEMORY
|
||||
case HOLD_EFFECT_MEMORY:
|
||||
#endif
|
||||
#ifdef HOLD_EFFECT_Z_CRYSTAL
|
||||
case HOLD_EFFECT_Z_CRYSTAL:
|
||||
#endif
|
||||
#ifdef HOLD_EFFECT_DRIVE
|
||||
case HOLD_EFFECT_DRIVE:
|
||||
#endif
|
||||
#ifdef HOLD_EFFECT_GEMS
|
||||
case HOLD_EFFECT_GEMS:
|
||||
#endif
|
||||
#ifdef HOLD_EFFECT_GRISEOUS_ORB
|
||||
case HOLD_EFFECT_GRISEOUS_ORB:
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user