diff --git a/asm/macros/event.inc b/asm/macros/event.inc index 891c7fd4edea..89a6a46830dc 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -2321,3 +2321,20 @@ .macro togglefakertc callnative Script_ToggleFakeRtc .endm + + @ ============================ @ + @ ITEM DESCRIPTION HEADER MACROS + @ Used with OW_SHOW_ITEM_DESCRIPTIONS config + .macro showitemdescription + callnative ScriptShowItemDescription + .byte 0 + .endm + + .macro showberrydescription + callnative ScriptShowItemDescription + .byte 1 + .endm + + .macro hideitemdescription + callnative ScriptHideItemDescription + .endm diff --git a/data/maps/MtChimney/scripts.inc b/data/maps/MtChimney/scripts.inc index b4becfabeec0..fbd0da31ae4f 100644 --- a/data/maps/MtChimney/scripts.inc +++ b/data/maps/MtChimney/scripts.inc @@ -111,6 +111,7 @@ MtChimney_EventScript_LavaCookieLady:: msgbox MtChimney_Text_ThankYouDear, MSGBOX_DEFAULT checkitemspace ITEM_LAVA_COOKIE call_if_eq VAR_RESULT, TRUE, MtChimney_EventScript_RemoveMoney +.if OW_SHOW_ITEM_DESCRIPTIONS == OW_ITEM_DESCRIPTIONS_OFF giveitem ITEM_LAVA_COOKIE goto_if_eq VAR_RESULT, FALSE, MtChimney_EventScript_BagIsFull hidemoneybox @@ -122,6 +123,19 @@ MtChimney_EventScript_BagIsFull:: hidemoneybox release end +.else + hidemoneybox + giveitem ITEM_LAVA_COOKIE + goto_if_eq VAR_RESULT, FALSE, MtChimney_EventScript_BagIsFull + release + end + +MtChimney_EventScript_BagIsFull:: + msgbox gText_TooBadBagIsFull, MSGBOX_DEFAULT + release + end +.endif @ OW_SHOW_ITEM_DESCRIPTIONS + MtChimney_EventScript_RemoveMoney:: removemoney 200 diff --git a/data/maps/Route109_SeashoreHouse/scripts.inc b/data/maps/Route109_SeashoreHouse/scripts.inc index afb2a4aa0dd4..d871596b9ae7 100644 --- a/data/maps/Route109_SeashoreHouse/scripts.inc +++ b/data/maps/Route109_SeashoreHouse/scripts.inc @@ -52,8 +52,13 @@ Route109_SeashoreHouse_EventScript_BuySodaPop:: msgbox Route109_SeashoreHouse_Text_HereYouGo, MSGBOX_DEFAULT removemoney 300 updatemoneybox +.if OW_SHOW_ITEM_DESCRIPTIONS != OW_ITEM_DESCRIPTIONS_OFF + hidemoneybox + giveitem ITEM_SODA_POP +.else giveitem ITEM_SODA_POP hidemoneybox +.endif release end diff --git a/data/scripts/berry_tree.inc b/data/scripts/berry_tree.inc index 4f4f723f1c2a..fc9abe960d9f 100644 --- a/data/scripts/berry_tree.inc +++ b/data/scripts/berry_tree.inc @@ -176,6 +176,8 @@ BerryTree_EventScript_PickBerry:: special IncrementDailyPickedBerries special ObjectEventInteractionRemoveBerryTree message BerryTree_Text_PickedTheBerry + delay 10 + showberrydescription playfanfare MUS_OBTAIN_BERRY waitmessage waitfanfare @@ -183,6 +185,7 @@ BerryTree_EventScript_PickBerry:: message BerryTree_Text_PutAwayBerry waitmessage waitbuttonpress + hideitemdescription release end diff --git a/data/scripts/obtain_item.inc b/data/scripts/obtain_item.inc index d052fa700438..c54b2f8dc560 100644 --- a/data/scripts/obtain_item.inc +++ b/data/scripts/obtain_item.inc @@ -2,6 +2,7 @@ .set AMOUNT, VAR_0x8001 Std_ObtainItem:: + copyvar VAR_0x8006, ITEMID additem ITEMID, AMOUNT copyvar VAR_0x8007, VAR_RESULT call EventScript_ObtainItemMessage @@ -58,8 +59,11 @@ EventScript_ObtainedItem:: EventScript_ObtainedItemMessage: message gText_ObtainedTheItem EventScript_ContinueObtainedItem: + delay 10 + showitemdescription waitfanfare msgbox gText_PutItemInPocket, MSGBOX_DEFAULT + hideitemdescription setvar VAR_RESULT, TRUE return @@ -103,6 +107,7 @@ Std_FindItem:: lock faceplayer waitse + copyvar VAR_0x8006, ITEMID copyvar VAR_0x8004, ITEMID copyvar VAR_0x8005, AMOUNT checkitemspace ITEMID, AMOUNT @@ -118,20 +123,25 @@ Std_FindItem:: EventScript_PickUpItem:: removeobject VAR_LAST_TALKED additem VAR_0x8004, VAR_0x8005 + copyvar VAR_0x8006 VAR_0x8004 specialvar VAR_RESULT, BufferTMHMMoveName copyvar VAR_0x8008, VAR_RESULT call_if_eq VAR_0x8008, TRUE, EventScript_FoundTMHM call_if_eq VAR_0x8008, FALSE, EventScript_FoundItem + delay 10 + showitemdescription waitfanfare waitmessage bufferitemnameplural STR_VAR_2, VAR_0x8004, VAR_0x8005 pyramid_inchallenge goto_if_eq VAR_RESULT, TRUE, EventScript_PutBattlePyramidItemInBag msgbox gText_PutItemInPocket, MSGBOX_DEFAULT + hideitemdescription return EventScript_PutBattlePyramidItemInBag:: msgbox gText_PlayerPutItemInBag, MSGBOX_DEFAULT + hideitemdescription return EventScript_FoundTMHM:: @@ -165,6 +175,7 @@ EventScript_NoRoomToPickUpItem:: EventScript_HiddenItemScript:: lockall waitse + copyvar VAR_0x8006, VAR_0x8005 additem VAR_0x8005 copyvar VAR_0x8007, VAR_RESULT bufferitemnameplural STR_VAR_2, VAR_0x8005, 1 @@ -194,11 +205,14 @@ EventScript_FoundHiddenItem:: end EventScript_PutHiddenItemInPocket:: + delay 10 + showitemdescription waitmessage waitfanfare bufferitemnameplural STR_VAR_2, VAR_0x8004, 1 copyvar VAR_0x8004, VAR_0x8008 msgbox gText_PutItemInPocket, MSGBOX_DEFAULT + hideitemdescription special TryPutTreasureInvestigatorsOnAir special SetHiddenItemFlag releaseall diff --git a/include/config/overworld.h b/include/config/overworld.h index 63479f18317c..cebbe5b34b26 100644 --- a/include/config/overworld.h +++ b/include/config/overworld.h @@ -10,6 +10,12 @@ #define OW_HIDE_REPEAT_MAP_POPUP FALSE // If enabled, map popups will not appear if entering a map with the same Map Section Id as the last. #define OW_FRLG_WHITEOUT FALSE // If enabled, shows an additional whiteout message and post whiteout event script with healing NPC. +// Item Obtain Description Box +#define OW_ITEM_DESCRIPTIONS_OFF 0 // never show descriptions +#define OW_ITEM_DESCRIPTIONS_FIRST_TIME 1 // show first time (** SAVE-BREAKING - see struct SaveBlock3 **) +#define OW_ITEM_DESCRIPTIONS_ALWAYS 2 // always show description +#define OW_SHOW_ITEM_DESCRIPTIONS OW_ITEM_DESCRIPTIONS_OFF // If enabled, item descriptions/images will be shown when finding items. + // These generational defines only make a distinction for Berries and the OW_PC_MOVE_ORDER #define GEN_6_XY GEN_6 #define GEN_6_ORAS GEN_LATEST + 1 diff --git a/include/global.h b/include/global.h index 783a91310678..86ada6036403 100644 --- a/include/global.h +++ b/include/global.h @@ -200,12 +200,17 @@ struct Time /*0x04*/ s8 seconds; }; +#include "constants/items.h" +#define ITEM_FLAGS_COUNT ((ITEMS_COUNT / 8) + ((ITEMS_COUNT % 8) ? 1 : 0)) struct SaveBlock3 { #if OW_USE_FAKE_RTC struct Time fakeRTC; #endif +#if OW_SHOW_ITEM_DESCRIPTIONS == OW_ITEM_DESCRIPTIONS_FIRST_TIME + u8 itemFlags[ITEM_FLAGS_COUNT]; +#endif }; extern struct SaveBlock3 *gSaveBlock3Ptr; diff --git a/include/overworld.h b/include/overworld.h index bda2046ec70d..3e9dbc30b6c2 100644 --- a/include/overworld.h +++ b/include/overworld.h @@ -155,4 +155,12 @@ bool32 Overworld_SendKeysToLinkIsRunning(void); bool32 IsSendingKeysOverCable(void); void ClearLinkPlayerObjectEvents(void); +// Item Description Headers +enum ItemObtainFlags +{ + FLAG_GET_ITEM_OBTAINED, + FLAG_SET_ITEM_OBTAINED, +}; +bool8 GetSetItemObtained(u16 item, enum ItemObtainFlags caseId); + #endif // GUARD_OVERWORLD_H diff --git a/src/berry.c b/src/berry.c index 1a1c3b7f1f6b..5c23623e3bcb 100644 --- a/src/berry.c +++ b/src/berry.c @@ -2144,6 +2144,8 @@ void ObjectEventInteractionGetBerryCountString(void) u8 treeId = GetObjectEventBerryTreeId(gSelectedObjectEvent); u8 berry = GetBerryTypeByBerryTreeId(treeId); u8 count = GetBerryCountByBerryTreeId(treeId); + + gSpecialVar_0x8006 = BerryTypeToItemId(berry); CopyItemNameHandlePlural(BerryTypeToItemId(berry), gStringVar1, count); berry = GetTreeMutationValue(treeId); if (berry > 0) diff --git a/src/overworld.c b/src/overworld.c index babdfad7b6e9..2bb49591bb7f 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -24,6 +24,8 @@ #include "gpu_regs.h" #include "heal_location.h" #include "io_reg.h" +#include "item.h" +#include "item_icon.h" #include "link.h" #include "link_rfu.h" #include "load_save.h" @@ -51,6 +53,7 @@ #include "secret_base.h" #include "sound.h" #include "start_menu.h" +#include "string_util.h" #include "task.h" #include "tileset_anims.h" #include "time_events.h" @@ -3290,3 +3293,207 @@ static void SpriteCB_LinkPlayer(struct Sprite *sprite) sprite->data[7]++; } } + +// ---------------- +// Item Header Descriptions +// Item Description Header + +#define ITEM_ICON_X 26 +#define ITEM_ICON_Y 24 +#define ITEM_TAG 0x2722 //same as money label + +bool8 GetSetItemObtained(u16 item, enum ItemObtainFlags caseId) +{ +#if OW_SHOW_ITEM_DESCRIPTIONS == OW_ITEM_DESCRIPTIONS_FIRST_TIME + u8 index = item / 8; + u8 bit = item % 8; + u8 mask = 1 << bit; + switch (caseId) + { + case FLAG_GET_ITEM_OBTAINED: + return gSaveBlock3Ptr->itemFlags[index] & mask; + case FLAG_SET_ITEM_OBTAINED: + gSaveBlock3Ptr->itemFlags[index] |= mask; + return TRUE; + } +#endif + return FALSE; +} + +#if OW_SHOW_ITEM_DESCRIPTIONS != OW_ITEM_DESCRIPTIONS_OFF + +EWRAM_DATA static u8 sHeaderBoxWindowId = 0; +EWRAM_DATA u8 sItemIconSpriteId = 0; +EWRAM_DATA u8 sItemIconSpriteId2 = 0; + +static void ShowItemIconSprite(u16 item, bool8 firstTime, bool8 flash); +static void DestroyItemIconSprite(void); + +static u8 ReformatItemDescription(u16 item, u8 *dest) +{ + u8 count = 0; + u8 numLines = 1; + u8 maxChars = 32; + u8 *desc = (u8 *)gItemsInfo[item].description; + + while (*desc != EOS) + { + if (count >= maxChars) + { + while (*desc != CHAR_SPACE && *desc != CHAR_NEWLINE) + { + *dest = *desc; //finish word + dest++; + desc++; + } + + *dest = CHAR_NEWLINE; + count = 0; + numLines++; + dest++; + desc++; + continue; + } + + *dest = *desc; + if (*desc == CHAR_NEWLINE) + { + *dest = CHAR_SPACE; + } + + dest++; + desc++; + count++; + } + + // finish string + *dest = EOS; + return numLines; +} + +void ScriptShowItemDescription(struct ScriptContext *ctx) +{ + u8 headerType = ScriptReadByte(ctx); + struct WindowTemplate template; + u16 item = gSpecialVar_0x8006; + u8 textY; + u8 *dst; + bool8 handleFlash = FALSE; + + if (GetFlashLevel() > 0 || InBattlePyramid_()) + handleFlash = TRUE; + + if (headerType == 1) // berry + dst = gStringVar3; + else + dst = gStringVar1; + + if (GetSetItemObtained(item, FLAG_GET_ITEM_OBTAINED)) + { + ShowItemIconSprite(item, FALSE, handleFlash); + return; //no box if item obtained previously + } + + SetWindowTemplateFields(&template, 0, 1, 1, 28, 3, 15, 8); + sHeaderBoxWindowId = AddWindow(&template); + FillWindowPixelBuffer(sHeaderBoxWindowId, PIXEL_FILL(0)); + PutWindowTilemap(sHeaderBoxWindowId); + CopyWindowToVram(sHeaderBoxWindowId, 3); + SetStandardWindowBorderStyle(sHeaderBoxWindowId, FALSE); + DrawStdFrameWithCustomTileAndPalette(sHeaderBoxWindowId, FALSE, 0x214, 14); + + if (ReformatItemDescription(item, dst) == 1) + textY = 4; + else + textY = 0; + + ShowItemIconSprite(item, TRUE, handleFlash); + AddTextPrinterParameterized(sHeaderBoxWindowId, 0, dst, ITEM_ICON_X + 2, textY, 0, NULL); +} + +void ScriptHideItemDescription(struct ScriptContext *ctx) +{ + DestroyItemIconSprite(); + + if (!GetSetItemObtained(gSpecialVar_0x8006, FLAG_GET_ITEM_OBTAINED)) + { + //header box only exists if haven't seen item before + GetSetItemObtained(gSpecialVar_0x8006, FLAG_SET_ITEM_OBTAINED); + ClearStdWindowAndFrameToTransparent(sHeaderBoxWindowId, FALSE); + CopyWindowToVram(sHeaderBoxWindowId, 3); + RemoveWindow(sHeaderBoxWindowId); + } +} + +static void ShowItemIconSprite(u16 item, bool8 firstTime, bool8 flash) +{ + s16 x = 0, y = 0; + u8 iconSpriteId; + u8 spriteId2 = MAX_SPRITES; + + if (flash) + { + SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON); + SetGpuRegBits(REG_OFFSET_WINOUT, WINOUT_WINOBJ_OBJ); + } + + iconSpriteId = AddItemIconSprite(ITEM_TAG, ITEM_TAG, item); + if (flash) + spriteId2 = AddItemIconSprite(ITEM_TAG, ITEM_TAG, item); + if (iconSpriteId != MAX_SPRITES) + { + if (!firstTime) + { + //show in message box + x = 213; + y = 140; + } + else + { + // show in header box + x = ITEM_ICON_X; + y = ITEM_ICON_Y; + } + + gSprites[iconSpriteId].x2 = x; + gSprites[iconSpriteId].y2 = y; + gSprites[iconSpriteId].oam.priority = 0; + } + + if (spriteId2 != MAX_SPRITES) + { + gSprites[spriteId2].x2 = x; + gSprites[spriteId2].y2 = y; + gSprites[spriteId2].oam.priority = 0; + gSprites[spriteId2].oam.objMode = ST_OAM_OBJ_WINDOW; + sItemIconSpriteId2 = spriteId2; + } + + sItemIconSpriteId = iconSpriteId; +} + +static void DestroyItemIconSprite(void) +{ + FreeSpriteTilesByTag(ITEM_TAG); + FreeSpritePaletteByTag(ITEM_TAG); + FreeSpriteOamMatrix(&gSprites[sItemIconSpriteId]); + DestroySprite(&gSprites[sItemIconSpriteId]); + + if ((GetFlashLevel() > 0 || InBattlePyramid_()) && sItemIconSpriteId2 != MAX_SPRITES) + { + FreeSpriteOamMatrix(&gSprites[sItemIconSpriteId2]); + DestroySprite(&gSprites[sItemIconSpriteId2]); + } +} + +#else +void ScriptShowItemDescription(struct ScriptContext *ctx) +{ + (void) ScriptReadByte(ctx); +} +void ScriptHideItemDescription(struct ScriptContext *ctx) +{ +} +#endif // OW_SHOW_ITEM_DESCRIPTIONS + + diff --git a/src/shop.c b/src/shop.c index 77f2039e3b52..a343bab0d3ee 100644 --- a/src/shop.c +++ b/src/shop.c @@ -1127,6 +1127,7 @@ static void BuyMenuTryMakePurchase(u8 taskId) { if (AddBagItem(tItemId, tItemCount) == TRUE) { + GetSetItemObtained(tItemId, FLAG_SET_ITEM_OBTAINED); RecordItemPurchase(taskId); BuyMenuDisplayMessage(taskId, gText_HereYouGoThankYou, BuyMenuSubtractMoney); }