mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-27 04:04:17 +01:00
Merge branch 'battle_engine' of https://github.com/rh-hideout/pokeemerald-expansion into BE/z-moves
This commit is contained in:
commit
5a5c257f68
@ -1773,6 +1773,14 @@
|
|||||||
various BS_ATTACKER, VARIOUS_SET_Z_EFFECT
|
various BS_ATTACKER, VARIOUS_SET_Z_EFFECT
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro activateitemeffects battler:req
|
||||||
|
various \battler, VARIOUS_MOVEEND_ITEM_EFFECTS
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro pickpocketsteal
|
||||||
|
various 0, VARIOUS_PICKPOCKET
|
||||||
|
.endm
|
||||||
|
|
||||||
@ helpful macros
|
@ helpful macros
|
||||||
.macro setstatchanger stat:req, stages:req, down:req
|
.macro setstatchanger stat:req, stages:req, down:req
|
||||||
setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7
|
setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7
|
||||||
|
@ -8045,3 +8045,28 @@ BattleScript_EffectTerrainHit:
|
|||||||
BattleScript_TryFaint:
|
BattleScript_TryFaint:
|
||||||
tryfaintmon BS_TARGET, FALSE, NULL
|
tryfaintmon BS_TARGET, FALSE, NULL
|
||||||
goto BattleScript_MoveEnd
|
goto BattleScript_MoveEnd
|
||||||
|
|
||||||
|
BattleScript_Pickpocket::
|
||||||
|
call BattleScript_AbilityPopUp
|
||||||
|
jumpifability BS_ATTACKER, ABILITY_STICKY_HOLD, BattleScript_PickpocketPrevented
|
||||||
|
swapattackerwithtarget
|
||||||
|
call BattleScript_ItemSteal
|
||||||
|
swapattackerwithtarget
|
||||||
|
activateitemeffects BS_TARGET
|
||||||
|
return
|
||||||
|
|
||||||
|
BattleScript_PickpocketPrevented:
|
||||||
|
pause B_WAIT_TIME_SHORT
|
||||||
|
copybyte gBattlerAbility, gBattlerAttacker
|
||||||
|
call BattleScript_AbilityPopUp
|
||||||
|
printstring STRINGID_ITEMCANNOTBEREMOVED
|
||||||
|
waitmessage B_WAIT_TIME_LONG
|
||||||
|
return
|
||||||
|
|
||||||
|
BattleScript_StickyBarbTransfer::
|
||||||
|
playanimation BS_TARGET, B_ANIM_ITEM_STEAL, NULL
|
||||||
|
printstring STRINGID_STICKYBARBTRANSFER
|
||||||
|
waitmessage B_WAIT_TIME_LONG
|
||||||
|
removeitem BS_TARGET
|
||||||
|
return
|
||||||
|
|
||||||
|
@ -490,6 +490,12 @@ struct ZMoveData
|
|||||||
u8 splits[MAX_BATTLERS_COUNT];
|
u8 splits[MAX_BATTLERS_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StolenItem
|
||||||
|
{
|
||||||
|
u16 originalItem:15;
|
||||||
|
u16 stolen:1;
|
||||||
|
};
|
||||||
|
|
||||||
struct BattleStruct
|
struct BattleStruct
|
||||||
{
|
{
|
||||||
u8 turnEffectsTracker;
|
u8 turnEffectsTracker;
|
||||||
@ -607,6 +613,7 @@ struct BattleStruct
|
|||||||
u16 moveEffect2; // For Knock Off
|
u16 moveEffect2; // For Knock Off
|
||||||
u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon.
|
u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon.
|
||||||
u8 quickClawBattlerId;
|
u8 quickClawBattlerId;
|
||||||
|
struct StolenItem itemStolen[PARTY_SIZE]; // Player's team that had items stolen (two bytes per party member)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GET_MOVE_TYPE(move, typeArg) \
|
#define GET_MOVE_TYPE(move, typeArg) \
|
||||||
@ -623,6 +630,7 @@ struct BattleStruct
|
|||||||
|
|
||||||
#define BATTLER_MAX_HP(battlerId)(gBattleMons[battlerId].hp == gBattleMons[battlerId].maxHP)
|
#define BATTLER_MAX_HP(battlerId)(gBattleMons[battlerId].hp == gBattleMons[battlerId].maxHP)
|
||||||
#define TARGET_TURN_DAMAGED ((gSpecialStatuses[gBattlerTarget].physicalDmg != 0 || gSpecialStatuses[gBattlerTarget].specialDmg != 0))
|
#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 IS_BATTLER_OF_TYPE(battlerId, type)((gBattleMons[battlerId].type1 == type || gBattleMons[battlerId].type2 == type || gBattleMons[battlerId].type3 == type))
|
||||||
#define SET_BATTLER_TYPE(battlerId, type) \
|
#define SET_BATTLER_TYPE(battlerId, type) \
|
||||||
|
@ -35,6 +35,7 @@ u32 IsAbilityStatusProtected(u32 battler);
|
|||||||
bool32 TryResetBattlerStatChanges(u8 battler);
|
bool32 TryResetBattlerStatChanges(u8 battler);
|
||||||
bool32 CanCamouflage(u8 battlerId);
|
bool32 CanCamouflage(u8 battlerId);
|
||||||
u16 GetNaturePowerMove(void);
|
u16 GetNaturePowerMove(void);
|
||||||
|
void StealTargetItem(u8 battlerStealer, u8 battlerItem);
|
||||||
|
|
||||||
extern void (* const gBattleScriptingCommandsTable[])(void);
|
extern void (* const gBattleScriptingCommandsTable[])(void);
|
||||||
extern const u8 gBattlePalaceNatureToMoveGroupLikelihood[NUM_NATURES][4];
|
extern const u8 gBattlePalaceNatureToMoveGroupLikelihood[NUM_NATURES][4];
|
||||||
|
@ -369,6 +369,9 @@ extern const u8 BattleScript_JabocaRowapBerryActivates[];
|
|||||||
extern const u8 BattleScript_NotAffectedAbilityPopUp[];
|
extern const u8 BattleScript_NotAffectedAbilityPopUp[];
|
||||||
extern const u8 BattleScript_BattlerShookOffTaunt[];
|
extern const u8 BattleScript_BattlerShookOffTaunt[];
|
||||||
extern const u8 BattleScript_BattlerGotOverItsInfatuation[];
|
extern const u8 BattleScript_BattlerGotOverItsInfatuation[];
|
||||||
|
extern const u8 BattleScript_Pickpocket[];
|
||||||
|
extern const u8 BattleScript_StickyBarbTransfer[];
|
||||||
|
|
||||||
|
|
||||||
// zmoves
|
// zmoves
|
||||||
extern const u8 BattleScript_ZMoveActivateDamaging[];
|
extern const u8 BattleScript_ZMoveActivateDamaging[];
|
||||||
|
@ -140,6 +140,13 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move);
|
|||||||
bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId);
|
bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId);
|
||||||
bool32 IsPartnerMonFromSameTrainer(u8 battlerId);
|
bool32 IsPartnerMonFromSameTrainer(u8 battlerId);
|
||||||
u8 GetSplitBasedOnStats(u8 battlerId);
|
u8 GetSplitBasedOnStats(u8 battlerId);
|
||||||
|
void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast);
|
||||||
|
bool32 TestSheerForceFlag(u8 battler, u16 move);
|
||||||
|
void TryRestoreStolenItems(void);
|
||||||
|
bool32 CanStealItem(u8 battlerStealing, u8 battlerItem, u16 item);
|
||||||
|
void TrySaveExchangedItem(u8 battlerId, u16 stolenItem);
|
||||||
|
bool32 IsPartnerMonFromSameTrainer(u8 battlerId);
|
||||||
|
|
||||||
|
|
||||||
// ability checks
|
// ability checks
|
||||||
bool32 IsRolePlayBannedAbilityAtk(u16 ability);
|
bool32 IsRolePlayBannedAbilityAtk(u16 ability);
|
||||||
|
@ -188,6 +188,9 @@
|
|||||||
#define B_CRITICAL_CAPTURE TRUE // If set to TRUE, Critical Capture will be enabled.
|
#define B_CRITICAL_CAPTURE TRUE // If set to TRUE, Critical Capture will be enabled.
|
||||||
#define B_CATCHING_CHARM_BOOST 20 // % boost in Critical Capture odds if player has the Catching Charm.
|
#define B_CATCHING_CHARM_BOOST 20 // % boost in Critical Capture odds if player has the Catching Charm.
|
||||||
|
|
||||||
|
// Item Theft Settings
|
||||||
|
#define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items.
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
#define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter.
|
#define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter.
|
||||||
#define B_SLEEP_TURNS GEN_7 // In Gen5+, sleep lasts for 1-3 turns instead of 2-5 turns.
|
#define B_SLEEP_TURNS GEN_7 // In Gen5+, sleep lasts for 1-3 turns instead of 2-5 turns.
|
||||||
|
@ -174,6 +174,7 @@
|
|||||||
#define VARIOUS_TOTEM_BOOST 103
|
#define VARIOUS_TOTEM_BOOST 103
|
||||||
#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104
|
#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104
|
||||||
#define VARIOUS_SET_Z_EFFECT 105
|
#define VARIOUS_SET_Z_EFFECT 105
|
||||||
|
#define VARIOUS_MOVEEND_ITEM_EFFECTS 106
|
||||||
|
|
||||||
// Cmd_manipulatedamage
|
// Cmd_manipulatedamage
|
||||||
#define DMG_CHANGE_SIGN 0
|
#define DMG_CHANGE_SIGN 0
|
||||||
@ -234,9 +235,10 @@
|
|||||||
#define MOVEEND_MIRROR_MOVE 19
|
#define MOVEEND_MIRROR_MOVE 19
|
||||||
#define MOVEEND_NEXT_TARGET 20
|
#define MOVEEND_NEXT_TARGET 20
|
||||||
#define MOVEEND_LIFE_ORB 21
|
#define MOVEEND_LIFE_ORB 21
|
||||||
#define MOVEEND_DANCER 22
|
#define MOVEEND_PICKPOCKET 22
|
||||||
#define MOVEEND_EMERGENCY_EXIT 23
|
#define MOVEEND_DANCER 23
|
||||||
#define MOVEEND_CLEAR_BITS 24
|
#define MOVEEND_EMERGENCY_EXIT 24
|
||||||
#define MOVEEND_COUNT 25
|
#define MOVEEND_CLEAR_BITS 25
|
||||||
|
#define MOVEEND_COUNT 26
|
||||||
|
|
||||||
#endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H
|
#endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H
|
||||||
|
@ -579,8 +579,10 @@
|
|||||||
#define STRINGID_ZMOVESTATUP 575
|
#define STRINGID_ZMOVESTATUP 575
|
||||||
#define STRINGID_ZMOVEHPTRAP 576
|
#define STRINGID_ZMOVEHPTRAP 576
|
||||||
#define STRINGID_TERRAINREMOVED 577
|
#define STRINGID_TERRAINREMOVED 577
|
||||||
|
#define STRINGID_ITEMCANNOTBEREMOVED 578
|
||||||
|
#define STRINGID_STICKYBARBTRANSFER 579
|
||||||
|
|
||||||
#define BATTLESTRINGS_COUNT 578
|
#define BATTLESTRINGS_COUNT 580
|
||||||
|
|
||||||
//// multichoice message IDs
|
//// multichoice message IDs
|
||||||
// switch in ability message
|
// switch in ability message
|
||||||
|
@ -134,6 +134,7 @@
|
|||||||
#define HOLD_EFFECT_LUMINOUS_MOSS 142
|
#define HOLD_EFFECT_LUMINOUS_MOSS 142
|
||||||
#define HOLD_EFFECT_SNOWBALL 143
|
#define HOLD_EFFECT_SNOWBALL 143
|
||||||
#define HOLD_EFFECT_WEAKNESS_POLICY 144
|
#define HOLD_EFFECT_WEAKNESS_POLICY 144
|
||||||
|
#define HOLD_EFFECT_PRIMAL_ORB 145
|
||||||
|
|
||||||
// Gen7 hold effects
|
// Gen7 hold effects
|
||||||
#define HOLD_EFFECT_PROTECTIVE_PADS 154
|
#define HOLD_EFFECT_PROTECTIVE_PADS 154
|
||||||
|
@ -2929,6 +2929,9 @@ static void BattleStartClearSetData(void)
|
|||||||
gBattleStruct->arenaLostOpponentMons = 0;
|
gBattleStruct->arenaLostOpponentMons = 0;
|
||||||
|
|
||||||
gBattleStruct->mega.triggerSpriteId = 0xFF;
|
gBattleStruct->mega.triggerSpriteId = 0xFF;
|
||||||
|
|
||||||
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
|
gBattleStruct->itemStolen[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchInClearSetData(void)
|
void SwitchInClearSetData(void)
|
||||||
@ -4877,6 +4880,10 @@ static void HandleEndTurn_FinishBattle(void)
|
|||||||
sub_8186444();
|
sub_8186444();
|
||||||
BeginFastPaletteFade(3);
|
BeginFastPaletteFade(3);
|
||||||
FadeOutMapMusic(5);
|
FadeOutMapMusic(5);
|
||||||
|
#if B_TRAINERS_KNOCK_OFF_ITEMS
|
||||||
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
|
||||||
|
TryRestoreStolenItems();
|
||||||
|
#endif
|
||||||
for (i = 0; i < PARTY_SIZE; i++)
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
{
|
{
|
||||||
UndoMegaEvolution(i);
|
UndoMegaEvolution(i);
|
||||||
|
@ -705,6 +705,9 @@ static const u8 sText_ZMoveRestoreHp[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} rest
|
|||||||
static const u8 sText_ZMoveStatUp[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} boosted\nits stats using its Z-Power!");
|
static const u8 sText_ZMoveStatUp[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} boosted\nits stats using its Z-Power!");
|
||||||
static const u8 sText_ZMoveHpSwitchInTrap[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s HP was restored by the Z-Power!");
|
static const u8 sText_ZMoveHpSwitchInTrap[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s HP was restored by the Z-Power!");
|
||||||
static const u8 sText_TerrainReturnedToNormal[] = _("The terrain returned to\nnormal!");
|
static const u8 sText_TerrainReturnedToNormal[] = _("The terrain returned to\nnormal!");
|
||||||
|
static const u8 sText_ItemCannotBeRemoved[] = _("{B_ATK_NAME_WITH_PREFIX}'s item cannot be removed!");
|
||||||
|
static const u8 sText_StickyBarbTransfer[] = _("The {B_LAST_ITEM} attached itself to\n{B_ATK_NAME_WITH_PREFIX}!");
|
||||||
|
|
||||||
|
|
||||||
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
||||||
{
|
{
|
||||||
@ -716,6 +719,8 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
|
|||||||
[STRINGID_ZMOVERESTOREHP - 12] = sText_ZMoveRestoreHp,
|
[STRINGID_ZMOVERESTOREHP - 12] = sText_ZMoveRestoreHp,
|
||||||
[STRINGID_ZMOVESTATUP - 12] = sText_ZMoveStatUp,
|
[STRINGID_ZMOVESTATUP - 12] = sText_ZMoveStatUp,
|
||||||
[STRINGID_ZMOVEHPTRAP - 12] = sText_ZMoveHpSwitchInTrap,
|
[STRINGID_ZMOVEHPTRAP - 12] = sText_ZMoveHpSwitchInTrap,
|
||||||
|
[STRINGID_STICKYBARBTRANSFER - 12] = sText_StickyBarbTransfer,
|
||||||
|
[STRINGID_ITEMCANNOTBEREMOVED - 12] = sText_ItemCannotBeRemoved,
|
||||||
[STRINGID_PKMNGOTOVERITSINFATUATION - 12] = sText_PkmnGotOverItsInfatuation,
|
[STRINGID_PKMNGOTOVERITSINFATUATION - 12] = sText_PkmnGotOverItsInfatuation,
|
||||||
[STRINGID_PKMNSHOOKOFFTHETAUNT - 12] = sText_PkmnShookOffTheTaunt,
|
[STRINGID_PKMNSHOOKOFFTHETAUNT - 12] = sText_PkmnShookOffTheTaunt,
|
||||||
[STRINGID_MICLEBERRYACTIVATES - 12] = sText_MicleBerryActivates,
|
[STRINGID_MICLEBERRYACTIVATES - 12] = sText_MicleBerryActivates,
|
||||||
|
@ -2459,6 +2459,32 @@ static void CheckSetUnburden(u8 battlerId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// battlerStealer steals the item of battlerItem
|
||||||
|
void StealTargetItem(u8 battlerStealer, u8 battlerItem)
|
||||||
|
{
|
||||||
|
gLastUsedItem = gBattleMons[battlerItem].item;
|
||||||
|
gBattleMons[battlerItem].item = 0;
|
||||||
|
|
||||||
|
RecordItemEffectBattle(battlerItem, 0);
|
||||||
|
RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem));
|
||||||
|
gBattleMons[battlerStealer].item = gLastUsedItem;
|
||||||
|
|
||||||
|
CheckSetUnburden(battlerItem);
|
||||||
|
gBattleResources->flags->flags[battlerStealer] &= ~(RESOURCE_FLAG_UNBURDEN);
|
||||||
|
|
||||||
|
gActiveBattler = battlerStealer;
|
||||||
|
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); // set attacker item
|
||||||
|
MarkBattlerForControllerExec(battlerStealer);
|
||||||
|
|
||||||
|
gActiveBattler = battlerItem;
|
||||||
|
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[battlerItem].item); // remove target item
|
||||||
|
MarkBattlerForControllerExec(battlerItem);
|
||||||
|
|
||||||
|
gBattleStruct->choicedMove[battlerItem] = 0;
|
||||||
|
|
||||||
|
TrySaveExchangedItem(battlerItem, gLastUsedItem);
|
||||||
|
}
|
||||||
|
|
||||||
#define INCREMENT_RESET_RETURN \
|
#define INCREMENT_RESET_RETURN \
|
||||||
{ \
|
{ \
|
||||||
gBattlescriptCurrInstr++; \
|
gBattlescriptCurrInstr++; \
|
||||||
@ -2509,9 +2535,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
|
|||||||
&& !primary && gBattleScripting.moveEffect <= 7)
|
&& !primary && gBattleScripting.moveEffect <= 7)
|
||||||
INCREMENT_RESET_RETURN
|
INCREMENT_RESET_RETURN
|
||||||
|
|
||||||
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE
|
if (TestSheerForceFlag(gBattlerAttacker, gCurrentMove) && affectsUser != MOVE_EFFECT_AFFECTS_USER)
|
||||||
&& gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST
|
|
||||||
&& affectsUser != MOVE_EFFECT_AFFECTS_USER)
|
|
||||||
INCREMENT_RESET_RETURN
|
INCREMENT_RESET_RETURN
|
||||||
|
|
||||||
if (gBattleMons[gEffectBattler].hp == 0
|
if (gBattleMons[gEffectBattler].hp == 0
|
||||||
@ -3005,7 +3029,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
|
|||||||
break;
|
break;
|
||||||
case MOVE_EFFECT_STEAL_ITEM:
|
case MOVE_EFFECT_STEAL_ITEM:
|
||||||
{
|
{
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL)
|
if (!CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item))
|
||||||
{
|
{
|
||||||
gBattlescriptCurrInstr++;
|
gBattlescriptCurrInstr++;
|
||||||
break;
|
break;
|
||||||
@ -3043,31 +3067,17 @@ void SetMoveEffect(bool32 primary, u32 certain)
|
|||||||
}
|
}
|
||||||
else if (gBattleMons[gBattlerAttacker].item != 0
|
else if (gBattleMons[gBattlerAttacker].item != 0
|
||||||
|| gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY
|
|| gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY
|
||||||
|| IS_ITEM_MAIL(gBattleMons[gBattlerTarget].item)
|
|
||||||
|| gBattleMons[gBattlerTarget].item == 0)
|
|| gBattleMons[gBattlerTarget].item == 0)
|
||||||
{
|
{
|
||||||
gBattlescriptCurrInstr++;
|
gBattlescriptCurrInstr++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gLastUsedItem = gBattleStruct->changedItems[gBattlerAttacker] = gBattleMons[gBattlerTarget].item;
|
StealTargetItem(gBattlerAttacker, gBattlerTarget); // Attacker steals target item
|
||||||
gBattleMons[gBattlerTarget].item = 0;
|
gBattleMons[gBattlerAttacker].item = 0; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS)
|
||||||
|
gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // Stolen item to be assigned later
|
||||||
CheckSetUnburden(gBattlerTarget);
|
|
||||||
gBattleResources->flags->flags[gBattlerAttacker] &= ~(RESOURCE_FLAG_UNBURDEN);
|
|
||||||
|
|
||||||
gActiveBattler = gBattlerAttacker;
|
|
||||||
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem);
|
|
||||||
MarkBattlerForControllerExec(gBattlerAttacker);
|
|
||||||
|
|
||||||
gActiveBattler = gBattlerTarget;
|
|
||||||
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBattlerTarget].item);
|
|
||||||
MarkBattlerForControllerExec(gBattlerTarget);
|
|
||||||
|
|
||||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||||
gBattlescriptCurrInstr = BattleScript_ItemSteal;
|
gBattlescriptCurrInstr = BattleScript_ItemSteal;
|
||||||
|
|
||||||
gBattleStruct->choicedMove[gBattlerTarget] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -4879,8 +4889,7 @@ static void Cmd_moveend(void)
|
|||||||
&& (*choicedMoveAtk == 0 || *choicedMoveAtk == 0xFFFF))
|
&& (*choicedMoveAtk == 0 || *choicedMoveAtk == 0xFFFF))
|
||||||
{
|
{
|
||||||
if ((gBattleMoves[gChosenMove].effect == EFFECT_BATON_PASS
|
if ((gBattleMoves[gChosenMove].effect == EFFECT_BATON_PASS
|
||||||
|| gBattleMoves[gChosenMove].effect == EFFECT_HEALING_WISH
|
|| gBattleMoves[gChosenMove].effect == EFFECT_HEALING_WISH)
|
||||||
|| gBattleMoves[gChosenMove].effect == EFFECT_HIT_ESCAPE)
|
|
||||||
&& !(gMoveResultFlags & MOVE_RESULT_FAILED))
|
&& !(gMoveResultFlags & MOVE_RESULT_FAILED))
|
||||||
{
|
{
|
||||||
++gBattleScripting.moveendState;
|
++gBattleScripting.moveendState;
|
||||||
@ -5105,7 +5114,7 @@ static void Cmd_moveend(void)
|
|||||||
case MOVEEND_LIFE_ORB:
|
case MOVEEND_LIFE_ORB:
|
||||||
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIFE_ORB
|
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIFE_ORB
|
||||||
&& IsBattlerAlive(gBattlerAttacker)
|
&& IsBattlerAlive(gBattlerAttacker)
|
||||||
&& !(GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE && gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST)
|
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
|
||||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
|
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
|
||||||
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
|
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
|
||||||
{
|
{
|
||||||
@ -5119,6 +5128,43 @@ static void Cmd_moveend(void)
|
|||||||
}
|
}
|
||||||
gBattleScripting.moveendState++;
|
gBattleScripting.moveendState++;
|
||||||
break;
|
break;
|
||||||
|
case MOVEEND_PICKPOCKET:
|
||||||
|
if (IsBattlerAlive(gBattlerAttacker)
|
||||||
|
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item
|
||||||
|
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]) // But not knocked off
|
||||||
|
&& !(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];
|
||||||
|
// Attacker is mon who made contact, battler is mon with pickpocket
|
||||||
|
if (battler != gBattlerAttacker // Cannot pickpocket yourself
|
||||||
|
&& GetBattlerAbility(battler) == ABILITY_PICKPOCKET // Target must have pickpocket ability
|
||||||
|
&& BATTLER_DAMAGED(battler) // Target needs to have been damaged
|
||||||
|
&& !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler) // Subsitute unaffected
|
||||||
|
&& IsBattlerAlive(battler) // Battler must be alive to pickpocket
|
||||||
|
&& gBattleMons[battler].item == ITEM_NONE // Pickpocketer can't have an item already
|
||||||
|
&& CanStealItem(battler, gBattlerAttacker, gBattleMons[gBattlerAttacker].item)) // Cannot steal plates, mega stones, etc
|
||||||
|
{
|
||||||
|
gBattlerTarget = gBattlerAbility = battler;
|
||||||
|
// Battle scripting is super brittle so we shall do the item exchange now (if possible)
|
||||||
|
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD)
|
||||||
|
StealTargetItem(gBattlerTarget, gBattlerAttacker); // Target takes attacker's item
|
||||||
|
|
||||||
|
gEffectBattler = gBattlerAttacker;
|
||||||
|
BattleScriptPushCursor();
|
||||||
|
gBattlescriptCurrInstr = BattleScript_Pickpocket; // Includes sticky hold check to print separate string
|
||||||
|
effect = TRUE;
|
||||||
|
break; // Pickpocket activates on fastest mon, so exit loop.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gBattleScripting.moveendState++;
|
||||||
|
break;
|
||||||
case MOVEEND_DANCER: // Special case because it's so annoying
|
case MOVEEND_DANCER: // Special case because it's so annoying
|
||||||
if (gBattleMoves[gCurrentMove].flags & FLAG_DANCE)
|
if (gBattleMoves[gCurrentMove].flags & FLAG_DANCE)
|
||||||
{
|
{
|
||||||
@ -8471,6 +8517,10 @@ static void Cmd_various(void)
|
|||||||
case VARIOUS_SET_Z_EFFECT:
|
case VARIOUS_SET_Z_EFFECT:
|
||||||
SetZEffect(); //handles battle script jumping internally
|
SetZEffect(); //handles battle script jumping internally
|
||||||
return;
|
return;
|
||||||
|
case VARIOUS_MOVEEND_ITEM_EFFECTS:
|
||||||
|
if (ItemBattleEffects(1, gActiveBattler, FALSE))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gBattlescriptCurrInstr += 3;
|
gBattlescriptCurrInstr += 3;
|
||||||
@ -11249,7 +11299,11 @@ static void Cmd_tryswapitems(void) // trick
|
|||||||
| BATTLE_TYPE_EREADER_TRAINER
|
| BATTLE_TYPE_EREADER_TRAINER
|
||||||
| BATTLE_TYPE_FRONTIER
|
| BATTLE_TYPE_FRONTIER
|
||||||
| BATTLE_TYPE_SECRET_BASE
|
| BATTLE_TYPE_SECRET_BASE
|
||||||
| BATTLE_TYPE_RECORDED_LINK))))
|
| BATTLE_TYPE_RECORDED_LINK
|
||||||
|
#if B_TRAINERS_KNOCK_OFF_ITEMS
|
||||||
|
| BATTLE_TYPE_TRAINER
|
||||||
|
#endif
|
||||||
|
))))
|
||||||
{
|
{
|
||||||
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
|
||||||
}
|
}
|
||||||
@ -11298,6 +11352,9 @@ static void Cmd_tryswapitems(void) // trick
|
|||||||
gBattleMons[gBattlerAttacker].item = 0;
|
gBattleMons[gBattlerAttacker].item = 0;
|
||||||
gBattleMons[gBattlerTarget].item = oldItemAtk;
|
gBattleMons[gBattlerTarget].item = oldItemAtk;
|
||||||
|
|
||||||
|
RecordItemEffectBattle(gBattlerAttacker, 0);
|
||||||
|
RecordItemEffectBattle(gBattlerTarget, ItemId_GetHoldEffect(oldItemAtk));
|
||||||
|
|
||||||
gActiveBattler = gBattlerAttacker;
|
gActiveBattler = gBattlerAttacker;
|
||||||
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, newItemAtk);
|
BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, newItemAtk);
|
||||||
MarkBattlerForControllerExec(gBattlerAttacker);
|
MarkBattlerForControllerExec(gBattlerAttacker);
|
||||||
@ -11314,6 +11371,15 @@ static void Cmd_tryswapitems(void) // trick
|
|||||||
PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk)
|
PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk)
|
||||||
PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk)
|
PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk)
|
||||||
|
|
||||||
|
if (!(sideAttacker == sideTarget && IsPartnerMonFromSameTrainer(gBattlerAttacker)))
|
||||||
|
{
|
||||||
|
// if targeting your own side and you aren't in a multi battle, don't save items as stolen
|
||||||
|
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
||||||
|
TrySaveExchangedItem(gBattlerAttacker, oldItemAtk);
|
||||||
|
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
|
||||||
|
TrySaveExchangedItem(gBattlerTarget, *newItemAtk);
|
||||||
|
}
|
||||||
|
|
||||||
if (oldItemAtk != 0 && *newItemAtk != 0)
|
if (oldItemAtk != 0 && *newItemAtk != 0)
|
||||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_BOTH; // attacker's item -> <- target's item
|
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_BOTH; // attacker's item -> <- target's item
|
||||||
else if (oldItemAtk == 0 && *newItemAtk != 0)
|
else if (oldItemAtk == 0 && *newItemAtk != 0)
|
||||||
|
@ -4644,7 +4644,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
|
|||||||
&& gBattleStruct->hpBefore[battler] > gBattleMons[battler].maxHP / 2
|
&& gBattleStruct->hpBefore[battler] > gBattleMons[battler].maxHP / 2
|
||||||
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
|
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
|
||||||
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
|
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
|
||||||
&& !(GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE && gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST)
|
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
|
||||||
&& gBattleMons[battler].statStages[STAT_SPATK] != MAX_STAT_STAGE)
|
&& gBattleMons[battler].statStages[STAT_SPATK] != MAX_STAT_STAGE)
|
||||||
{
|
{
|
||||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||||
@ -4662,7 +4662,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
|
|||||||
&& gBattleStruct->hpBefore[battler] > gBattleMons[battler].maxHP / 2
|
&& gBattleStruct->hpBefore[battler] > gBattleMons[battler].maxHP / 2
|
||||||
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
|
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
|
||||||
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
|
&& (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))
|
&& (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
|
||||||
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
||||||
&& CountUsablePartyMons(battler) > 0)
|
&& CountUsablePartyMons(battler) > 0)
|
||||||
@ -5925,18 +5925,6 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
|
|||||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||||
if (IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON))
|
if (IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON))
|
||||||
goto LEFTOVERS;
|
goto LEFTOVERS;
|
||||||
case HOLD_EFFECT_STICKY_BARB:
|
|
||||||
if (!moveTurn)
|
|
||||||
{
|
|
||||||
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 8;
|
|
||||||
if (gBattleMoveDamage == 0)
|
|
||||||
gBattleMoveDamage = 1;
|
|
||||||
BattleScriptExecute(BattleScript_ItemHurtEnd2);
|
|
||||||
effect = ITEM_HP_CHANGE;
|
|
||||||
RecordItemEffectBattle(battlerId, battlerHoldEffect);
|
|
||||||
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HOLD_EFFECT_LEFTOVERS:
|
case HOLD_EFFECT_LEFTOVERS:
|
||||||
LEFTOVERS:
|
LEFTOVERS:
|
||||||
if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn)
|
if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn)
|
||||||
@ -6497,6 +6485,23 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
|
|||||||
case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move
|
case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move
|
||||||
effect = DamagedStatBoostBerryEffect(battlerId, STAT_SPDEF, SPLIT_SPECIAL);
|
effect = DamagedStatBoostBerryEffect(battlerId, STAT_SPDEF, SPLIT_SPECIAL);
|
||||||
break;
|
break;
|
||||||
|
case HOLD_EFFECT_STICKY_BARB:
|
||||||
|
if (TARGET_TURN_DAMAGED
|
||||||
|
&& (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
|
||||||
|
&& IsMoveMakingContact(gCurrentMove, gBattlerAttacker)
|
||||||
|
&& !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battlerId)
|
||||||
|
&& IsBattlerAlive(gBattlerAttacker)
|
||||||
|
&& CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item)
|
||||||
|
&& gBattleMons[gBattlerAttacker].item == ITEM_NONE)
|
||||||
|
{
|
||||||
|
// No sticky hold checks.
|
||||||
|
gEffectBattler = battlerId; // gEffectBattler = target
|
||||||
|
StealTargetItem(gBattlerAttacker, gBattlerTarget); // Attacker takes target's barb
|
||||||
|
BattleScriptPushCursor();
|
||||||
|
gBattlescriptCurrInstr = BattleScript_StickyBarbTransfer;
|
||||||
|
effect = ITEM_EFFECT_OTHER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -6530,6 +6535,18 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
|
|||||||
RecordItemEffectBattle(battlerId, battlerHoldEffect);
|
RecordItemEffectBattle(battlerId, battlerHoldEffect);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case HOLD_EFFECT_STICKY_BARB: // Not an orb per se, but similar effect, and needs to NOT activate with pickpocket
|
||||||
|
if (GetBattlerAbility(battlerId) != ABILITY_MAGIC_GUARD)
|
||||||
|
{
|
||||||
|
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 8;
|
||||||
|
if (gBattleMoveDamage == 0)
|
||||||
|
gBattleMoveDamage = 1;
|
||||||
|
BattleScriptExecute(BattleScript_ItemHurtEnd2);
|
||||||
|
effect = ITEM_HP_CHANGE;
|
||||||
|
RecordItemEffectBattle(battlerId, battlerHoldEffect);
|
||||||
|
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effect == ITEM_STATUS_CHANGE)
|
if (effect == ITEM_STATUS_CHANGE)
|
||||||
@ -8435,25 +8452,30 @@ bool32 DoBattlersShareType(u32 battler1, u32 battler2)
|
|||||||
bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId)
|
bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId)
|
||||||
{
|
{
|
||||||
u16 species = gBattleMons[battlerId].species;
|
u16 species = gBattleMons[battlerId].species;
|
||||||
|
u16 holdEffect = ItemId_GetHoldEffect(itemId);
|
||||||
|
|
||||||
if (IS_ITEM_MAIL(itemId))
|
// Mail can be stolen now
|
||||||
|
if (itemId == ITEM_ENIGMA_BERRY)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (itemId == ITEM_ENIGMA_BERRY)
|
else if (GET_BASE_SPECIES_ID(species) == SPECIES_KYOGRE && itemId == ITEM_BLUE_ORB) // includes primal
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (species == SPECIES_KYOGRE && itemId == ITEM_BLUE_ORB)
|
else if (GET_BASE_SPECIES_ID(species) == SPECIES_GROUDON && itemId == ITEM_RED_ORB) // includes primal
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (species == SPECIES_GROUDON && itemId == ITEM_RED_ORB)
|
// Mega stone cannot be lost if pokemon's base species can mega evolve with it.
|
||||||
|
else if (holdEffect == HOLD_EFFECT_MEGA_STONE && (GetMegaEvolutionSpecies(GET_BASE_SPECIES_ID(species), itemId) != SPECIES_NONE))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
// Mega stone cannot be lost if pokemon can mega evolve with it or is already mega evolved.
|
else if (GET_BASE_SPECIES_ID(species) == SPECIES_GIRATINA && itemId == ITEM_GRISEOUS_ORB)
|
||||||
else if (ItemId_GetHoldEffect(itemId) == HOLD_EFFECT_MEGA_STONE
|
|
||||||
&& ((GetMegaEvolutionSpecies(species, itemId) != SPECIES_NONE) || gBattleStruct->mega.evolvedPartyIds[GetBattlerSide(battlerId)] & gBitTable[gBattlerPartyIndexes[battlerId]]))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (species == SPECIES_GIRATINA && itemId == ITEM_GRISEOUS_ORB)
|
else if (GET_BASE_SPECIES_ID(species) == SPECIES_GENESECT && holdEffect == HOLD_EFFECT_DRIVE)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (species == SPECIES_GENESECT && GetBattlerHoldEffect(battlerId, FALSE) == HOLD_EFFECT_DRIVE)
|
else if (GET_BASE_SPECIES_ID(species) == SPECIES_SILVALLY && holdEffect == HOLD_EFFECT_MEMORY)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (species == SPECIES_SILVALLY && GetBattlerHoldEffect(battlerId, FALSE) == HOLD_EFFECT_MEMORY)
|
else if (GET_BASE_SPECIES_ID(species) == SPECIES_ARCEUS && holdEffect == HOLD_EFFECT_PLATE)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
#ifdef HOLD_EFFECT_Z_CRYSTAL
|
||||||
|
else if (holdEffect == HOLD_EFFECT_Z_CRYSTAL)
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -8721,3 +8743,122 @@ bool32 IsEntrainmentTargetOrSimpleBeamBannedAbility(u16 ability)
|
|||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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, currSpeed, currBattler;
|
||||||
|
u16 speeds[4] = {0};
|
||||||
|
|
||||||
|
for (i = 0; i < gBattlersCount; i++)
|
||||||
|
speeds[i] = GetBattlerTotalSpeedStat(battlers[i]);
|
||||||
|
|
||||||
|
for (i = 1; i < gBattlersCount; i++)
|
||||||
|
{
|
||||||
|
currBattler = battlers[i];
|
||||||
|
currSpeed = speeds[i];
|
||||||
|
j = i - 1;
|
||||||
|
|
||||||
|
if (slowToFast)
|
||||||
|
{
|
||||||
|
while (j >= 0 && speeds[j] > currSpeed)
|
||||||
|
{
|
||||||
|
battlers[j + 1] = battlers[j];
|
||||||
|
speeds[j + 1] = speeds[j];
|
||||||
|
j = j - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (j >= 0 && speeds[j] < currSpeed)
|
||||||
|
{
|
||||||
|
battlers[j + 1] = battlers[j];
|
||||||
|
speeds[j + 1] = speeds[j];
|
||||||
|
j = j - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
battlers[j + 1] = currBattler;
|
||||||
|
speeds[j + 1] = currSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool32 TestSheerForceFlag(u8 battler, u16 move)
|
||||||
|
{
|
||||||
|
if (GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && gBattleMoves[move].flags & FLAG_SHEER_FORCE_BOOST)
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TryRestoreStolenItems(void)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
u16 stolenItem = ITEM_NONE;
|
||||||
|
|
||||||
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (gBattleStruct->itemStolen[i].stolen)
|
||||||
|
{
|
||||||
|
stolenItem = gBattleStruct->itemStolen[i].originalItem;
|
||||||
|
if (stolenItem != ITEM_NONE && ItemId_GetPocket(stolenItem) != POCKET_BERRIES)
|
||||||
|
SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &stolenItem); // Restore stolen non-berry items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool32 CanStealItem(u8 battlerStealing, u8 battlerItem, u16 item)
|
||||||
|
{
|
||||||
|
u8 stealerSide = GetBattlerSide(battlerStealing);
|
||||||
|
|
||||||
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Check if the battler trying to steal should be able to
|
||||||
|
if (stealerSide == B_SIDE_OPPONENT
|
||||||
|
&& !(gBattleTypeFlags &
|
||||||
|
(BATTLE_TYPE_EREADER_TRAINER
|
||||||
|
| BATTLE_TYPE_FRONTIER
|
||||||
|
| BATTLE_TYPE_LINK
|
||||||
|
| BATTLE_TYPE_RECORDED_LINK
|
||||||
|
| BATTLE_TYPE_SECRET_BASE
|
||||||
|
#if B_TRAINERS_KNOCK_OFF_ITEMS
|
||||||
|
| BATTLE_TYPE_TRAINER
|
||||||
|
#endif
|
||||||
|
)))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if (!(gBattleTypeFlags &
|
||||||
|
(BATTLE_TYPE_EREADER_TRAINER
|
||||||
|
| BATTLE_TYPE_FRONTIER
|
||||||
|
| BATTLE_TYPE_LINK
|
||||||
|
| BATTLE_TYPE_RECORDED_LINK
|
||||||
|
| BATTLE_TYPE_SECRET_BASE))
|
||||||
|
&& (gWishFutureKnock.knockedOffMons[stealerSide] & gBitTable[gBattlerPartyIndexes[battlerStealing]]))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanBattlerGetOrLoseItem(battlerItem, item) // Battler with item cannot have it stolen
|
||||||
|
||!CanBattlerGetOrLoseItem(battlerStealing, item)) // Stealer cannot take the item
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrySaveExchangedItem(u8 battlerId, u16 stolenItem)
|
||||||
|
{
|
||||||
|
// Because BtlController_EmitSetMonData does SetMonData, we need to save the stolen item only if it matches the battler's original
|
||||||
|
// So, if the player steals an item during battle and has it stolen from it, it will not end the battle with it (naturally)
|
||||||
|
#if B_TRAINERS_KNOCK_OFF_ITEMS == TRUE
|
||||||
|
// If regular trainer battle and mon's original item matches what is being stolen, save it to be restored at end of battle
|
||||||
|
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER
|
||||||
|
&& !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
|
||||||
|
&& GetBattlerSide(battlerId) == B_SIDE_PLAYER
|
||||||
|
&& stolenItem == gBattleStruct->itemStolen[gBattlerPartyIndexes[battlerId]].originalItem)
|
||||||
|
gBattleStruct->itemStolen[gBattlerPartyIndexes[battlerId]].stolen = TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user