Battle Item Refactor (#2902)

* items that can be used in battle now use battlescripts
* removed ExecuteTableBasedItemEffect_
* taught AI how to use items, removed AI_itemtype/flag
* X-Items store stages raised in holdEffectParam
* USE_ITEM in tests
This commit is contained in:
AgustinGDLV 2023-04-14 11:25:50 -07:00 committed by GitHub
parent 48fba7a35c
commit 2eabcea86e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1102 additions and 957 deletions

View File

@ -1330,6 +1330,22 @@
.4byte \jumpInstr
.endm
.macro itemrestorehp
callnative BS_ItemRestoreHP
.endm
.macro itemcurestatus
callnative BS_ItemCureStatus
.endm
.macro itemincreasestat
callnative BS_ItemIncreaseStat
.endm
.macro itemrestorepp
callnative BS_ItemRestorePP
.endm
@ various command changed to more readable macros
.macro cancelmultiturnmoves battler:req
various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES

View File

@ -3,7 +3,7 @@
#include "constants/battle_script_commands.h"
#include "constants/battle_anim.h"
#include "constants/battle_string_ids.h"
#include "constants/items.h"
#include "constants/moves.h"
#include "constants/songs.h"
#include "constants/game_stat.h"
.include "asm/macros.inc"
@ -14,16 +14,17 @@
.align 2
gBattlescriptsForUsingItem::
.4byte BattleScript_PlayerUsesItem
.4byte BattleScript_OpponentUsesHealItem @ AI_ITEM_FULL_RESTORE
.4byte BattleScript_OpponentUsesHealItem @ AI_ITEM_HEAL_HP
.4byte BattleScript_OpponentUsesStatusCureItem @ AI_ITEM_CURE_CONDITION
.4byte BattleScript_OpponentUsesXItem @ AI_ITEM_X_STAT
.4byte BattleScript_OpponentUsesGuardSpec @ AI_ITEM_GUARD_SPEC
.align 2
gBattlescriptsForRunningByItem::
.4byte BattleScript_RunByUsingItem
.4byte BattleScript_ItemRestoreHP @ EFFECT_ITEM_RESTORE_HP
.4byte BattleScript_ItemCureStatus @ EFFECT_ITEM_CURE_STATUS
.4byte BattleScript_ItemHealAndCureStatus @ EFFECT_ITEM_HEAL_AND_CURE_STATUS
.4byte BattleScript_ItemIncreaseStat @ EFFECT_ITEM_INCREASE_STAT
.4byte BattleScript_ItemSetMist @ EFFECT_ITEM_SET_MIST
.4byte BattleScript_ItemSetFocusEnergy @ EFFECT_ITEM_SET_FOCUS_ENERGY
.4byte BattleScript_RunByUsingItem @ EFFECT_ITEM_ESCAPE
.4byte BattleScript_BallThrow @ EFFECT_ITEM_THROW_BALL
.4byte BattleScript_ItemRestoreHP @ EFFECT_ITEM_REVIVE
.4byte BattleScript_ItemRestorePP @ EFFECT_ITEM_RESTORE_PP
.4byte BattleScript_ItemIncreaseAllStats @ EFFECT_ITEM_INCREASE_ALL_STATS
.align 2
gBattlescriptsForSafariActions::
@ -32,6 +33,100 @@ gBattlescriptsForSafariActions::
.4byte BattleScript_ActionThrowPokeblock
.4byte BattleScript_ActionWallyThrow
BattleScript_ItemEnd:
end
BattleScript_UseItemMessage:
printstring STRINGID_EMPTYSTRING3
pause B_WAIT_TIME_MED
playse SE_USE_ITEM
getbattlerside BS_ATTACKER
copybyte cMULTISTRING_CHOOSER, gBattleCommunication
printfromtable gTrainerUsedItemStringIds
waitmessage B_WAIT_TIME_LONG
return
BattleScript_ItemRestoreHP::
call BattleScript_UseItemMessage
itemrestorehp
printstring STRINGID_ITEMRESTOREDSPECIESHEALTH
waitmessage B_WAIT_TIME_LONG
jumpifbyte CMP_EQUAL, gBattleCommunication, TRUE, BattleScript_ItemRestoreHP_SendOutRevivedBattler
bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
updatestatusicon BS_ATTACKER
end
BattleScript_ItemRestoreHP_SendOutRevivedBattler:
switchinanim BS_ATTACKER, FALSE
waitstate
switchineffects BS_ATTACKER
end
BattleScript_ItemCureStatus::
call BattleScript_UseItemMessage
itemcurestatus
printstring STRINGID_ITEMCUREDSPECIESSTATUS
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_ATTACKER
end
BattleScript_ItemHealAndCureStatus::
call BattleScript_UseItemMessage
itemrestorehp
curestatus BS_ATTACKER
printstring STRINGID_ITEMRESTOREDSPECIESHEALTH
waitmessage B_WAIT_TIME_LONG
bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
updatestatusicon BS_ATTACKER
end
BattleScript_ItemIncreaseStat::
call BattleScript_UseItemMessage
itemincreasestat
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_ItemEnd
setgraphicalstatchangevalues
playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
end
BattleScript_ItemSetMist::
call BattleScript_UseItemMessage
setmist
playmoveanimation BS_ATTACKER, MOVE_MIST
waitanimation
printfromtable gMistUsedStringIds
waitmessage B_WAIT_TIME_LONG
end
BattleScript_ItemSetFocusEnergy::
call BattleScript_UseItemMessage
jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY, BattleScript_ButItFailed
setfocusenergy
playmoveanimation BS_ATTACKER, MOVE_FOCUS_ENERGY
waitanimation
printstring STRINGID_PKMNUSEDXTOGETPUMPED
waitmessage B_WAIT_TIME_LONG
end
BattleScript_ItemRestorePP::
call BattleScript_UseItemMessage
itemrestorepp
printstring STRINGID_ITEMRESTOREDSPECIESPP
waitmessage B_WAIT_TIME_LONG
end
BattleScript_ItemIncreaseAllStats::
call BattleScript_UseItemMessage
call BattleScript_AllStatsUp
end
BattleScript_BallThrow::
jumpifword CMP_COMMON_BITS, gBattleTypeFlags, BATTLE_TYPE_WALLY_TUTORIAL, BattleScript_BallThrowByWally
printstring STRINGID_PLAYERUSEDITEM
@ -100,64 +195,6 @@ BattleScript_TrainerBallBlock::
waitmessage B_WAIT_TIME_LONG
finishaction
BattleScript_PlayerUsesItem::
moveendcase MOVEEND_MIRROR_MOVE
end
BattleScript_OpponentUsesHealItem::
printstring STRINGID_EMPTYSTRING3
pause B_WAIT_TIME_MED
playse SE_USE_ITEM
printstring STRINGID_TRAINER1USEDITEM
waitmessage B_WAIT_TIME_LONG
bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
useitemonopponent
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
printstring STRINGID_PKMNSITEMRESTOREDHEALTH
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_ATTACKER
moveendcase MOVEEND_MIRROR_MOVE
finishaction
BattleScript_OpponentUsesStatusCureItem::
printstring STRINGID_EMPTYSTRING3
pause B_WAIT_TIME_MED
playse SE_USE_ITEM
printstring STRINGID_TRAINER1USEDITEM
waitmessage B_WAIT_TIME_LONG
useitemonopponent
printfromtable gTrainerItemCuredStatusStringIds
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_ATTACKER
moveendcase MOVEEND_MIRROR_MOVE
finishaction
BattleScript_OpponentUsesXItem::
printstring STRINGID_EMPTYSTRING3
pause B_WAIT_TIME_MED
playse SE_USE_ITEM
printstring STRINGID_TRAINER1USEDITEM
waitmessage B_WAIT_TIME_LONG
useitemonopponent
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
moveendcase MOVEEND_MIRROR_MOVE
finishaction
BattleScript_OpponentUsesGuardSpec::
printstring STRINGID_EMPTYSTRING3
pause B_WAIT_TIME_MED
playse SE_USE_ITEM
printstring STRINGID_TRAINER1USEDITEM
waitmessage B_WAIT_TIME_LONG
useitemonopponent
printfromtable gMistUsedStringIds
waitmessage B_WAIT_TIME_LONG
moveendcase MOVEEND_MIRROR_MOVE
finishaction
BattleScript_RunByUsingItem::
playse SE_FLEE
setbyte gBattleOutcome, B_OUTCOME_RAN

View File

@ -581,8 +581,6 @@ struct BattleStruct
void (*savedCallback)(void);
u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle
u16 chosenItem[MAX_BATTLERS_COUNT];
u8 AI_itemType[2];
u8 AI_itemFlags[2];
u16 choicedMove[MAX_BATTLERS_COUNT];
u16 changedItems[MAX_BATTLERS_COUNT];
u8 switchInItemsCounter;
@ -662,6 +660,7 @@ struct BattleStruct
u8 storedHealingWish:4; // Each battler as a bit.
u8 storedLunarDance:4; // Each battler as a bit.
u16 supremeOverlordModifier[MAX_BATTLERS_COUNT];
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
};
#define F_DYNAMIC_TYPE_1 (1 << 6)

View File

@ -1,36 +1,6 @@
#ifndef GUARD_BATTLE_AI_SWITCH_ITEMS_H
#define GUARD_BATTLE_AI_SWITCH_ITEMS_H
enum
{
AI_ITEM_FULL_RESTORE = 1,
AI_ITEM_HEAL_HP,
AI_ITEM_CURE_CONDITION,
AI_ITEM_X_STAT,
AI_ITEM_GUARD_SPEC,
AI_ITEM_NOT_RECOGNIZABLE
};
enum {
AI_HEAL_CONFUSION,
AI_HEAL_PARALYSIS,
AI_HEAL_FREEZE,
AI_HEAL_BURN,
AI_HEAL_POISON,
AI_HEAL_SLEEP,
};
enum {
AI_X_ATTACK,
AI_X_DEFEND,
AI_X_SPEED,
AI_X_SPATK,
AI_X_SPDEF, // Unused
AI_X_ACCURACY,
AI_X_EVASION, // Unused
AI_DIRE_HIT,
};
void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId);
void AI_TrySwitchOrUseItem(void);
u8 GetMostSuitableMonToSwitchInto(void);

View File

@ -648,8 +648,11 @@
#define STRINGID_COULDNTFULLYPROTECT 646
#define STRINGID_STOCKPILEDEFFECTWOREOFF 647
#define STRINGID_PKMNREVIVEDREADYTOFIGHT 648
#define STRINGID_ITEMRESTOREDSPECIESHEALTH 649
#define STRINGID_ITEMCUREDSPECIESSTATUS 650
#define STRINGID_ITEMRESTOREDSPECIESPP 651
#define BATTLESTRINGS_COUNT 649
#define BATTLESTRINGS_COUNT 652
// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,

View File

@ -7,12 +7,12 @@
#define ITEM0_INFATUATION 0x80
// new field 1 masks
#define ITEM1_X_ATTACK 0x1
#define ITEM1_X_DEFENSE 0x2
#define ITEM1_X_SPEED 0x4
#define ITEM1_X_SPATK 0x8
#define ITEM1_X_SPDEF 0x10
#define ITEM1_X_ACCURACY 0x20
#define ITEM1_X_ATTACK STAT_ATK
#define ITEM1_X_DEFENSE STAT_DEF
#define ITEM1_X_SPEED STAT_SPEED
#define ITEM1_X_SPATK STAT_SPATK
#define ITEM1_X_SPDEF STAT_SPDEF
#define ITEM1_X_ACCURACY STAT_ACC
// field 3 masks
#define ITEM3_CONFUSION 0x1

View File

@ -1035,9 +1035,22 @@
#define ITEM_USE_FIELD 2
#define ITEM_USE_PBLOCK_CASE 3
#define ITEM_USE_BAG_MENU 4 // No exit callback, stays in bag menu
#define ITEM_USE_PARTY_MENU_MOVES 5
// Item battle usage IDs (only checked to see if nonzero)
#define ITEM_B_USE_MEDICINE 1
#define ITEM_B_USE_OTHER 2
// Item battle script IDs (need to be non-zero)
#define EFFECT_ITEM_RESTORE_HP 1
#define EFFECT_ITEM_CURE_STATUS 2
#define EFFECT_ITEM_HEAL_AND_CURE_STATUS 3
#define EFFECT_ITEM_INCREASE_STAT 4
#define EFFECT_ITEM_SET_MIST 5
#define EFFECT_ITEM_SET_FOCUS_ENERGY 6
#define EFFECT_ITEM_ESCAPE 7
#define EFFECT_ITEM_THROW_BALL 8
#define EFFECT_ITEM_REVIVE 9
#define EFFECT_ITEM_RESTORE_PP 10
#define EFFECT_ITEM_INCREASE_ALL_STATS 11
// Enigma Berry dummy constant
#define EFFECT_ITEM_ENIGMA_BERRY_EREADER 1
#endif // GUARD_CONSTANTS_ITEMS_H

View File

@ -19,7 +19,6 @@ struct Item
u8 type;
ItemUseFunc fieldUseFunc;
u8 battleUsage;
ItemUseFunc battleUseFunc;
u8 secondaryId;
u8 flingPower;
};
@ -72,8 +71,9 @@ u8 ItemId_GetPocket(u16 itemId);
u8 ItemId_GetType(u16 itemId);
ItemUseFunc ItemId_GetFieldFunc(u16 itemId);
u8 ItemId_GetBattleUsage(u16 itemId);
ItemUseFunc ItemId_GetBattleFunc(u16 itemId);
u8 ItemId_GetSecondaryId(u16 itemId);
u8 ItemId_GetFlingPower(u16 itemId);
u32 GetItemStatus1Mask(u16 itemId);
u32 GetItemStatus2Mask(u16 itemId);
#endif // GUARD_ITEM_H

View File

@ -30,12 +30,9 @@ void ItemUseOutOfBattle_FormChange(u8);
void ItemUseOutOfBattle_FormChange_ConsumedOnUse(u8);
void ItemUseOutOfBattle_Honey(u8);
void ItemUseOutOfBattle_CannotUse(u8);
void ItemUseInBattle_PokeBall(u8);
void ItemUseInBattle_StatIncrease(u8);
void ItemUseInBattle_Medicine(u8);
void ItemUseInBattle_PPRecovery(u8);
void ItemUseInBattle_Escape(u8);
void ItemUseInBattle_EnigmaBerry(u8);
void ItemUseInBattle_BagMenu(u8 taskId);
void ItemUseInBattle_PartyMenu(u8 taskId);
void ItemUseInBattle_PartyMenuChooseMove(u8 taskId);
void Task_UseDigEscapeRopeOnField(u8 taskId);
u8 CanUseDigOrEscapeRopeOnCurMap(void);
u8 CheckIfItemIsTMHMOrEvolutionStone(u16 itemId);

View File

@ -48,6 +48,8 @@ void LoadHeldItemIcons(void);
void DrawHeldItemIconsForTrade(u8 *partyCounts, u8 *partySpriteIds, u8 whichParty);
void LoadPartyMenuAilmentGfx(void);
void CB2_ShowPartyMenuForItemUse(void);
void ItemUseCB_BattleScript(u8 taskId, TaskFunc task);
void ItemUseCB_BattleChooseMove(u8 taskId, TaskFunc task);
void ItemUseCB_Medicine(u8 taskId, TaskFunc task);
void ItemUseCB_AbilityCapsule(u8 taskId, TaskFunc task);
void ItemUseCB_AbilityPatch(u8 taskId, TaskFunc task);
@ -64,6 +66,7 @@ void ItemUseCB_SacredAsh(u8 taskId, TaskFunc task);
void ItemUseCB_EvolutionStone(u8 taskId, TaskFunc task);
void ItemUseCB_FormChange(u8 taskId, TaskFunc task);
void ItemUseCB_FormChange_ConsumedOnUse(u8 taskId, TaskFunc task);
const u8* GetItemEffect(u16 item);
u8 GetItemEffectType(u16 item);
void CB2_PartyMenuFromStartMenu(void);
void CB2_ChooseMonToGiveItem(void);

View File

@ -44,6 +44,7 @@ enum
RECORDED_MOVE_TARGET,
RECORDED_PARTY_INDEX,
RECORDED_BATTLE_PALACE_ACTION,
RECORDED_ITEM_ID,
};
extern u32 gRecordedBattleRngSeed;

View File

@ -10,6 +10,8 @@
#include "constants/hold_effects.h"
#include "battle_setup.h"
#include "data.h"
#include "item.h"
#include "party_menu.h"
#include "pokemon.h"
#include "random.h"
#include "util.h"
@ -995,22 +997,6 @@ u8 GetMostSuitableMonToSwitchInto(void)
return PARTY_SIZE;
}
static u8 GetAI_ItemType(u16 itemId, const u8 *itemEffect)
{
if (itemId == ITEM_FULL_RESTORE)
return AI_ITEM_FULL_RESTORE;
else if (itemEffect[4] & ITEM4_HEAL_HP)
return AI_ITEM_HEAL_HP;
else if (itemEffect[3] & ITEM3_STATUS_ALL)
return AI_ITEM_CURE_CONDITION;
else if ((itemEffect[0] & ITEM0_DIRE_HIT) || itemEffect[1])
return AI_ITEM_X_STAT;
else if (itemEffect[3] & ITEM3_GUARD_SPEC)
return AI_ITEM_GUARD_SPEC;
else
return AI_ITEM_NOT_RECOGNIZABLE;
}
static bool32 AiExpectsToFaintPlayer(void)
{
bool32 canFaintPlayer;
@ -1070,96 +1056,70 @@ static bool8 ShouldUseItem(void)
u8 paramOffset;
u8 battlerSide;
if (i != 0 && validMons > (gBattleResources->battleHistory->itemsNo - i) + 1)
continue;
item = gBattleResources->battleHistory->trainerItems[i];
if (item == ITEM_NONE)
continue;
if (gItemEffectTable[item] == NULL)
itemEffects = GetItemEffect(item);
if (itemEffects == NULL)
continue;
if (item == ITEM_ENIGMA_BERRY_E_READER)
itemEffects = gSaveBlock1Ptr->enigmaBerry.itemEffect;
else
itemEffects = gItemEffectTable[item];
*(gBattleStruct->AI_itemType + gActiveBattler / 2) = GetAI_ItemType(item, itemEffects);
switch (*(gBattleStruct->AI_itemType + gActiveBattler / 2))
switch (ItemId_GetBattleUsage(item))
{
case AI_ITEM_FULL_RESTORE:
case EFFECT_ITEM_HEAL_AND_CURE_STATUS:
shouldUse = AI_ShouldHeal(0);
break;
case AI_ITEM_HEAL_HP:
case EFFECT_ITEM_RESTORE_HP:
shouldUse = AI_ShouldHeal(itemEffects[GetItemEffectParamOffset(item, 4, 4)]);
break;
case AI_ITEM_CURE_CONDITION:
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) = 0;
case EFFECT_ITEM_CURE_STATUS:
if (itemEffects[3] & ITEM3_SLEEP && gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)
{
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_HEAL_SLEEP);
shouldUse = TRUE;
}
if (itemEffects[3] & ITEM3_POISON && (gBattleMons[gActiveBattler].status1 & STATUS1_POISON
|| gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_POISON))
{
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_HEAL_POISON);
shouldUse = TRUE;
}
if (itemEffects[3] & ITEM3_BURN && gBattleMons[gActiveBattler].status1 & STATUS1_BURN)
{
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_HEAL_BURN);
shouldUse = TRUE;
}
if (itemEffects[3] & ITEM3_FREEZE && gBattleMons[gActiveBattler].status1 & STATUS1_FREEZE)
{
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_HEAL_FREEZE);
shouldUse = TRUE;
}
if (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[gActiveBattler].status1 & STATUS1_PARALYSIS)
{
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_HEAL_PARALYSIS);
shouldUse = TRUE;
}
if (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[gActiveBattler].status2 & STATUS2_CONFUSION)
{
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_HEAL_CONFUSION);
shouldUse = TRUE;
}
break;
case AI_ITEM_X_STAT:
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) = 0;
if (gDisableStructs[gActiveBattler].isFirstTurn == 0)
break;
if (itemEffects[1] & ITEM1_X_ATTACK)
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_X_ATTACK);
if (itemEffects[1] & ITEM1_X_DEFENSE)
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_X_DEFEND);
if (itemEffects[1] & ITEM1_X_SPEED)
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_X_SPEED);
if (itemEffects[1] & ITEM1_X_SPATK)
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_X_SPATK);
if (itemEffects[1] & ITEM1_X_SPDEF)
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_X_SPDEF);
if (itemEffects[1] & ITEM1_X_ACCURACY)
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_X_ACCURACY);
if (itemEffects[0] & ITEM0_DIRE_HIT)
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) |= (1 << AI_DIRE_HIT);
shouldUse = TRUE;
break;
case AI_ITEM_GUARD_SPEC:
case EFFECT_ITEM_INCREASE_STAT:
case EFFECT_ITEM_INCREASE_ALL_STATS:
if (!gDisableStructs[gActiveBattler].isFirstTurn
|| AI_OpponentCanFaintAiWithMod(0))
break;
shouldUse = TRUE;
break;
case EFFECT_ITEM_SET_FOCUS_ENERGY:
if (!gDisableStructs[gActiveBattler].isFirstTurn
|| gBattleMons[gActiveBattler].status2 & STATUS2_FOCUS_ENERGY
|| AI_OpponentCanFaintAiWithMod(0))
break;
shouldUse = TRUE;
break;
case EFFECT_ITEM_SET_MIST:
battlerSide = GetBattlerSide(gActiveBattler);
if (gDisableStructs[gActiveBattler].isFirstTurn != 0 && gSideTimers[battlerSide].mistTimer == 0)
if (gDisableStructs[gActiveBattler].isFirstTurn && gSideTimers[battlerSide].mistTimer == 0)
shouldUse = TRUE;
break;
case AI_ITEM_NOT_RECOGNIZABLE:
case EFFECT_ITEM_REVIVE:
gBattleStruct->itemPartyIndex[gActiveBattler] = GetFirstFaintedPartyIndex(gActiveBattler);
if (gBattleStruct->itemPartyIndex[gActiveBattler] != PARTY_SIZE) // Revive if possible.
shouldUse = TRUE;
break;
default:
return FALSE;
}
if (shouldUse)
{
// Set selected party ID to current battler if none chosen.
if (gBattleStruct->itemPartyIndex[gActiveBattler] == PARTY_SIZE)
gBattleStruct->itemPartyIndex[gActiveBattler] = gBattlerPartyIndexes[gActiveBattler];
BtlController_EmitTwoReturnValues(BUFFER_B, B_ACTION_USE_ITEM, 0);
*(gBattleStruct->chosenItem + (gActiveBattler / 2) * 2) = item;
gBattleStruct->chosenItem[gActiveBattler] = item;
gBattleResources->battleHistory->trainerItems[i] = 0;
return shouldUse;
}

View File

@ -1667,7 +1667,7 @@ static void OpponentHandleChooseMove(void)
static void OpponentHandleChooseItem(void)
{
BtlController_EmitOneReturnValue(BUFFER_B, *(gBattleStruct->chosenItem + (gActiveBattler / 2) * 2));
BtlController_EmitOneReturnValue(BUFFER_B, gBattleStruct->chosenItem[gActiveBattler]);
OpponentBufferExecCompleted();
}

View File

@ -10,6 +10,7 @@
#include "battle_tv.h"
#include "bg.h"
#include "data.h"
#include "item_menu.h"
#include "item_use.h"
#include "link.h"
#include "main.h"
@ -1437,6 +1438,10 @@ static void RecordedOpponentHandleChooseMove(void)
static void RecordedOpponentHandleChooseItem(void)
{
u8 byte1 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler);
u8 byte2 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler);
gBattleStruct->chosenItem[gActiveBattler] = (byte1 << 8) | byte2;
BtlController_EmitOneReturnValue(BUFFER_B, gBattleStruct->chosenItem[gActiveBattler]);
RecordedOpponentBufferExecCompleted();
}

View File

@ -7,6 +7,7 @@
#include "battle_interface.h"
#include "bg.h"
#include "data.h"
#include "item_menu.h"
#include "item_use.h"
#include "link.h"
#include "main.h"
@ -1461,6 +1462,10 @@ static void RecordedPlayerHandleChooseMove(void)
static void RecordedPlayerHandleChooseItem(void)
{
u8 byte1 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler);
u8 byte2 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler);
gBattleStruct->chosenItem[gActiveBattler] = (byte1 << 8) | byte2;
BtlController_EmitOneReturnValue(BUFFER_B, gBattleStruct->chosenItem[gActiveBattler]);
RecordedPlayerBufferExecCompleted();
}

View File

@ -4162,6 +4162,7 @@ static void HandleTurnActionSelectionState(void)
}
else
{
gBattleStruct->itemPartyIndex[gActiveBattler] = PARTY_SIZE;
BtlController_EmitChooseAction(BUFFER_A, gChosenActionByBattler[0], gBattleResources->bufferB[0][1] | (gBattleResources->bufferB[0][2] << 8));
MarkBattlerForControllerExec(gActiveBattler);
gBattleCommunication[gActiveBattler]++;
@ -4229,10 +4230,11 @@ static void HandleTurnActionSelectionState(void)
return;
}
if ((gBattleTypeFlags & (BATTLE_TYPE_LINK
if (((gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_FRONTIER_NO_PYRAMID
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_RECORDED_LINK))
&& !gTestRunnerEnabled)
// Or if currently held by Sky Drop
|| gStatuses3[gActiveBattler] & STATUS3_SKY_DROPPED)
{

View File

@ -467,7 +467,7 @@ const u8 *const gPokeblockWasTooXStringTable[FLAVOR_COUNT] =
static const u8 sText_PlayerUsedItem[] = _("{B_PLAYER_NAME} used\n{B_LAST_ITEM}!");
static const u8 sText_WallyUsedItem[] = _("WALLY used\n{B_LAST_ITEM}!");
static const u8 sText_Trainer1UsedItem[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME}\nused {B_LAST_ITEM}!");
static const u8 sText_Trainer1UsedItem[] = _("{B_ATK_TRAINER_CLASS} {B_ATK_TRAINER_NAME}\nused {B_LAST_ITEM}!");
static const u8 sText_TrainerBlockedBall[] = _("The TRAINER blocked the BALL!");
static const u8 sText_DontBeAThief[] = _("Don't be a thief!");
static const u8 sText_ItDodgedBall[] = _("It dodged the thrown BALL!\nThis POKéMON can't be caught!");
@ -783,9 +783,15 @@ static const u8 sText_ShellTrapDidntWork[] = _("{B_ATK_NAME_WITH_PREFIX}'s shell
static const u8 sText_CouldntFullyProtect[] = _("{B_DEF_NAME_WITH_PREFIX} couldn't fully protect\nitself and got hurt!");
static const u8 sText_StockpiledEffectWoreOff[] = _("{B_ATK_NAME_WITH_PREFIX}'s stockpiled\neffect wore off!");
static const u8 sText_PkmnRevivedReadyToFight[] = _("{B_BUFF1} was revived and\nis ready to fight again!");
static const u8 sText_ItemRestoredSpeciesHealth[] = _("{B_LAST_ITEM} restored\n{B_BUFF1}'s health!");
static const u8 sText_ItemCuredSpeciesStatus[] = _("{B_LAST_ITEM} cured\n{B_BUFF1}'s status!");
static const u8 sText_ItemRestoredSpeciesPP[] = _("{B_LAST_ITEM} restored\n{B_BUFF1}'s PP!");
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{
[STRINGID_ITEMRESTOREDSPECIESHEALTH - BATTLESTRINGS_TABLE_START] = sText_ItemRestoredSpeciesHealth,
[STRINGID_ITEMCUREDSPECIESSTATUS - BATTLESTRINGS_TABLE_START] = sText_ItemCuredSpeciesStatus,
[STRINGID_ITEMRESTOREDSPECIESPP - BATTLESTRINGS_TABLE_START] = sText_ItemRestoredSpeciesPP,
[STRINGID_PKMNREVIVEDREADYTOFIGHT - BATTLESTRINGS_TABLE_START] = sText_PkmnRevivedReadyToFight,
[STRINGID_STOCKPILEDEFFECTWOREOFF - BATTLESTRINGS_TABLE_START] = sText_StockpiledEffectWoreOff,
[STRINGID_COULDNTFULLYPROTECT - BATTLESTRINGS_TABLE_START] = sText_CouldntFullyProtect,
@ -1424,6 +1430,11 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
[STRINGID_PKMNSABILITYPREVENTSABILITY - BATTLESTRINGS_TABLE_START] = sText_PkmnsAbilityPreventsAbility,
};
const u16 gTrainerUsedItemStringIds[] =
{
STRINGID_PLAYERUSEDITEM, STRINGID_TRAINER1USEDITEM
};
const u16 gZEffectStringIds[] =
{
[B_MSG_Z_RESET_STATS] = STRINGID_ZMOVERESETSSTATS,
@ -1820,16 +1831,6 @@ const u16 gSafariPokeblockResultStringIds[] =
[B_MSG_MON_IGNORED] = STRINGID_PKMNIGNOREDX
};
const u16 gTrainerItemCuredStatusStringIds[] =
{
[AI_HEAL_CONFUSION] = STRINGID_PKMNSITEMSNAPPEDOUT,
[AI_HEAL_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS,
[AI_HEAL_FREEZE] = STRINGID_PKMNSITEMDEFROSTEDIT,
[AI_HEAL_BURN] = STRINGID_PKMNSITEMHEALEDBURN,
[AI_HEAL_POISON] = STRINGID_PKMNSITEMCUREDPOISON,
[AI_HEAL_SLEEP] = STRINGID_PKMNSITEMWOKEIT
};
const u16 gBerryEffectStringIds[] =
{
[B_MSG_CURED_PROBLEM] = STRINGID_PKMNSITEMCUREDPROBLEM,

View File

@ -1299,11 +1299,18 @@ static void TryCloseBagToGiveItem(u8 taskId)
static void BagAction_UseInBattle(u8 taskId)
{
if (ItemId_GetBattleFunc(gSpecialVar_ItemId) != NULL)
{
// Safety check
u16 type = ItemId_GetType(gSpecialVar_ItemId);
if (!ItemId_GetBattleUsage(gSpecialVar_ItemId))
return;
CloseMenuActionWindow();
ItemId_GetBattleFunc(gSpecialVar_ItemId)(taskId);
}
if (type == ITEM_USE_BAG_MENU)
ItemUseInBattle_BagMenu(taskId);
else if (type == ITEM_USE_PARTY_MENU)
ItemUseInBattle_PartyMenu(taskId);
else if (type == ITEM_USE_PARTY_MENU_MOVES)
ItemUseInBattle_PartyMenuChooseMove(taskId);
}
static void Task_BeginItemSwap(u8 taskId)

View File

@ -52,6 +52,7 @@
#include "constants/battle_string_ids.h"
#include "constants/hold_effects.h"
#include "constants/items.h"
#include "constants/item_effects.h"
#include "constants/map_types.h"
#include "constants/moves.h"
#include "constants/party_menu.h"
@ -11264,7 +11265,7 @@ static void Cmd_various(void)
// Open party menu, wait to go to next instruction.
else
{
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CHOOSE_FAINTED_MON, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]);
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CHOOSE_FAINTED_MON, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gBattlerAttacker]);
MarkBattlerForControllerExec(gBattlerAttacker);
}
return;
@ -16427,3 +16428,144 @@ u8 GetFirstFaintedPartyIndex(u8 battlerId)
// Returns PARTY_SIZE if none found.
return PARTY_SIZE;
}
void BS_ItemRestoreHP(void) {
NATIVE_ARGS();
u16 healAmount;
u32 battlerId = MAX_BATTLERS_COUNT;
u32 healParam = GetItemEffect(gLastUsedItem)[6];
u32 side = GetBattlerSide(gBattlerAttacker);
struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty;
u16 hp = GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_HP);
u16 maxHP = GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_MAX_HP);
gBattleCommunication[MULTIUSE_STATE] = 0;
// Track the number of Revives used in a battle.
if (hp == 0 && side == B_SIDE_PLAYER && gBattleResults.numRevivesUsed < 255)
gBattleResults.numRevivesUsed++;
// Check if the recipient is an active battler.
if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker])
battlerId = gBattlerAttacker;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)])
battlerId = BATTLE_PARTNER(gBattlerAttacker);
// Get amount to heal.
switch (healParam)
{
case ITEM6_HEAL_HP_FULL:
healAmount = maxHP;
break;
case ITEM6_HEAL_HP_HALF:
healAmount = maxHP / 2;
break;
case ITEM6_HEAL_HP_QUARTER:
healAmount = maxHP / 4;
break;
default:
healAmount = healParam;
break;
}
if (hp + healAmount > maxHP)
healAmount = maxHP - hp;
// Heal is applied as move damage if battler is active.
if (battlerId != MAX_BATTLERS_COUNT && hp != 0)
{
gBattleMoveDamage = -healAmount;
}
else
{
hp += healAmount;
SetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_HP, &hp);
// Revived battlers on the field need to be brought back.
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && battlerId != MAX_BATTLERS_COUNT)
{
gAbsentBattlerFlags &= ~gBitTable[battlerId];
gBattleCommunication[MULTIUSE_STATE] = TRUE;
}
}
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES));
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_ItemCureStatus(void) {
NATIVE_ARGS();
struct Pokemon *party = (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty;
// Heal Status1 conditions.
HealStatusConditions(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], gBattleStruct->itemPartyIndex[gBattlerAttacker], GetItemStatus1Mask(gLastUsedItem), gBattlerAttacker);
// Heal Status2 conditions if battler is active.
if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker])
gBattleMons[gBattleStruct->itemPartyIndex[gBattlerAttacker]].status2 &= ~GetItemStatus2Mask(gLastUsedItem);
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)])
{
gBattleMons[gBattlerAttacker].status2 &= ~GetItemStatus2Mask(gLastUsedItem);
gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker);
if (GetItemStatus1Mask(gLastUsedItem) & STATUS1_SLEEP)
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE;
}
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES));
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_ItemIncreaseStat(void) {
NATIVE_ARGS();
u16 statId = GetItemEffect(gLastUsedItem)[1];
u16 stages = ItemId_GetHoldEffectParam(gLastUsedItem);
SET_STATCHANGER(statId, stages, FALSE);
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_ItemRestorePP(void) {
NATIVE_ARGS();
const u8 *effect = GetItemEffect(gLastUsedItem);
u32 i, pp, maxPP, moveId;
u32 loopEnd = MAX_MON_MOVES;
u32 battlerId = MAX_BATTLERS_COUNT;
struct Pokemon *mon = (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) ? &gPlayerParty[gBattleStruct->itemPartyIndex[gBattlerAttacker]] : &gEnemyParty[gBattleStruct->itemPartyIndex[gBattlerAttacker]];
// Check whether to apply to all moves.
if (effect[4] & ITEM4_HEAL_PP_ONE)
{
i = gChosenMovePos;
loopEnd = gChosenMovePos + 1;
}
// Check if the recipient is an active battler.
if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker])
battlerId = gBattlerAttacker;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)])
battlerId = BATTLE_PARTNER(gBattlerAttacker);
// Heal PP!
for (i = 0; i < loopEnd; i++)
{
pp = GetMonData(mon, MON_DATA_PP1 + i, NULL);
moveId = GetMonData(mon, MON_DATA_MOVE1 + i, NULL);
maxPP = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), i);
if (pp != maxPP)
{
pp += effect[6];
if (pp > maxPP)
pp = maxPP;
SetMonData(mon, MON_DATA_PP1 + i, &pp);
// Update battler PP if needed.
if (battlerId != MAX_BATTLERS_COUNT
&& gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[battlerId]
&& MOVE_IS_PERMANENT(battlerId, i))
{
gBattleMons[battlerId].pp[i] = pp;
}
}
}
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(mon, MON_DATA_SPECIES));
gBattlescriptCurrInstr = cmd->nextInstr;
}

View File

@ -21,6 +21,7 @@
#include "sprite.h"
#include "string_util.h"
#include "task.h"
#include "test_runner.h"
#include "trig.h"
#include "window.h"
#include "battle_message.h"
@ -550,93 +551,13 @@ void HandleAction_Switch(void)
void HandleAction_UseItem(void)
{
gBattlerAttacker = gBattlerTarget = gBattlerByTurnOrder[gCurrentTurnActionNumber];
gActiveBattler = gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber];
gBattle_BG0_X = 0;
gBattle_BG0_Y = 0;
ClearFuryCutterDestinyBondGrudge(gBattlerAttacker);
gLastUsedItem = gBattleResources->bufferB[gBattlerAttacker][1] | (gBattleResources->bufferB[gBattlerAttacker][2] << 8);
if (gLastUsedItem <= LAST_BALL) // is ball
{
gBattlescriptCurrInstr = BattleScript_BallThrow;
}
else if (gLastUsedItem == ITEM_POKE_DOLL || gLastUsedItem == ITEM_FLUFFY_TAIL)
{
gBattlescriptCurrInstr = gBattlescriptsForRunningByItem[0]; // BattleScript_RunByUsingItem
}
else if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
{
gBattlescriptCurrInstr = gBattlescriptsForUsingItem[0]; // BattleScript_PlayerUsesItem
}
else
{
gBattleScripting.battler = gBattlerAttacker;
switch (*(gBattleStruct->AI_itemType + (gBattlerAttacker >> 1)))
{
case AI_ITEM_FULL_RESTORE:
case AI_ITEM_HEAL_HP:
break;
case AI_ITEM_CURE_CONDITION:
gBattleCommunication[MULTISTRING_CHOOSER] = AI_HEAL_CONFUSION;
if (*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & (1 << AI_HEAL_CONFUSION))
{
if (*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 0x3E)
gBattleCommunication[MULTISTRING_CHOOSER] = AI_HEAL_SLEEP;
}
else
{
// Check for other statuses, stopping at first (shouldn't be more than one)
while (!(*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) & 1))
{
*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) >>= 1;
gBattleCommunication[MULTISTRING_CHOOSER]++;
// MULTISTRING_CHOOSER will be either AI_HEAL_PARALYSIS, AI_HEAL_FREEZE,
// AI_HEAL_BURN, AI_HEAL_POISON, or AI_HEAL_SLEEP
}
}
break;
case AI_ITEM_X_STAT:
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_ROSE_ITEM;
if (*(gBattleStruct->AI_itemFlags + (gBattlerAttacker >> 1)) & (1 << AI_DIRE_HIT))
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_USED_DIRE_HIT;
}
else
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK)
PREPARE_STRING_BUFFER(gBattleTextBuff2, CHAR_X)
while (!((*(gBattleStruct->AI_itemFlags + (gBattlerAttacker >> 1))) & 1))
{
*(gBattleStruct->AI_itemFlags + gBattlerAttacker / 2) >>= 1;
gBattleTextBuff1[2]++;
}
gBattleScripting.animArg1 = gBattleTextBuff1[2] + 14;
gBattleScripting.animArg2 = 0;
}
break;
case AI_ITEM_GUARD_SPEC:
// It seems probable that at some point there was a special message for
// an AI trainer using Guard Spec in a double battle.
// There isn't now however, and the assignment to 2 below goes out of
// bounds for gMistUsedStringIds and instead prints "{mon} is getting pumped"
// from the next table, gFocusEnergyUsedStringIds.
// In any case this isn't an issue in the retail version, as no trainers
// are ever given any Guard Spec to use.
#ifndef UBFIX
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
else
#endif
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_MIST;
break;
}
gBattlescriptCurrInstr = gBattlescriptsForUsingItem[*(gBattleStruct->AI_itemType + gBattlerAttacker / 2)];
}
gBattlescriptCurrInstr = gBattlescriptsForUsingItem[ItemId_GetBattleUsage(gLastUsedItem) - 1];
gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT;
}
@ -914,7 +835,7 @@ void HandleAction_ActionFinished(void)
u32 i, j;
bool32 afterYouActive = gSpecialStatuses[gBattlerByTurnOrder[gCurrentTurnActionNumber + 1]].afterYou;
#endif
*(gBattleStruct->monToSwitchIntoId + gBattlerByTurnOrder[gCurrentTurnActionNumber]) = PARTY_SIZE;
*(gBattleStruct->monToSwitchIntoId + gBattlerByTurnOrder[gCurrentTurnActionNumber]) = gSelectedMonPartyId = PARTY_SIZE;
gCurrentTurnActionNumber++;
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
SpecialStatusesClear();
@ -8207,7 +8128,6 @@ u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating)
return ItemId_GetHoldEffect(gBattleMons[battlerId].item);
}
//
static u32 GetBattlerItemHoldEffectParam(u8 battlerId, u16 item)
{
if (item == ITEM_ENIGMA_BERRY_E_READER)

View File

@ -20,9 +20,8 @@ const struct Item gItems[] =
.price = 200,
.description = sPokeBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_POKE_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_POKE_BALL - FIRST_BALL,
},
@ -33,9 +32,8 @@ const struct Item gItems[] =
.price = 600,
.description = sGreatBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_GREAT_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_GREAT_BALL - FIRST_BALL,
},
@ -46,9 +44,8 @@ const struct Item gItems[] =
.price = 800,
.description = sUltraBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_ULTRA_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_ULTRA_BALL - FIRST_BALL,
},
@ -59,9 +56,8 @@ const struct Item gItems[] =
.price = 0,
.description = sMasterBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_MASTER_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_MASTER_BALL - FIRST_BALL,
},
@ -72,9 +68,8 @@ const struct Item gItems[] =
.price = 20,
.description = sPremierBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_PREMIER_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_PREMIER_BALL - FIRST_BALL,
},
@ -85,9 +80,8 @@ const struct Item gItems[] =
.price = 300,
.description = sHealBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_HEAL_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_HEAL_BALL - FIRST_BALL,
},
@ -98,9 +92,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sNetBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_NET_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_NET_BALL - FIRST_BALL,
},
@ -111,9 +104,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sNestBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_NEST_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_NEST_BALL - FIRST_BALL,
},
@ -124,9 +116,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sDiveBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_DIVE_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_DIVE_BALL - FIRST_BALL,
},
@ -137,9 +128,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sDuskBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_DUSK_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_DUSK_BALL - FIRST_BALL,
},
@ -150,9 +140,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sTimerBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_TIMER_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_TIMER_BALL - FIRST_BALL,
},
@ -163,9 +152,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sQuickBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_QUICK_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_QUICK_BALL - FIRST_BALL,
},
@ -176,9 +164,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sRepeatBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_REPEAT_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_REPEAT_BALL - FIRST_BALL,
},
@ -189,9 +176,8 @@ const struct Item gItems[] =
.price = 1000,
.description = sLuxuryBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_LUXURY_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_LUXURY_BALL - FIRST_BALL,
},
@ -202,9 +188,8 @@ const struct Item gItems[] =
.price = 0,
.description = sLevelBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_LEVEL_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_LEVEL_BALL - FIRST_BALL,
},
@ -215,9 +200,8 @@ const struct Item gItems[] =
.price = 0,
.description = sLureBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_LURE_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_LURE_BALL - FIRST_BALL,
},
@ -228,9 +212,8 @@ const struct Item gItems[] =
.price = 0,
.description = sMoonBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_MOON_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_MOON_BALL - FIRST_BALL,
},
@ -241,9 +224,8 @@ const struct Item gItems[] =
.price = 0,
.description = sFriendBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_FRIEND_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_FRIEND_BALL - FIRST_BALL,
},
@ -254,9 +236,8 @@ const struct Item gItems[] =
.price = 0,
.description = sLoveBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_LOVE_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_LOVE_BALL - FIRST_BALL,
},
@ -267,9 +248,8 @@ const struct Item gItems[] =
.price = 0,
.description = sFastBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_FAST_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_FAST_BALL - FIRST_BALL,
},
@ -280,9 +260,8 @@ const struct Item gItems[] =
.price = 0,
.description = sHeavyBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_HEAVY_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_HEAVY_BALL - FIRST_BALL,
},
@ -293,9 +272,8 @@ const struct Item gItems[] =
.price = 0,
.description = sDreamBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_DREAM_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_DREAM_BALL - FIRST_BALL,
},
@ -306,9 +284,8 @@ const struct Item gItems[] =
.price = 0,
.description = sSafariBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_SAFARI_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_SAFARI_BALL - FIRST_BALL,
},
@ -319,9 +296,8 @@ const struct Item gItems[] =
.price = 0,
.description = sSportBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_SPORT_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_SPORT_BALL - FIRST_BALL,
},
@ -332,9 +308,8 @@ const struct Item gItems[] =
.price = 0,
.description = sParkBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_PARK_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_PARK_BALL - FIRST_BALL,
},
@ -345,9 +320,8 @@ const struct Item gItems[] =
.price = 0,
.description = sBeastBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_BEAST_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_BEAST_BALL - FIRST_BALL,
},
@ -358,9 +332,8 @@ const struct Item gItems[] =
.price = 0,
.description = sCherishBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_CHERISH_BALL - FIRST_BALL,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
.secondaryId = ITEM_CHERISH_BALL - FIRST_BALL,
},
@ -376,8 +349,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -391,8 +363,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -406,8 +377,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -421,8 +391,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -436,8 +405,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_HEAL_AND_CURE_STATUS,
.flingPower = 30,
},
@ -450,8 +418,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_REVIVE,
.flingPower = 30,
},
@ -464,8 +431,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_REVIVE,
.flingPower = 30,
},
@ -479,8 +445,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -494,8 +459,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -509,8 +473,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -524,8 +487,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -538,8 +500,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -552,8 +513,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -566,8 +526,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -580,8 +539,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_REVIVE,
.flingPower = 30,
},
@ -594,8 +552,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -608,8 +565,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -622,8 +578,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -636,8 +591,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -650,8 +604,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -664,8 +617,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -677,10 +629,9 @@ const struct Item gItems[] =
.holdEffectParam = 10,
.description = sEtherDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.type = ITEM_USE_PARTY_MENU_MOVES,
.fieldUseFunc = ItemUseOutOfBattle_PPRecovery,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_PPRecovery,
.battleUsage = EFFECT_ITEM_RESTORE_PP,
.flingPower = 30,
},
@ -692,10 +643,9 @@ const struct Item gItems[] =
.holdEffectParam = 255,
.description = sMaxEtherDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.type = ITEM_USE_PARTY_MENU_MOVES,
.fieldUseFunc = ItemUseOutOfBattle_PPRecovery,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_PPRecovery,
.battleUsage = EFFECT_ITEM_RESTORE_PP,
.flingPower = 30,
},
@ -709,8 +659,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_PPRecovery,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_PPRecovery,
.battleUsage = EFFECT_ITEM_RESTORE_PP,
.flingPower = 30,
},
@ -724,8 +673,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_PPRecovery,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_PPRecovery,
.battleUsage = EFFECT_ITEM_RESTORE_PP,
.flingPower = 30,
},
@ -740,8 +688,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -767,8 +714,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 30,
},
@ -781,8 +727,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_REVIVE,
.flingPower = 30,
},
@ -797,8 +742,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -811,8 +755,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -825,8 +768,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -839,8 +781,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -853,8 +794,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -867,8 +807,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -881,8 +820,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -895,8 +833,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -1454,8 +1391,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -1468,8 +1404,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -1482,8 +1417,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 30,
},
@ -1618,17 +1552,19 @@ const struct Item gItems[] =
// X Items
#define X_ITEM_STAGES (B_X_ITEMS_BUFF >= GEN_7) ? 2 : 1
[ITEM_X_ATTACK] =
{
.name = _("X Attack"),
.itemId = ITEM_X_ATTACK,
.price = 1000,
.holdEffectParam = X_ITEM_STAGES,
.description = sXAttackDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_INCREASE_STAT,
.flingPower = 30,
},
@ -1637,12 +1573,12 @@ const struct Item gItems[] =
.name = _("X Defense"),
.itemId = ITEM_X_DEFENSE,
.price = 2000,
.holdEffectParam = X_ITEM_STAGES,
.description = sXDefenseDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_INCREASE_STAT,
.flingPower = 30,
},
@ -1651,12 +1587,12 @@ const struct Item gItems[] =
.name = _("X Sp. Atk"),
.itemId = ITEM_X_SP_ATK,
.price = 1000,
.holdEffectParam = X_ITEM_STAGES,
.description = sXSpAtkDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_INCREASE_STAT,
.flingPower = 30,
},
@ -1665,12 +1601,12 @@ const struct Item gItems[] =
.name = _("X Sp. Def"),
.itemId = ITEM_X_SP_DEF,
.price = 2000,
.holdEffectParam = X_ITEM_STAGES,
.description = sXSpDefDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_INCREASE_STAT,
.flingPower = 30,
},
@ -1679,12 +1615,12 @@ const struct Item gItems[] =
.name = _("X Speed"),
.itemId = ITEM_X_SPEED,
.price = 1000,
.holdEffectParam = X_ITEM_STAGES,
.description = sXSpeedDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_INCREASE_STAT,
.flingPower = 30,
},
@ -1693,12 +1629,12 @@ const struct Item gItems[] =
.name = _("X Accuracy"),
.itemId = ITEM_X_ACCURACY,
.price = 1000,
.holdEffectParam = X_ITEM_STAGES,
.description = sXAccuracyDesc,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_INCREASE_STAT,
.flingPower = 30,
},
@ -1711,8 +1647,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_SET_FOCUS_ENERGY,
.flingPower = 30,
},
@ -1725,8 +1660,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease,
.battleUsage = EFFECT_ITEM_SET_MIST,
.flingPower = 30,
},
@ -1739,8 +1673,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_Escape,
.battleUsage = EFFECT_ITEM_ESCAPE,
.flingPower = 30,
},
@ -1753,8 +1686,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_Escape,
.battleUsage = EFFECT_ITEM_ESCAPE,
.flingPower = 30,
},
@ -1767,8 +1699,7 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_Escape,
.battleUsage = EFFECT_ITEM_ESCAPE,
.flingPower = 30,
},
@ -1781,11 +1712,12 @@ const struct Item gItems[] =
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_StatIncrease, // Todo
.battleUsage = EFFECT_ITEM_INCREASE_ALL_STATS,
.flingPower = 30,
},
#undef X_ITEM_STAGES
// Treasures
[ITEM_BOTTLE_CAP] =
@ -6874,8 +6806,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 10,
},
@ -6889,8 +6820,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 10,
},
@ -6904,8 +6834,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 10,
},
@ -6919,8 +6848,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 10,
},
@ -6934,8 +6862,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 10,
},
@ -6948,10 +6875,9 @@ const struct Item gItems[] =
.holdEffectParam = 10,
.description = sLeppaBerryDesc,
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.type = ITEM_USE_PARTY_MENU_MOVES,
.fieldUseFunc = ItemUseOutOfBattle_PPRecovery,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_PPRecovery,
.battleUsage = EFFECT_ITEM_RESTORE_PP,
.flingPower = 10,
},
@ -6966,8 +6892,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 10,
},
@ -6981,8 +6906,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 10,
},
@ -6996,8 +6920,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_CURE_STATUS,
.flingPower = 10,
},
@ -7017,8 +6940,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_Medicine,
.battleUsage = EFFECT_ITEM_RESTORE_HP,
.flingPower = 10,
},
@ -7794,8 +7716,7 @@ const struct Item gItems[] =
.pocket = POCKET_BERRIES,
.type = ITEM_USE_BAG_MENU, // Type handled by ItemUseOutOfBattle_EnigmaBerry
.fieldUseFunc = ItemUseOutOfBattle_EnigmaBerry,
.battleUsage = ITEM_B_USE_MEDICINE,
.battleUseFunc = ItemUseInBattle_EnigmaBerry,
.battleUsage = EFFECT_ITEM_ENIGMA_BERRY_EREADER,
.flingPower = 10,
},

View File

@ -533,8 +533,6 @@ const u8 *const gItemEffectTable[ITEMS_COUNT] =
[ITEM_DIRE_HIT] = gItemEffect_DireHit,
[ITEM_GUARD_SPEC] = gItemEffect_GuardSpec,
//[ITEM_MAX_MUSHROOMS] = gItemEffect_MaxMushrooms, // Todo
// Evolution Items
[ITEM_FIRE_STONE] = gItemEffect_EvoItem,
[ITEM_WATER_STONE] = gItemEffect_EvoItem,

View File

@ -7,12 +7,15 @@
#include "malloc.h"
#include "secret_base.h"
#include "item_menu.h"
#include "party_menu.h"
#include "strings.h"
#include "load_save.h"
#include "item_use.h"
#include "battle_pyramid.h"
#include "battle_pyramid_bag.h"
#include "constants/battle.h"
#include "constants/items.h"
#include "constants/item_effects.h"
#include "constants/hold_effects.h"
static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count);
@ -922,14 +925,36 @@ ItemUseFunc ItemId_GetFieldFunc(u16 itemId)
return gItems[SanitizeItemId(itemId)].fieldUseFunc;
}
// Returns an item's battle effect script ID.
u8 ItemId_GetBattleUsage(u16 itemId)
{
return gItems[SanitizeItemId(itemId)].battleUsage;
}
ItemUseFunc ItemId_GetBattleFunc(u16 itemId)
u16 item = SanitizeItemId(itemId);
// Handle E-Reader berries.
if (item == ITEM_ENIGMA_BERRY_E_READER)
{
return gItems[SanitizeItemId(itemId)].battleUseFunc;
switch (GetItemEffectType(gSpecialVar_ItemId))
{
case ITEM_EFFECT_X_ITEM:
return EFFECT_ITEM_INCREASE_STAT;
case ITEM_EFFECT_HEAL_HP:
return EFFECT_ITEM_RESTORE_HP;
case ITEM_EFFECT_CURE_POISON:
case ITEM_EFFECT_CURE_SLEEP:
case ITEM_EFFECT_CURE_BURN:
case ITEM_EFFECT_CURE_FREEZE:
case ITEM_EFFECT_CURE_PARALYSIS:
case ITEM_EFFECT_CURE_ALL_STATUS:
case ITEM_EFFECT_CURE_CONFUSION:
case ITEM_EFFECT_CURE_INFATUATION:
return EFFECT_ITEM_CURE_STATUS;
case ITEM_EFFECT_HEAL_PP:
return EFFECT_ITEM_RESTORE_PP;
default:
return 0;
}
}
else
return gItems[item].battleUsage;
}
u8 ItemId_GetSecondaryId(u16 itemId)
@ -941,3 +966,36 @@ u8 ItemId_GetFlingPower(u16 itemId)
{
return gItems[SanitizeItemId(itemId)].flingPower;
}
u32 GetItemStatus1Mask(u16 itemId)
{
const u8 *effect = GetItemEffect(itemId);
switch (effect[3])
{
case ITEM3_FREEZE:
return STATUS1_FREEZE;
case ITEM3_BURN:
return STATUS1_BURN;
case ITEM3_POISON:
return STATUS1_POISON | STATUS1_TOXIC_POISON;
case ITEM3_SLEEP:
return STATUS1_SLEEP;
case ITEM3_STATUS_ALL:
return STATUS1_ANY;
}
return 0;
}
u32 GetItemStatus2Mask(u16 itemId)
{
const u8 *effect = GetItemEffect(itemId);
if (effect[3] & ITEM3_STATUS_ALL)
return STATUS2_INFATUATION | STATUS2_CONFUSION;
else if (effect[0] & ITEM0_INFATUATION)
return STATUS2_INFATUATION;
else if (effect[3] & ITEM3_CONFUSION)
return STATUS2_CONFUSION;
else
return 0;
}

View File

@ -1985,11 +1985,18 @@ static void ItemMenu_Cancel(u8 taskId)
static void ItemMenu_UseInBattle(u8 taskId)
{
if (ItemId_GetBattleFunc(gSpecialVar_ItemId))
{
// Safety check
u16 type = ItemId_GetType(gSpecialVar_ItemId);
if (!ItemId_GetBattleUsage(gSpecialVar_ItemId))
return;
RemoveContextWindow();
ItemId_GetBattleFunc(gSpecialVar_ItemId)(taskId);
}
if (type == ITEM_USE_BAG_MENU)
ItemUseInBattle_BagMenu(taskId);
else if (type == ITEM_USE_PARTY_MENU)
ItemUseInBattle_PartyMenu(taskId);
else if (type == ITEM_USE_PARTY_MENU_MOVES)
ItemUseInBattle_PartyMenuChooseMove(taskId);
}
void CB2_ReturnToBagMenuPocket(void)

View File

@ -75,6 +75,7 @@ static void Task_CloseCantUseKeyItemMessage(u8);
static void SetDistanceOfClosestHiddenItem(u8, s16, s16);
static void CB2_OpenPokeblockFromBag(void);
static void ItemUseOnFieldCB_Honey(u8 taskId);
static bool32 CannotUseBagBattleItem(u16 itemId);
// EWRAM variables
EWRAM_DATA static void(*sItemUseOnFieldCB)(u8 taskId) = NULL;
@ -89,6 +90,7 @@ static const MainCallback sItemUseCallbacks[] =
[ITEM_USE_PARTY_MENU - 1] = CB2_ShowPartyMenuForItemUse,
[ITEM_USE_FIELD - 1] = CB2_ReturnToField,
[ITEM_USE_PBLOCK_CASE - 1] = NULL,
[ITEM_USE_PARTY_MENU_MOVES - 1] = CB2_ShowPartyMenuForItemUse,
};
static const u8 sClockwiseDirections[] = {DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST};
@ -1105,25 +1107,6 @@ static void Task_UseStatIncreaseItem(u8 taskId)
}
}
// e.g. X Attack, Guard Spec
void ItemUseInBattle_StatIncrease(u8 taskId)
{
u16 partyId = gBattlerPartyIndexes[gBattlerInMenuId];
if (ExecuteTableBasedItemEffect(&gPlayerParty[partyId], gSpecialVar_ItemId, partyId, 0) != FALSE)
{
if (!InBattlePyramid())
DisplayItemMessage(taskId, FONT_NORMAL, gText_WontHaveEffect, CloseItemMessage);
else
DisplayItemMessageInBattlePyramid(taskId, gText_WontHaveEffect, Task_CloseBattlePyramidBagMessage);
}
else
{
gTasks[taskId].func = Task_UseStatIncreaseItem;
gTasks[taskId].data[8] = 0;
}
}
static void ItemUseInBattle_ShowPartyMenu(u8 taskId)
{
if (!InBattlePyramid())
@ -1138,41 +1121,119 @@ static void ItemUseInBattle_ShowPartyMenu(u8 taskId)
}
}
void ItemUseInBattle_Medicine(u8 taskId)
void ItemUseInBattle_PartyMenu(u8 taskId)
{
gItemUseCB = ItemUseCB_Medicine;
gItemUseCB = ItemUseCB_BattleScript;
ItemUseInBattle_ShowPartyMenu(taskId);
}
// Unused. Sacred Ash cannot be used in battle
void ItemUseInBattle_SacredAsh(u8 taskId)
void ItemUseInBattle_PartyMenuChooseMove(u8 taskId)
{
gItemUseCB = ItemUseCB_SacredAsh;
gItemUseCB = ItemUseCB_BattleChooseMove;
ItemUseInBattle_ShowPartyMenu(taskId);
}
void ItemUseInBattle_PPRecovery(u8 taskId)
// Returns whether an item can be used in battle and sets the fail text.
static bool32 CannotUseBagBattleItem(u16 itemId)
{
gItemUseCB = ItemUseCB_PPRecovery;
ItemUseInBattle_ShowPartyMenu(taskId);
u8 cannotUse = FALSE;
u16 battleUsage = ItemId_GetBattleUsage(itemId);
const u8* failStr = NULL;
// Embargo Check
if ((gPartyMenu.slotId == 0 && gStatuses3[B_POSITION_PLAYER_LEFT] & STATUS3_EMBARGO)
|| (gPartyMenu.slotId == 1 && gStatuses3[B_POSITION_PLAYER_RIGHT] & STATUS3_EMBARGO))
{
return TRUE;
}
// X-Items
if (battleUsage == EFFECT_ITEM_INCREASE_STAT
&& gBattleMons[gBattlerInMenuId].statStages[gItemEffectTable[itemId][1]] == MAX_STAT_STAGE)
{
cannotUse++;
}
// Dire Hit
if (battleUsage == EFFECT_ITEM_SET_FOCUS_ENERGY
&& !(gBattleMons[gBattlerInMenuId].status2 & STATUS2_FOCUS_ENERGY))
{
cannotUse++;
}
// Guard Spec
if (battleUsage == EFFECT_ITEM_SET_MIST
&& gSideStatuses[GetBattlerSide(gBattlerInMenuId)] & SIDE_STATUS_MIST)
{
cannotUse++;
}
// Escape Items
if (battleUsage == EFFECT_ITEM_ESCAPE
&& gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
cannotUse++;
}
// Poke Balls
if (battleUsage == EFFECT_ITEM_THROW_BALL)
{
switch (GetBallThrowableState())
{
case BALL_THROW_UNABLE_TWO_MONS:
failStr = sText_CantThrowPokeBall_TwoMons;
cannotUse++;
break;
case BALL_THROW_UNABLE_NO_ROOM:
failStr = gText_BoxFull;
cannotUse++;
break;
#if B_SEMI_INVULNERABLE_CATCH >= GEN_4
case BALL_THROW_UNABLE_SEMI_INVULNERABLE:
failStr = sText_CantThrowPokeBall_SemiInvulnerable;
cannotUse++;
break;
#endif
case BALL_THROW_UNABLE_DISABLED_FLAG:
failStr = sText_CantThrowPokeBall_Disabled;
cannotUse++;
break;
}
}
// Max Mushrooms
if (battleUsage == EFFECT_ITEM_INCREASE_ALL_STATS)
{
u32 i;
for (i = 1; i < NUM_STATS; i++)
{
if (CompareStat(gBattlerInMenuId, i, MAX_STAT_STAGE, CMP_EQUAL))
{
cannotUse++;
break;
}
}
}
// Fluffy Tail / Poke Doll
void ItemUseInBattle_Escape(u8 taskId)
{
if (failStr != NULL)
StringExpandPlaceholders(gStringVar4, failStr);
else
StringExpandPlaceholders(gStringVar4, gText_WontHaveEffect);
return cannotUse;
}
if((gBattleTypeFlags & BATTLE_TYPE_TRAINER) == FALSE)
void ItemUseInBattle_BagMenu(u8 taskId)
{
if (CannotUseBagBattleItem(gSpecialVar_ItemId))
{
if (!InBattlePyramid())
DisplayItemMessage(taskId, FONT_NORMAL, gStringVar4, CloseItemMessage);
else
DisplayItemMessageInBattlePyramid(taskId, gStringVar4, Task_CloseBattlePyramidBagMessage);
}
else
{
PlaySE(SE_SELECT);
RemoveUsedItem();
if (!InBattlePyramid())
DisplayItemMessage(taskId, FONT_NORMAL, gStringVar4, Task_FadeAndCloseBagMenu);
else
DisplayItemMessageInBattlePyramid(taskId, gStringVar4, CloseBattlePyramidBag);
}
else
{
DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
}
}
void ItemUseOutOfBattle_EnigmaBerry(u8 taskId)
@ -1219,33 +1280,6 @@ void ItemUseOutOfBattle_EnigmaBerry(u8 taskId)
}
}
void ItemUseInBattle_EnigmaBerry(u8 taskId)
{
switch (GetItemEffectType(gSpecialVar_ItemId))
{
case ITEM_EFFECT_X_ITEM:
ItemUseInBattle_StatIncrease(taskId);
break;
case ITEM_EFFECT_HEAL_HP:
case ITEM_EFFECT_CURE_POISON:
case ITEM_EFFECT_CURE_SLEEP:
case ITEM_EFFECT_CURE_BURN:
case ITEM_EFFECT_CURE_FREEZE:
case ITEM_EFFECT_CURE_PARALYSIS:
case ITEM_EFFECT_CURE_ALL_STATUS:
case ITEM_EFFECT_CURE_CONFUSION:
case ITEM_EFFECT_CURE_INFATUATION:
ItemUseInBattle_Medicine(taskId);
break;
case ITEM_EFFECT_HEAL_PP:
ItemUseInBattle_PPRecovery(taskId);
break;
default:
ItemUseOutOfBattle_CannotUse(taskId);
break;
}
}
void ItemUseOutOfBattle_FormChange(u8 taskId)
{
gItemUseCB = ItemUseCB_FormChange;

View File

@ -390,8 +390,8 @@ static void Task_DisplayHPRestoredMessage(u8);
static u16 ItemEffectToMonEv(struct Pokemon *, u8);
static void ItemEffectToStatString(u8, u8 *);
static void ReturnToUseOnWhichMon(u8);
static void SetSelectedMoveForPPItem(u8);
static void TryUsePPItem(u8);
static void SetSelectedMoveForItem(u8);
static void TryUseItemOnMove(u8);
static void Task_LearnedMove(u8);
static void Task_ReplaceMoveYesNo(u8);
static void Task_DoLearnedMoveFanfareAfterText(u8);
@ -480,6 +480,9 @@ static bool8 SetUpFieldMove_Fly(void);
static bool8 SetUpFieldMove_Waterfall(void);
static bool8 SetUpFieldMove_Dive(void);
void TryItemHoldFormChange(struct Pokemon *mon);
static void ShowMoveSelectWindow(u8 slot);
static void Task_HandleWhichMoveInput(u8 taskId);
static bool32 CannotUsePartyBattleItem(u16 itemId, struct Pokemon* mon);
// static const data
#include "data/party_menu.h"
@ -4301,12 +4304,7 @@ static void Task_SetSacredAshCB(u8 taskId)
static bool8 IsHPRecoveryItem(u16 item)
{
const u8 *effect;
if (item == ITEM_ENIGMA_BERRY_E_READER)
effect = gSaveBlock1Ptr->enigmaBerry.itemEffect;
else
effect = gItemEffectTable[item];
const u8 *effect = GetItemEffect(item);
if (effect == NULL)
return FALSE;
@ -4396,18 +4394,97 @@ static bool8 IsItemFlute(u16 item)
return FALSE;
}
static bool8 ExecuteTableBasedItemEffect_(u8 partyMonIndex, u16 item, u8 monMoveIndex)
static bool32 CannotUsePartyBattleItem(u16 itemId, struct Pokemon* mon)
{
if (gMain.inBattle)
u8 i;
u8 cannotUse = FALSE;
u16 battleUsage = ItemId_GetBattleUsage(itemId);
u16 hp = GetMonData(mon, MON_DATA_HP);
// Embargo Check
if ((gPartyMenu.slotId == 0 && gStatuses3[B_POSITION_PLAYER_LEFT] & STATUS3_EMBARGO)
|| (gPartyMenu.slotId == 1 && gStatuses3[B_POSITION_PLAYER_RIGHT] & STATUS3_EMBARGO))
{
if ((partyMonIndex == 0 && gStatuses3[B_POSITION_PLAYER_LEFT] & STATUS3_EMBARGO)
|| (partyMonIndex == 1 && gStatuses3[B_POSITION_PLAYER_RIGHT] & STATUS3_EMBARGO))
return TRUE; // cannot use on this mon
else
return ExecuteTableBasedItemEffect(&gPlayerParty[partyMonIndex], item, GetPartyIdFromBattleSlot(partyMonIndex), monMoveIndex);
return FALSE;
}
// Items that restore HP (Potions, Sitrus Berry, etc.)
if (battleUsage == EFFECT_ITEM_RESTORE_HP && (hp == 0 || hp == GetMonData(mon, MON_DATA_MAX_HP)))
{
cannotUse++;
}
// Items that cure status (Burn Heal, Awakening, etc.)
if (battleUsage == EFFECT_ITEM_CURE_STATUS
&& !((GetMonData(mon, MON_DATA_STATUS) & GetItemStatus1Mask(itemId))
|| (gPartyMenu.slotId == 0 && gBattleMons[gBattlerInMenuId].status2 & GetItemStatus2Mask(itemId))))
{
cannotUse++;
}
// Items that restore HP and cure status (Full Restore)
if (battleUsage == EFFECT_ITEM_HEAL_AND_CURE_STATUS
&& (hp == 0 || hp == GetMonData(mon, MON_DATA_MAX_HP))
&& !((GetMonData(mon, MON_DATA_STATUS) & GetItemStatus1Mask(itemId))
|| (gPartyMenu.slotId == 0 && gBattleMons[gBattlerInMenuId].status2 & GetItemStatus2Mask(itemId))))
{
cannotUse++;
}
// Items that revive a party member
if (battleUsage == EFFECT_ITEM_REVIVE && hp != 0)
{
cannotUse++;
}
// Items that restore PP (Elixir, Ether, Leppa Berry)
if (battleUsage == EFFECT_ITEM_RESTORE_PP)
{
if (GetItemEffect(itemId)[6] == ITEM4_HEAL_PP)
{
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (GetMonData(mon, MON_DATA_PP1 + i) < CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + i), GetMonData(mon, MON_DATA_PP_BONUSES), i));
break;
}
if (i == MAX_MON_MOVES)
cannotUse++;
}
else if (GetMonData(mon, MON_DATA_PP1 + gPartyMenu.data1) == CalculatePPWithBonus(GetMonData(mon, MON_DATA_MOVE1 + gPartyMenu.data1), GetMonData(mon, MON_DATA_PP_BONUSES), gPartyMenu.data1))
{
cannotUse++;
}
}
return cannotUse;
}
// Battle scripts called in HandleAction_UseItem
void ItemUseCB_BattleScript(u8 taskId, TaskFunc task)
{
struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId];
if (CannotUsePartyBattleItem(gSpecialVar_ItemId, mon))
{
gPartyMenuUseExitCallback = FALSE;
PlaySE(SE_SELECT);
DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = task;
}
else
return ExecuteTableBasedItemEffect(&gPlayerParty[partyMonIndex], item, partyMonIndex, monMoveIndex);
{
gBattleStruct->itemPartyIndex[gBattlerInMenuId] = GetPartyIdFromBattleSlot(gPartyMenu.slotId);
gPartyMenuUseExitCallback = TRUE;
PlaySE(SE_SELECT);
CopyItemName(gSpecialVar_ItemId, gStringVar2);
StringExpandPlaceholders(gStringVar4, gText_PlayerUsedVar2);
DisplayPartyMenuMessage(gStringVar4, TRUE);
ScheduleBgCopyTilemapToVram(2);
RemoveBagItem(gSpecialVar_ItemId, 1);
gTasks[taskId].func = task;
}
}
void ItemUseCB_BattleChooseMove(u8 taskId, TaskFunc task)
{
PlaySE(SE_SELECT);
DisplayPartyMenuStdMessage(PARTY_MSG_RESTORE_WHICH_MOVE);
ShowMoveSelectWindow(gPartyMenu.slotId);
gTasks[taskId].func = Task_HandleWhichMoveInput;
}
void ItemUseCB_Medicine(u8 taskId, TaskFunc task)
@ -4430,7 +4507,7 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task)
if (hp == GetMonData(mon, MON_DATA_MAX_HP))
canHeal = FALSE;
}
cannotUse = ExecuteTableBasedItemEffect_(gPartyMenu.slotId, item, 0);
cannotUse = ExecuteTableBasedItemEffect(mon, item, gPartyMenu.slotId, 0);
}
if (cannotUse != FALSE)
@ -4691,7 +4768,7 @@ void ItemUseCB_ReduceEV(u8 taskId, TaskFunc task)
u8 effectType = GetItemEffectType(item);
u16 friendship = GetMonData(mon, MON_DATA_FRIENDSHIP);
u16 ev = ItemEffectToMonEv(mon, effectType);
bool8 cannotUseEffect = ExecuteTableBasedItemEffect_(gPartyMenu.slotId, item, 0);
bool8 cannotUseEffect = ExecuteTableBasedItemEffect(mon, item, gPartyMenu.slotId, 0);
u16 newFriendship = GetMonData(mon, MON_DATA_FRIENDSHIP);
u16 newEv = ItemEffectToMonEv(mon, effectType);
@ -4807,25 +4884,19 @@ static void Task_HandleWhichMoveInput(u8 taskId)
else
{
PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]);
SetSelectedMoveForPPItem(taskId);
SetSelectedMoveForItem(taskId);
}
}
}
void ItemUseCB_PPRecovery(u8 taskId, TaskFunc task)
{
const u8 *effect;
u16 item = gSpecialVar_ItemId;
if (item == ITEM_ENIGMA_BERRY_E_READER)
effect = gSaveBlock1Ptr->enigmaBerry.itemEffect;
else
effect = gItemEffectTable[item];
const u8 *effect = GetItemEffect(gSpecialVar_ItemId);
if (effect == NULL || !(effect[4] & ITEM4_HEAL_PP_ONE))
{
gPartyMenu.data1 = 0;
TryUsePPItem(taskId);
TryUseItemOnMove(taskId);
}
else
{
@ -4836,11 +4907,11 @@ void ItemUseCB_PPRecovery(u8 taskId, TaskFunc task)
}
}
static void SetSelectedMoveForPPItem(u8 taskId)
static void SetSelectedMoveForItem(u8 taskId)
{
PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]);
gPartyMenu.data1 = Menu_GetCursorPos();
TryUsePPItem(taskId);
TryUseItemOnMove(taskId);
}
static void ReturnToUseOnWhichMon(u8 taskId)
@ -4851,15 +4922,42 @@ static void ReturnToUseOnWhichMon(u8 taskId)
DisplayPartyMenuStdMessage(PARTY_MSG_USE_ON_WHICH_MON);
}
static void TryUsePPItem(u8 taskId)
static void TryUseItemOnMove(u8 taskId)
{
struct PartyMenu *ptr = &gPartyMenu;
struct Pokemon *mon = &gPlayerParty[ptr->slotId];
// In battle, set appropriate variables to be used in battle script.
if (gMain.inBattle)
{
if (CannotUsePartyBattleItem(gSpecialVar_ItemId, mon))
{
gPartyMenuUseExitCallback = FALSE;
PlaySE(SE_SELECT);
DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = Task_ClosePartyMenuAfterText;
}
else
{
gBattleStruct->itemPartyIndex[gBattlerInMenuId] = GetPartyIdFromBattleSlot(gPartyMenu.slotId);
gChosenMovePos = ptr->data1;
gPartyMenuUseExitCallback = TRUE;
RemoveBagItem(gSpecialVar_ItemId, 1);
CopyItemName(gSpecialVar_ItemId, gStringVar2);
StringExpandPlaceholders(gStringVar4, gText_PlayerUsedVar2);
DisplayPartyMenuMessage(gStringVar4, TRUE);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = Task_ClosePartyMenuAfterText;
}
}
// Outside of battle, only PP items are used on moves.
else
{
u16 move = MOVE_NONE;
s16 *moveSlot = &gPartyMenu.data1;
u16 item = gSpecialVar_ItemId;
struct PartyMenu *ptr = &gPartyMenu;
struct Pokemon *mon;
if (ExecuteTableBasedItemEffect_(ptr->slotId, item, *moveSlot))
if (ExecuteTableBasedItemEffect(mon, item, ptr->slotId, *moveSlot))
{
gPartyMenuUseExitCallback = FALSE;
PlaySE(SE_SELECT);
@ -4870,7 +4968,6 @@ static void TryUsePPItem(u8 taskId)
else
{
gPartyMenuUseExitCallback = TRUE;
mon = &gPlayerParty[ptr->slotId];
PlaySE(SE_USE_ITEM);
RemoveBagItem(item, 1);
move = GetMonData(mon, MON_DATA_MOVE1 + *moveSlot);
@ -4881,6 +4978,7 @@ static void TryUsePPItem(u8 taskId)
gTasks[taskId].func = Task_ClosePartyMenuAfterText;
}
}
}
void ItemUseCB_PPUp(u8 taskId, TaskFunc task)
{
@ -5192,7 +5290,7 @@ void ItemUseCB_RareCandy(u8 taskId, TaskFunc task)
if (sInitialLevel != MAX_LEVEL)
{
BufferMonStatsToTaskData(mon, arrayPtr);
cannotUseEffect = ExecuteTableBasedItemEffect_(gPartyMenu.slotId, *itemPtr, 0);
cannotUseEffect = ExecuteTableBasedItemEffect(mon, gPartyMenu.slotId, *itemPtr, 0);
BufferMonStatsToTaskData(mon, &ptr->data[NUM_STATS]);
}
else
@ -5459,7 +5557,7 @@ static void UseSacredAsh(u8 taskId)
}
hp = GetMonData(mon, MON_DATA_HP);
if (ExecuteTableBasedItemEffect_(gPartyMenu.slotId, gSpecialVar_ItemId, 0))
if (ExecuteTableBasedItemEffect(mon, gSpecialVar_ItemId, gPartyMenu.slotId, 0))
{
gTasks[taskId].func = Task_SacredAshLoop;
return;
@ -5526,7 +5624,7 @@ void ItemUseCB_EvolutionStone(u8 taskId, TaskFunc task)
{
PlaySE(SE_SELECT);
gCB2_AfterEvolution = gPartyMenu.exitCallback;
if (ExecuteTableBasedItemEffect_(gPartyMenu.slotId, gSpecialVar_ItemId, 0))
if (ExecuteTableBasedItemEffect(&gPlayerParty[gPartyMenu.slotId], gSpecialVar_ItemId, gPartyMenu.slotId, 0))
{
gPartyMenuUseExitCallback = FALSE;
DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE);
@ -5691,16 +5789,18 @@ void TryItemHoldFormChange(struct Pokemon *mon)
#undef tAnimWait
#undef tNextFunc
const u8* GetItemEffect(u16 item)
{
if (item == ITEM_ENIGMA_BERRY_E_READER)
return gSaveBlock1Ptr->enigmaBerry.itemEffect;
else
return gItemEffectTable[item];
}
u8 GetItemEffectType(u16 item)
{
const u8 *itemEffect;
u32 statusCure;
// Read the item's effect properties.
if (item == ITEM_ENIGMA_BERRY_E_READER)
itemEffect = gSaveBlock1Ptr->enigmaBerry.itemEffect;
else
itemEffect = gItemEffectTable[item];
const u8 *itemEffect = GetItemEffect(item);
if (itemEffect == NULL)
return ITEM_EFFECT_NONE;

View File

@ -5736,55 +5736,16 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
// Get item hold effect
heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, NULL);
if (heldItem == ITEM_ENIGMA_BERRY_E_READER)
{
if (gMain.inBattle)
holdEffect = gEnigmaBerries[gBattlerInMenuId].holdEffect;
else
holdEffect = gSaveBlock1Ptr->enigmaBerry.holdEffect;
}
else
{
holdEffect = ItemId_GetHoldEffect(heldItem);
}
// Get battler id (if relevant)
gPotentialItemEffectBattler = gBattlerInMenuId;
if (gMain.inBattle)
{
gActiveBattler = gBattlerInMenuId;
i = (GetBattlerSide(gActiveBattler) != B_SIDE_PLAYER);
while (i < gBattlersCount)
{
if (gBattlerPartyIndexes[i] == partyIndex)
{
battlerId = i;
break;
}
i += 2;
}
}
else
{
gActiveBattler = 0;
battlerId = MAX_BATTLERS_COUNT;
}
// Skip using the item if it won't do anything
if (gItemEffectTable[item] == NULL && item != ITEM_ENIGMA_BERRY_E_READER)
return TRUE;
// Get item effect
if (item == ITEM_ENIGMA_BERRY_E_READER)
{
if (gMain.inBattle)
itemEffect = gEnigmaBerries[gActiveBattler].itemEffect;
else
itemEffect = gSaveBlock1Ptr->enigmaBerry.itemEffect;
}
else
{
itemEffect = gItemEffectTable[item];
}
itemEffect = GetItemEffect(item);
// Do item effect
for (i = 0; i < ITEM_EFFECT_ARG_START; i++)
@ -5793,85 +5754,13 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
{
// Handle ITEM0 effects (infatuation, Dire Hit, X Attack). ITEM0_SACRED_ASH is handled in party_menu.c
// Now handled in item battle scripts.
case 0:
// Cure infatuation
if ((itemEffect[i] & ITEM0_INFATUATION)
&& gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && (gBattleMons[battlerId].status2 & STATUS2_INFATUATION))
{
gBattleMons[battlerId].status2 &= ~STATUS2_INFATUATION;
retVal = FALSE;
}
// Dire Hit
if ((itemEffect[i] & ITEM0_DIRE_HIT)
&& !(gBattleMons[gActiveBattler].status2 & STATUS2_FOCUS_ENERGY))
{
gBattleMons[gActiveBattler].status2 |= STATUS2_FOCUS_ENERGY;
retVal = FALSE;
}
break;
// Handle ITEM1 effects (in-battle stat boosting effects)
// Now handled in item battle scripts.
case 1:
// X Attack
if ((itemEffect[i] & ITEM1_X_ATTACK)
&& gBattleMons[gActiveBattler].statStages[STAT_ATK] < MAX_STAT_STAGE)
{
gBattleMons[gActiveBattler].statStages[STAT_ATK] += X_ITEM_STAGES;
if (gBattleMons[gActiveBattler].statStages[STAT_ATK] > MAX_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[STAT_ATK] = MAX_STAT_STAGE;
retVal = FALSE;
}
// X Defense
if ((itemEffect[i] & ITEM1_X_DEFENSE)
&& gBattleMons[gActiveBattler].statStages[STAT_DEF] < MAX_STAT_STAGE)
{
gBattleMons[gActiveBattler].statStages[STAT_DEF] += X_ITEM_STAGES;
if (gBattleMons[gActiveBattler].statStages[STAT_DEF] > MAX_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[STAT_DEF] = MAX_STAT_STAGE;
retVal = FALSE;
}
// X Speed
if ((itemEffect[i] & ITEM1_X_SPEED)
&& gBattleMons[gActiveBattler].statStages[STAT_SPEED] < MAX_STAT_STAGE)
{
gBattleMons[gActiveBattler].statStages[STAT_SPEED] += X_ITEM_STAGES;
if (gBattleMons[gActiveBattler].statStages[STAT_SPEED] > MAX_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[STAT_SPEED] = MAX_STAT_STAGE;
retVal = FALSE;
}
// X Sp Attack
if ((itemEffect[i] & ITEM1_X_SPATK)
&& gBattleMons[gActiveBattler].statStages[STAT_SPATK] < MAX_STAT_STAGE)
{
gBattleMons[gActiveBattler].statStages[STAT_SPATK] += X_ITEM_STAGES;
if (gBattleMons[gActiveBattler].statStages[STAT_SPATK] > MAX_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[STAT_SPATK] = MAX_STAT_STAGE;
retVal = FALSE;
}
// X Sp Defense
if ((itemEffect[i] & ITEM1_X_SPDEF)
&& gBattleMons[gActiveBattler].statStages[STAT_SPDEF] < MAX_STAT_STAGE)
{
gBattleMons[gActiveBattler].statStages[STAT_SPDEF] += X_ITEM_STAGES;
if (gBattleMons[gActiveBattler].statStages[STAT_SPDEF] > MAX_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[STAT_SPDEF] = MAX_STAT_STAGE;
retVal = FALSE;
}
// X Accuracy
if ((itemEffect[i] & ITEM1_X_ACCURACY)
&& gBattleMons[gActiveBattler].statStages[STAT_ACC] < MAX_STAT_STAGE)
{
gBattleMons[gActiveBattler].statStages[STAT_ACC] += X_ITEM_STAGES;
if (gBattleMons[gActiveBattler].statStages[STAT_ACC] > MAX_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[STAT_ACC] = MAX_STAT_STAGE;
retVal = FALSE;
}
break;
// Formerly used by the item effects of the X Sp. Atk and the X Accuracy
case 2:
@ -5879,14 +5768,6 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
// Handle ITEM3 effects (Guard Spec, Rare Candy, cure status)
case 3:
// Guard Spec
if ((itemEffect[i] & ITEM3_GUARD_SPEC)
&& gSideTimers[GetBattlerSide(gActiveBattler)].mistTimer == 0)
{
gSideTimers[GetBattlerSide(gActiveBattler)].mistTimer = 5;
retVal = FALSE;
}
// Rare Candy / EXP Candy
if ((itemEffect[i] & ITEM3_LEVEL_UP)
&& GetMonData(mon, MON_DATA_LEVEL, NULL) != MAX_LEVEL)
@ -5915,13 +5796,8 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
}
// Cure status
if ((itemEffect[i] & ITEM3_SLEEP)
&& HealStatusConditions(mon, partyIndex, STATUS1_SLEEP, battlerId) == 0)
{
if (battlerId != MAX_BATTLERS_COUNT)
gBattleMons[battlerId].status2 &= ~STATUS2_NIGHTMARE;
if ((itemEffect[i] & ITEM3_SLEEP) && HealStatusConditions(mon, partyIndex, STATUS1_SLEEP, battlerId) == 0)
retVal = FALSE;
}
if ((itemEffect[i] & ITEM3_POISON) && HealStatusConditions(mon, partyIndex, STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER, battlerId) == 0)
retVal = FALSE;
if ((itemEffect[i] & ITEM3_BURN) && HealStatusConditions(mon, partyIndex, STATUS1_BURN, battlerId) == 0)
@ -5930,12 +5806,6 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
retVal = FALSE;
if ((itemEffect[i] & ITEM3_PARALYSIS) && HealStatusConditions(mon, partyIndex, STATUS1_PARALYSIS, battlerId) == 0)
retVal = FALSE;
if ((itemEffect[i] & ITEM3_CONFUSION) // heal confusion
&& gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && (gBattleMons[battlerId].status2 & STATUS2_CONFUSION))
{
gBattleMons[battlerId].status2 &= ~STATUS2_CONFUSION;
retVal = FALSE;
}
break;
// Handle ITEM4 effects (Change HP/Atk EVs, HP heal, PP heal, PP up, Revive, and evolution stones)
@ -6022,39 +5892,13 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
break;
case 2: // ITEM4_HEAL_HP
// If Revive, update number of times revive has been used
if (effectFlags & (ITEM4_REVIVE >> 2))
{
if (GetMonData(mon, MON_DATA_HP, NULL) != 0)
// Check use validity.
if ((effectFlags & (ITEM4_REVIVE >> 2) && GetMonData(mon, MON_DATA_HP, NULL) != 0)
|| (!(effectFlags & (ITEM4_REVIVE >> 2)) && GetMonData(mon, MON_DATA_HP, NULL) == 0))
{
itemEffectParam++;
break;
}
if (gMain.inBattle)
{
if (battlerId != MAX_BATTLERS_COUNT)
{
gAbsentBattlerFlags &= ~gBitTable[battlerId];
CopyPlayerPartyMonToBattleData(battlerId, GetPartyIdFromBattlePartyId(gBattlerPartyIndexes[battlerId]));
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER && gBattleResults.numRevivesUsed < 255)
gBattleResults.numRevivesUsed++;
}
else
{
gAbsentBattlerFlags &= ~gBitTable[gActiveBattler ^ 2];
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER && gBattleResults.numRevivesUsed < 255)
gBattleResults.numRevivesUsed++;
}
}
}
else
{
if (GetMonData(mon, MON_DATA_HP, NULL) == 0)
{
itemEffectParam++;
break;
}
}
// Get amount of HP to restore
dataUnsigned = itemEffect[itemEffectParam++];
@ -6080,36 +5924,12 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
// Only restore HP if not at max health
if (GetMonData(mon, MON_DATA_MAX_HP, NULL) != GetMonData(mon, MON_DATA_HP, NULL))
{
if (!usedByAI)
{
// Restore HP
dataUnsigned = GetMonData(mon, MON_DATA_HP, NULL) + dataUnsigned;
if (dataUnsigned > GetMonData(mon, MON_DATA_MAX_HP, NULL))
dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL);
SetMonData(mon, MON_DATA_HP, &dataUnsigned);
// Update battler (if applicable)
if (gMain.inBattle && battlerId != MAX_BATTLERS_COUNT)
{
gBattleMons[battlerId].hp = dataUnsigned;
if (!(effectFlags & (ITEM4_REVIVE >> 2)) && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
{
if (gBattleResults.numHealingItemsUsed < 255)
gBattleResults.numHealingItemsUsed++;
temp2 = gActiveBattler;
gActiveBattler = battlerId;
BtlController_EmitGetMonData(BUFFER_A, REQUEST_ALL_BATTLE, 0);
MarkBattlerForControllerExec(gActiveBattler);
gActiveBattler = temp2;
}
}
}
else
{
gBattleMoveDamage = -dataUnsigned;
}
retVal = FALSE;
}
effectFlags &= ~(ITEM4_REVIVE >> 2);
@ -6134,11 +5954,6 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), temp2);
}
SetMonData(mon, MON_DATA_PP1 + temp2, &dataUnsigned);
// Heal battler PP too (if applicable)
if (gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && MOVE_IS_PERMANENT(battlerId, temp2))
gBattleMons[battlerId].pp[temp2] = dataUnsigned;
retVal = FALSE;
}
}
@ -6160,11 +5975,6 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex);
}
SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned);
// Heal battler PP too (if applicable)
if (gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && MOVE_IS_PERMANENT(battlerId, moveIndex))
gBattleMons[battlerId].pp[moveIndex] = dataUnsigned;
retVal = FALSE;
}
}

View File

@ -0,0 +1,25 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("X-Attack sharply raises battler's attack stat", s16 damage)
{
u16 useItem;
PARAMETRIZE { useItem = FALSE; }
PARAMETRIZE { useItem = TRUE; }
GIVEN {
ASSUME(gItems[ITEM_X_ATTACK].battleUsage == EFFECT_ITEM_INCREASE_STAT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (useItem) TURN { USE_ITEM(player, ITEM_X_ATTACK); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
MESSAGE("Wobbuffet used Tackle!");
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
if (B_X_ITEMS_BUFF >= GEN_7)
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage);
else
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
}
}

View File

@ -0,0 +1,37 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Potion restores a battler's HP by 20")
{
s16 damage;
GIVEN {
ASSUME(gItems[ITEM_POTION].battleUsage == EFFECT_ITEM_RESTORE_HP);
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { USE_ITEM(player, ITEM_POTION, partyIndex: 0); }
} SCENE {
HP_BAR(player, captureDamage: &damage);
} FINALLY {
EXPECT_EQ(damage, -20);
}
}
SINGLE_BATTLE_TEST("Sitrus Berry restores a battler's HP")
{
s16 damage;
GIVEN {
ASSUME(gItems[ITEM_SITRUS_BERRY].battleUsage == EFFECT_ITEM_RESTORE_HP);
PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { USE_ITEM(player, ITEM_SITRUS_BERRY, partyIndex: 0); }
} SCENE {
HP_BAR(player, captureDamage: &damage);
} FINALLY {
if (I_SITRUS_BERRY_HEAL >= GEN_4)
EXPECT_EQ(damage, -25);
else
EXPECT_EQ(damage, -30);
}
}

View File

@ -0,0 +1,19 @@
#include "global.h"
#include "test_battle.h"
SINGLE_BATTLE_TEST("Ether restores the PP of one of a battler's moves")
{
GIVEN {
ASSUME(gItems[ITEM_ETHER].battleUsage == EFFECT_ITEM_RESTORE_PP);
ASSUME(gItems[ITEM_ETHER].type == ITEM_USE_PARTY_MENU_MOVES);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_CONFUSION); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_CONFUSION); }
TURN { USE_ITEM(player, ITEM_ETHER, partyIndex: 0, move: MOVE_TACKLE); }
} FINALLY {
EXPECT_EQ(player->pp[0], 35);
EXPECT_EQ(player->pp[1], 24);
}
}

View File

@ -334,6 +334,13 @@
* via Switch, e.g. after fainting or due to a U-turn.
* SEND_OUT(player, 1);
*
* USE_ITEM(battler, itemId, [partyIndex:], [move:])
* Used when the battler chooses to use an item from the Bag. The item
* ID must be specified, and party index and move slot if applicable, e.g:
* USE_ITEM(player, ITEM_X_ATTACK);
* USE_ITEM(player, ITEM_POTION, partyIndex: 0);
* USE_ITEM(player, ITEM_LEPPA_BERRY, partyIndex: 0, move: MOVE_TACKLE);
*
* SCENE
* Contains an abridged description of the UI during the THEN. The order
* of the description must match too, e.g.
@ -765,7 +772,7 @@ enum { TURN_CLOSED, TURN_OPEN, TURN_CLOSING };
#define SWITCH(battler, partyIndex) Switch(__LINE__, battler, partyIndex)
#define SKIP_TURN(battler) SkipTurn(__LINE__, battler)
#define SEND_OUT(battler, partyIndex) SendOut(__LINE__, battler, partyIndex)
#define USE_ITEM(battler, ...) UseItem(__LINE__, battler, (struct ItemContext) { APPEND_TRUE(__VA_ARGS__) })
#define WITH_RNG(tag, value) rng: ((struct TurnRNG) { tag, value })
struct MoveContext
@ -791,13 +798,23 @@ struct MoveContext
bool8 explicitRNG;
};
struct ItemContext
{
u16 itemId;
u16 explicitItemId:1;
u16 partyIndex;
u16 explicitPartyIndex:1;
u16 move;
u16 explicitMove:1;
};
void OpenTurn(u32 sourceLine);
void CloseTurn(u32 sourceLine);
void Move(u32 sourceLine, struct BattlePokemon *, struct MoveContext);
void ForcedMove(u32 sourceLine, struct BattlePokemon *);
void Switch(u32 sourceLine, struct BattlePokemon *, u32 partyIndex);
void SkipTurn(u32 sourceLine, struct BattlePokemon *);
void UseItem(u32 sourceLine, struct BattlePokemon *, struct ItemContext);
void SendOut(u32 sourceLine, struct BattlePokemon *, u32 partyIndex);
/* Scene */

View File

@ -3,6 +3,7 @@
#include "battle_anim.h"
#include "battle_controllers.h"
#include "characters.h"
#include "item_menu.h"
#include "main.h"
#include "malloc.h"
#include "random.h"
@ -1251,6 +1252,9 @@ void BattleTest_CheckBattleRecordActionType(u32 battlerId, u32 recordIndex, u32
case B_ACTION_SWITCH:
actualMacro = "SWITCH";
break;
case B_ACTION_USE_ITEM:
actualMacro = "USE_ITEM";
break;
}
break;
case RECORDED_PARTY_INDEX:
@ -1508,6 +1512,40 @@ void SendOut(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex)
DATA.currentMonIndexes[battlerId] = partyIndex;
}
void UseItem(u32 sourceLine, struct BattlePokemon *battler, struct ItemContext ctx)
{
s32 i;
s32 battlerId = battler - gBattleMons;
bool32 requirePartyIndex = ItemId_GetType(ctx.itemId) == ITEM_USE_PARTY_MENU || ItemId_GetType(ctx.itemId) == ITEM_USE_PARTY_MENU_MOVES;
// Check general bad use.
INVALID_IF(DATA.turnState == TURN_CLOSED, "USE_ITEM outside TURN");
INVALID_IF(DATA.actionBattlers & (1 << battlerId), "Multiple battler actions");
INVALID_IF(ctx.itemId >= ITEMS_COUNT, "Illegal item: %d", ctx.itemId);
// Check party menu items.
INVALID_IF(requirePartyIndex && !ctx.explicitPartyIndex, "%S requires explicit party index", ItemId_GetName(ctx.itemId));
INVALID_IF(requirePartyIndex && ctx.partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), \
"USE_ITEM to invalid party index");
// Check move slot items.
if (ItemId_GetType(ctx.itemId) == ITEM_USE_PARTY_MENU_MOVES)
{
INVALID_IF(!ctx.explicitMove, "%S requires an explicit move", ItemId_GetName(ctx.itemId));
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (GetMonData(CurrentMon(battlerId), MON_DATA_MOVE1 + i, NULL) == ctx.move)
break;
}
INVALID_IF(i == MAX_MON_MOVES, "USE_ITEM on invalid move: %d", ctx.move);
}
PushBattlerAction(sourceLine, battlerId, RECORDED_ACTION_TYPE, B_ACTION_USE_ITEM);
PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, (ctx.itemId >> 8) & 0xFF);
PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, ctx.itemId & 0xFF);
if (ctx.explicitPartyIndex)
gBattleStruct->itemPartyIndex[battlerId] = ctx.partyIndex;
if (ctx.explicitMove)
gBattleStruct->itemPartyIndex[battlerId] = i;
DATA.actionBattlers |= 1 << battlerId;
}
static const char *const sQueueGroupTypeMacros[] =
{
[QUEUE_GROUP_NONE] = NULL,