Table of Contents
By devolov. Item completely inspired by one in the Radical Red and soupercell gets the credit for the idea.
Goal: Make an item that can heal your party up to 6 times. After 6 times, a Pokemon Center must be used to replenish.
Note: In my hack, the goal is to allow a vanilla save file to use play the game, so I swapped Dream Mail for this item. You'd probably want to keep Dream Mail in your hack, so just use this as a basis on how the logic was done.
Note 2: I have not yet got to the PokeVial in my playthrough of Radical Red. I just watched a YouTube video before playing it and thought "That's a nice feature."
Add an icon to graphics/items/icons/dream_mail.png
:
If you're creating a new item, add it with a different name copy the dream mail pallette in graphics/items/icon_palettes
too.
Add the PokeVial as an item.
------------------------------- src/data/items.h -------------------------------
index 7cd180a2b..d8305cbe3 100644
@@ -1577,18 +1577,21 @@ const struct Item gItems[] =
.fieldUseFunc = ItemUseOutOfBattle_Mail,
.secondaryId = ITEM_TO_MAIL(ITEM_TROPIC_MAIL),
},
[ITEM_DREAM_MAIL] =
{
- .name = _("DREAM MAIL"),
+ .name = _("PokéVial"),
.itemId = ITEM_DREAM_MAIL,
- .price = 50,
+ .price = 0,
.description = sDreamMailDesc,
- .pocket = POCKET_ITEMS,
- .type = ITEM_USE_MAIL,
+ .importance = 1,
+ .holdEffectParam = 6, //Set to max usages before Pokemon Center
+ .registrability = TRUE,
+ .pocket = POCKET_KEY_ITEMS,
+ .type = ITEM_USE_FIELD,
.fieldUseFunc = ItemUseOutOfBattle_Mail,
- .secondaryId = ITEM_TO_MAIL(ITEM_DREAM_MAIL),
+ .fieldUseFunc = ItemUseOutOfBattle_PokeVial,
},
[ITEM_FAB_MAIL] =
{
Give it a description.
---------------------- src/data/text/item_descriptions.h ----------------------
index 26fc8d086..62404b54a 100644
@@ -480,12 +480,12 @@ static const u8 sTropicMailDesc[] = _(
"A BELLOSSOM-print\n"
"MAIL to be held by\n"
"a POKéMON.");
static const u8 sDreamMailDesc[] = _(
- "MAIL featuring a\n"
- "sketch of the\n"
- "holding POKéMON.");
+ "Use to heal party.\n"
+ "Replenishes at\n"
+ "POKéMON Centers.");
static const u8 sFabMailDesc[] = _(
"A gorgeous-print\n"
"MAIL to be held\n"
Add a variable tyhat tracks its usage.
--------------------------- include/constants/vars.h ---------------------------
index f26ee2186..e95e14b18 100644
@@ -269,9 +269,9 @@
#define VAR_WILD_PKMN_ROUTE_SEEN_3 0x40FA
#define VAR_WILD_PKMN_ROUTE_SEEN_4 0x40FB
#define VAR_DIFFICULTY 0x40FC
#define VAR_EXP_MULT 0x40FD
-#define VAR_UNUSED_0x40FE 0x40FE // Unused Var
+#define VAR_POKEVIAL_USAGES 0x40FE
#define VAR_UNUSED_0x40FF 0x40FF // Unused Var
#define VARS_END 0x40FF
#define VARS_COUNT (VARS_END - VARS_START + 1)
Add functionality for when it's used.
-------------------------------- src/item_use.c --------------------------------
index 5a07392b8..a6c0fdf8a 100755
@@ -43,8 +43,9 @@
#include "constants/items.h"
#include "constants/songs.h"
#include "battle_setup.h"
#include "region_map.h"
+#include "script_pokemon_util.h"
static void SetUpItemUseCallback(u8);
static void FieldCB_UseItemOnField(void);
static void Task_CallItemUseOnFieldCallback(u8);
@@ -1165,8 +1166,32 @@ void ItemUseOutOfBattle_CannotUse(u8 taskId)
DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
}
+void ItemUseOutOfBattle_PokeVial(u8 taskId)
+{
+ u16 vialUsages = VarGet(VAR_POKEVIAL_USAGES);
+ u16 vialUsagesMax = ItemId_GetHoldEffectParam(ITEM_POKEVIAL);
+ if (vialUsages >= vialUsagesMax){
+ if (gTasks[taskId].tUsingRegisteredKeyItem) // to account for pressing select in the overworld
+ DisplayItemMessageOnField(taskId, gText_PokeVial_Failure, Task_CloseCantUseKeyItemMessage);
+ else if (!InBattlePyramid())
+ DisplayItemMessage(taskId, FONT_NORMAL, gText_PokeVial_Failure, CloseItemMessage);
+ else
+ DisplayItemMessageInBattlePyramid(taskId, gText_PokeVial_Failure, Task_CloseBattlePyramidBagMessage);
+
+ }
+ else{
+ PlaySE(SE_RG_POKE_JUMP_SUCCESS);
+ HealPlayerParty();
+ vialUsages++;
+ VarSet(VAR_POKEVIAL_USAGES, vialUsages);
+ ConvertIntToDecimalStringN(gStringVar1, vialUsagesMax - vialUsages, STR_CONV_MODE_LEFT_ALIGN, 2);
+ if (gTasks[taskId].tUsingRegisteredKeyItem) // to account for pressing select in the overworld
+ DisplayItemMessageOnField(taskId, gText_PokeVial_Success, Task_CloseCantUseKeyItemMessage);
+ else if (!InBattlePyramid())
+ DisplayItemMessage(taskId, FONT_NORMAL, gText_PokeVial_Success, CloseItemMessage);
+ else
+ DisplayItemMessageInBattlePyramid(taskId, gText_PokeVial_Success, Task_CloseBattlePyramidBagMessage);
+ }
+}
+
Replenish it at Pokemon Centers
---------------------- data/scripts/pkmn_center_nurse.inc ----------------------
index 233e0a736..546385218 100644
@@ -15,8 +15,9 @@ EventScript_PkmnCenterNurse_Goodbye::
EventScript_PkmnCenterNurse_HealPkmn::
incrementgamestat GAME_STAT_USED_POKECENTER
playfanfare MUS_HEAL
special HealPlayerParty
+ setvar VAR_POKEVIAL_USAGES, 0
goto_if_unset FLAG_POKERUS_EXPLAINED, EventScript_PkmnCenterNurse_CheckPokerus
goto EventScript_PkmnCenterNurse_CheckTrainerHillAndUnionRoom
end
Add strings for when it's used.
-------------------------------- src/strings.c --------------------------------
index ecf0fcd80..80e805451 100644
@@ -237,8 +237,10 @@ const u8 gText_ThrewAwayVar2Var1s[] = _("Threw away {STR_VAR_2}\n{STR_VAR_1}(s).
const u8 gText_ConfirmTossItems[] = _("Is it okay to\nthrow away {STR_VAR_2}\n{STR_VAR_1}(s)?");
const u8 gText_DadsAdvice[] = _("DAD's advice…\n{PLAYER}, there's a time and place for\leverything!{PAUSE_UNTIL_PRESS}");
const u8 gText_ExpShareTurnOn[] = _("Turned on the Exp. Share.\pParty will now gain a portion\nof the Experience Points.{PAUSE_UNTIL_PRESS}");
const u8 gText_ExpShareTurnOff[] = _("Turned off the Exp. Share.\pParty will no longer gain a portion\nof any Experience Points.{PAUSE_UNTIL_PRESS}");
+const u8 gText_PokeVial_Success[] = _("PokéVial successfully healed party.\p{STR_VAR_1} more uses before needing\nto heal at a POKéMON Center.{PAUSE_UNTIL_PRESS}");
+const u8 gText_PokeVial_Failure[] = _("PokéVial is drained.\nHeal at a POKéMON Center to replenish.{PAUSE_UNTIL_PRESS}");
const u8 gText_CleanseTagTurnOn[] = _("Turned on Cleanse Tag.\nAll wild encounters will be avoided.{PAUSE_UNTIL_PRESS}");
const u8 gText_CleanseTagTurnOff[] = _("Turned off Cleanse Tag.{PAUSE_UNTIL_PRESS}");
const u8 gText_CantDismountBike[] = _("You can't dismount your BIKE here.{PAUSE_UNTIL_PRESS}");
const u8 gText_ItemFinderNearby[] = _("Huh?\nThe ITEMFINDER's responding!\pThere's an item buried around here!{PAUSE_UNTIL_PRESS}");
Declare those strings.
------------------------------ include/strings.h ------------------------------
index a0a515fd8..34eb01266 100644
@@ -936,8 +936,10 @@ extern const u8 gText_Gabby[];
extern const u8 gText_Anna[];
extern const u8 gText_ExpShareTurnOn[];
extern const u8 gText_ExpShareTurnOff[];
+extern const u8 gText_PokeVial_Success[];
+extern const u8 gText_PokeVial_Failure[];
extern const u8 gText_CleanseTagTurnOn[];
extern const u8 gText_CleanseTagTurnOff[];
extern const u8 gText_DadsAdvice[];
extern const u8 gText_CantDismountBike[];
If you're swapping Dream Mail for this item, remove checks for the mail.
---------------------------------- src/mail.c ----------------------------------
index 63553f172..b9d50d0c4 100644
@@ -204,16 +204,8 @@ static const struct MailGraphics sMailGraphics[] = {
.unused = 0x220,
.textColor = RGB(10, 10, 10),
.textShadow = RGB(25, 25, 25),
},
- [ITEM_TO_MAIL(ITEM_DREAM_MAIL)] = {
- .palette = gMailPalette_Dream,
- .tiles = gMailTiles_Dream,
- .tileMap = gMailTilemap_Dream,
- .unused = 0x340,
- .textColor = RGB(10, 10, 10),
- .textShadow = RGB(25, 25, 25),
- },
[ITEM_TO_MAIL(ITEM_FAB_MAIL)] = {
.palette = gMailPalette_Fab,
.tiles = gMailTiles_Fab,
.tileMap = gMailTilemap_Fab,
@@ -309,16 +301,8 @@ static const struct MailLayout sMailLayouts_Wide[] = {
.wordsYPos = 2,
.wordsXPos = 4,
.lines = sLineLayouts_Wide,
},
- [ITEM_TO_MAIL(ITEM_DREAM_MAIL)] = {
- .numLines = ARRAY_COUNT(sLineLayouts_Wide),
- .signatureYPos = 0,
- .signatureWidth = 0,
- .wordsYPos = 2,
- .wordsXPos = 4,
- .lines = sLineLayouts_Wide,
- },
[ITEM_TO_MAIL(ITEM_FAB_MAIL)] = {
.numLines = ARRAY_COUNT(sLineLayouts_Wide),
.signatureYPos = 8,
.signatureWidth = 0,
@@ -416,16 +400,8 @@ static const struct MailLayout sMailLayouts_Tall[] = {
.wordsYPos = 9,
.wordsXPos = 30,
.lines = sLineLayouts_Tall,
},
- [ITEM_TO_MAIL(ITEM_DREAM_MAIL)] = {
- .numLines = ARRAY_COUNT(sLineLayouts_Tall),
- .signatureYPos = 9,
- .signatureWidth = 96,
- .wordsYPos = 9,
- .wordsXPos = 30,
- .lines = sLineLayouts_Tall,
- },
[ITEM_TO_MAIL(ITEM_FAB_MAIL)] = {
.numLines = ARRAY_COUNT(sLineLayouts_Tall),
.signatureYPos = 17,
.signatureWidth = 104,
@@ -483,11 +459,8 @@ void ReadMail(struct Mail *mail, void (*exitCallback)(void), bool8 hasText)
break;
case ITEM_TO_MAIL(ITEM_BEAD_MAIL):
sMailRead->iconType = ICON_TYPE_BEAD;
break;
- case ITEM_TO_MAIL(ITEM_DREAM_MAIL):
- sMailRead->iconType = ICON_TYPE_DREAM;
- break;
}
}
else
{
------------------------------- src/mail_data.c -------------------------------
index 99cf1f9ed..a8e8ee0ed 100644
@@ -194,9 +194,9 @@ bool8 ItemIsMail(u16 itemId)
case ITEM_WAVE_MAIL:
case ITEM_BEAD_MAIL:
case ITEM_SHADOW_MAIL:
case ITEM_TROPIC_MAIL:
- case ITEM_DREAM_MAIL:
case ITEM_FAB_MAIL:
case ITEM_RETRO_MAIL:
return TRUE;
default: