-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Make Pokeballs Usable Out Of Battle
original source: Lunos' pokecommunity post
From Lunos:
So, earlier, someone asked in RHH's Discord if it was possible to modify the caught ball of a certain Pokémon in the party at will.
Naturally, that's perfectly possible because the entire source code of the game is laid right before our very eyes and the code itself already does it.
Then Jaizu brought up a very neat suggestion; to make Poké Balls usable outside of battle to set the caught ball directly like that.
Honestly, that sounded very cool to me so I just went and did it.
And now that it's done, I came here to post it because why not.
I don't think there's a need for explanations. You go to the bag, try to use a Poké Ball and the magic happens. It's all pretty straightforward.
video:
https://www.youtube.com/watch?v=weJzo2Q2N3s
To implement this, you can track my GitHub repository via git remote and pull the branch oobBalls which is where I'm hosting the code:
git remote add lunos https://github.com/LOuroboros/pokeemerald
git pull lunos oobBalls
And that's pretty much it.
add at end of file before #endif
void ItemUseOutOfBattle_PokeBall(u8);
add at end of file, before #endif
void ItemUseCB_PokeBall(u8 taskId, TaskFunc task);
for this file, in each ITEM_*_BALL entry, add the following line after .type = ITEM_*_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
so the entries should look like this:
header line
[ITEM_MASTER_BALL] =
{
.name = _("MASTER BALL"),
.itemId = ITEM_MASTER_BALL,
.price = 0,
.description = sMasterBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_MASTER_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_MASTER_BALL - FIRST_BALL,
},
[ITEM_ULTRA_BALL] =
{
.name = _("ULTRA BALL"),
.itemId = ITEM_ULTRA_BALL,
.price = 1200,
.description = sUltraBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_ULTRA_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_ULTRA_BALL - FIRST_BALL,
},
[ITEM_GREAT_BALL] =
{
.name = _("GREAT BALL"),
.itemId = ITEM_GREAT_BALL,
.price = 600,
.description = sGreatBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_GREAT_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_GREAT_BALL - FIRST_BALL,
},
[ITEM_POKE_BALL] =
{
.name = _("POKé BALL"),
.itemId = ITEM_POKE_BALL,
.price = 200,
.description = sPokeBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_POKE_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_POKE_BALL - FIRST_BALL,
},
[ITEM_SAFARI_BALL] =
{
.name = _("SAFARI BALL"),
.itemId = ITEM_SAFARI_BALL,
.price = 0,
.description = sSafariBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_SAFARI_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_SAFARI_BALL - FIRST_BALL,
},
[ITEM_NET_BALL] =
{
.name = _("NET BALL"),
.itemId = ITEM_NET_BALL,
.price = 1000,
.description = sNetBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_NET_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_NET_BALL - FIRST_BALL,
},
[ITEM_DIVE_BALL] =
{
.name = _("DIVE BALL"),
.itemId = ITEM_DIVE_BALL,
.price = 1000,
.description = sDiveBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_DIVE_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_DIVE_BALL - FIRST_BALL,
},
[ITEM_NEST_BALL] =
{
.name = _("NEST BALL"),
.itemId = ITEM_NEST_BALL,
.price = 1000,
.description = sNestBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_NEST_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_NEST_BALL - FIRST_BALL,
},
[ITEM_REPEAT_BALL] =
{
.name = _("REPEAT BALL"),
.itemId = ITEM_REPEAT_BALL,
.price = 1000,
.description = sRepeatBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_REPEAT_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_REPEAT_BALL - FIRST_BALL,
},
[ITEM_TIMER_BALL] =
{
.name = _("TIMER BALL"),
.itemId = ITEM_TIMER_BALL,
.price = 1000,
.description = sTimerBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_TIMER_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_TIMER_BALL - FIRST_BALL,
},
[ITEM_LUXURY_BALL] =
{
.name = _("LUXURY BALL"),
.itemId = ITEM_LUXURY_BALL,
.price = 1000,
.description = sLuxuryBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_LUXURY_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_LUXURY_BALL - FIRST_BALL,
},
[ITEM_PREMIER_BALL] =
{
.name = _("PREMIER BALL"),
.itemId = ITEM_PREMIER_BALL,
.price = 200,
.description = sPremierBallDesc,
.pocket = POCKET_POKE_BALLS,
.type = ITEM_PREMIER_BALL - FIRST_BALL,
.fieldUseFunc = ItemUseOutOfBattle_PokeBall,
.battleUsage = ITEM_B_USE_OTHER,
.battleUseFunc = ItemUseInBattle_PokeBall,
.secondaryId = ITEM_PREMIER_BALL - FIRST_BALL,
},
in section static const u8 sContextMenuItems_BallsPocket[] = {
replace line ACTION_GIVE, ACTION_DUMMY,
ACTION_USE, ACTION_GIVE,
add to the end of file
void ItemUseOutOfBattle_PokeBall(u8 taskId)
{
gItemUseCB = ItemUseCB_PokeBall;
gBagMenu->newScreenCallback = CB2_ShowPartyMenuForItemUse;
Task_FadeAndCloseBagMenu(taskId);
}
add to end of file
void ItemUseCB_PokeBall(u8 taskId, TaskFunc task)
{
struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId];
u16 currBall = GetMonData(mon, MON_DATA_POKEBALL);
u16 newBall = gSpecialVar_ItemId;
static const u8 sText_MonBallWasChanged[] = _("{STR_VAR_1} was put in the {STR_VAR_2}.{PAUSE_UNTIL_PRESS}");
if (currBall == newBall)
{
gPartyMenuUseExitCallback = FALSE;
DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = task;
}
else
{
GetMonNickname(mon, gStringVar1);
CopyItemName(newBall, gStringVar2);
PlaySE(SE_SELECT);
gPartyMenuUseExitCallback = TRUE;
SetMonData(mon, MON_DATA_POKEBALL, &newBall);
StringExpandPlaceholders(gStringVar4, sText_MonBallWasChanged);
DisplayPartyMenuMessage(gStringVar4, TRUE);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = task;
RemoveBagItem(newBall, 1);
}
}