2723 lines
85 KiB
C
2723 lines
85 KiB
C
|
#include "global.h"
|
||
|
#include "malloc.h"
|
||
|
#include "decompress.h"
|
||
|
#include "decoration.h"
|
||
|
#include "decoration_inventory.h"
|
||
|
#include "event_data.h"
|
||
|
#include "event_object_movement.h"
|
||
|
#include "event_scripts.h"
|
||
|
#include "field_camera.h"
|
||
|
#include "field_player_avatar.h"
|
||
|
#include "field_screen_effect.h"
|
||
|
#include "field_weather.h"
|
||
|
#include "fieldmap.h"
|
||
|
#include "graphics.h"
|
||
|
#include "international_string_util.h"
|
||
|
#include "item_icon.h"
|
||
|
#include "item_menu.h"
|
||
|
#include "list_menu.h"
|
||
|
#include "main.h"
|
||
|
#include "menu.h"
|
||
|
#include "menu_helpers.h"
|
||
|
#include "metatile_behavior.h"
|
||
|
#include "overworld.h"
|
||
|
#include "palette.h"
|
||
|
#include "player_pc.h"
|
||
|
#include "script.h"
|
||
|
#include "secret_base.h"
|
||
|
#include "sound.h"
|
||
|
#include "string_util.h"
|
||
|
#include "strings.h"
|
||
|
#include "task.h"
|
||
|
#include "text.h"
|
||
|
#include "tilesets.h"
|
||
|
#include "trader.h"
|
||
|
#include "tv.h"
|
||
|
#include "constants/decorations.h"
|
||
|
#include "constants/event_objects.h"
|
||
|
#include "constants/songs.h"
|
||
|
#include "constants/region_map_sections.h"
|
||
|
#include "constants/metatile_labels.h"
|
||
|
|
||
|
#define PLACE_DECORATION_SELECTOR_TAG 0xbe5
|
||
|
#define PLACE_DECORATION_PLAYER_TAG 0x008
|
||
|
#define NUM_DECORATION_FLAGS (FLAG_DECORATION_14 - FLAG_DECORATION_0)
|
||
|
|
||
|
#define tCursorX data[0]
|
||
|
#define tCursorY data[1]
|
||
|
#define tState data[2]
|
||
|
#define tInitialX data[3]
|
||
|
#define tInitialY data[4]
|
||
|
#define tDecorWidth data[5]
|
||
|
#define tDecorHeight data[6]
|
||
|
#define tButton data[10]
|
||
|
#define tDecorationMenuCommand data[11]
|
||
|
#define tDecorationItemsMenuCommand data[12]
|
||
|
#define tMenuTaskId data[13]
|
||
|
|
||
|
#define DECOR_MENU_PLACE 0
|
||
|
#define DECOR_MENU_TOSS 1
|
||
|
#define DECOR_MENU_TRADE 2
|
||
|
|
||
|
#define DECOR_ITEMS_MENU_PLACE 0
|
||
|
#define DECOR_ITEMS_MENU_PUT_AWAY 1
|
||
|
|
||
|
struct DecorationItemsMenu
|
||
|
{
|
||
|
struct ListMenuItem items[41];
|
||
|
u8 names[41][24];
|
||
|
u8 numMenuItems;
|
||
|
u8 maxShownItems;
|
||
|
u8 scrollIndicatorsTaskId;
|
||
|
};
|
||
|
|
||
|
struct PlaceDecorationGraphicsDataBuffer
|
||
|
{
|
||
|
const struct Decoration *decoration;
|
||
|
u16 tiles[0x40];
|
||
|
u8 image[0x800];
|
||
|
u16 palette[16];
|
||
|
};
|
||
|
|
||
|
struct DecorRearrangementDataBuffer
|
||
|
{
|
||
|
u8 idx;
|
||
|
u8 width;
|
||
|
u8 height;
|
||
|
u16 flagId;
|
||
|
};
|
||
|
|
||
|
struct DecorationPCContext
|
||
|
{
|
||
|
u8 *items;
|
||
|
u8 *pos;
|
||
|
u8 size;
|
||
|
u8 isPlayerRoom;
|
||
|
};
|
||
|
|
||
|
enum Windows
|
||
|
{
|
||
|
WINDOW_MAIN_MENU,
|
||
|
WINDOW_DECORATION_CATEGORIES,
|
||
|
WINDOW_DECORATION_CATEGORY_SUMMARY,
|
||
|
WINDOW_DECORATION_CATEGORY_ITEMS,
|
||
|
WINDOW_COUNT
|
||
|
};
|
||
|
|
||
|
EWRAM_DATA u8 *gCurDecorationItems = NULL;
|
||
|
EWRAM_DATA static u8 sDecorationActionsCursorPos = 0;
|
||
|
EWRAM_DATA static u8 sNumOwnedDecorationsInCurCategory = 0;
|
||
|
EWRAM_DATA static u8 sSecretBaseItemsIndicesBuffer[DECOR_MAX_SECRET_BASE] = {};
|
||
|
EWRAM_DATA static u8 sPlayerRoomItemsIndicesBuffer[DECOR_MAX_PLAYERS_HOUSE] = {};
|
||
|
EWRAM_DATA static u16 sDecorationsCursorPos = 0;
|
||
|
EWRAM_DATA static u16 sDecorationsScrollOffset = 0;
|
||
|
EWRAM_DATA u8 gCurDecorationIndex = 0;
|
||
|
EWRAM_DATA static u8 sCurDecorationCategory = DECORCAT_DESK;
|
||
|
EWRAM_DATA static u32 sFiller[2] = {};
|
||
|
EWRAM_DATA static struct DecorationPCContext sDecorationContext = {};
|
||
|
EWRAM_DATA static u8 sDecorMenuWindowIds[WINDOW_COUNT] = {};
|
||
|
EWRAM_DATA static struct DecorationItemsMenu *sDecorationItemsMenu = NULL;
|
||
|
EWRAM_DATA static struct PlaceDecorationGraphicsDataBuffer sPlaceDecorationGraphicsDataBuffer = {};
|
||
|
EWRAM_DATA static u16 sCurDecorMapX = 0;
|
||
|
EWRAM_DATA static u16 sCurDecorMapY = 0;
|
||
|
EWRAM_DATA static u8 sDecor_CameraSpriteObjectIdx1 = 0;
|
||
|
EWRAM_DATA static u8 sDecor_CameraSpriteObjectIdx2 = 0;
|
||
|
EWRAM_DATA static u8 sDecorationLastDirectionMoved = 0;
|
||
|
EWRAM_DATA static struct OamData sDecorSelectorOam = {};
|
||
|
EWRAM_DATA static struct DecorRearrangementDataBuffer sDecorRearrangementDataBuffer[DECOR_MAX_SECRET_BASE] = {};
|
||
|
EWRAM_DATA static u8 sCurDecorSelectedInRearrangement = 0;
|
||
|
|
||
|
static void HandleDecorationActionsMenuInput(u8 taskId);
|
||
|
static void PrintCurMainMenuDescription(void);
|
||
|
static void DecorationMenuAction_Decorate(u8 taskId);
|
||
|
static void DecorationMenuAction_PutAway(u8 taskId);
|
||
|
static void DecorationMenuAction_Toss(u8 taskId);
|
||
|
static void DecorationMenuAction_Cancel(u8 taskId);
|
||
|
static void ReturnToDecorationActionsAfterInvalidSelection(u8 taskId);
|
||
|
static void SecretBasePC_PrepMenuForSelectingStoredDecors(u8 taskId);
|
||
|
static void InitDecorationCategoriesWindow(u8 taskId);
|
||
|
static void PrintDecorationCategoryMenuItems(u8 taskId);
|
||
|
static void PrintDecorationCategoryMenuItem(u8 winid, u8 category, u8 x, u8 y, bool8 disabled, u8 speed);
|
||
|
static void ColorMenuItemString(u8 *str, bool8 disabled);
|
||
|
static void HandleDecorationCategoriesMenuInput(u8 taskId);
|
||
|
static void SelectDecorationCategory(u8 taskId);
|
||
|
static void ReturnToDecorationCategoriesAfterInvalidSelection(u8 taskId);
|
||
|
static void ExitDecorationCategoriesMenu(u8 taskId);
|
||
|
static void ReturnToActionsMenuFromCategories(u8 taskId);
|
||
|
static void ExitTraderDecorationMenu(u8 taskId);
|
||
|
static void CopyDecorationMenuItemName(u8 *dest, u16 decoration);
|
||
|
static void DecorationItemsMenu_OnCursorMove(s32 itemIndex, bool8 flag, struct ListMenu *menu);
|
||
|
static void DecorationItemsMenu_PrintDecorationInUse(u8 windowId, u32 itemIndex, u8 y);
|
||
|
static void ShowDecorationItemsWindow(u8 taskId);
|
||
|
static void HandleDecorationItemsMenuInput(u8 taskId);
|
||
|
static void PrintDecorationItemDescription(s32 itemIndex);
|
||
|
static void RemoveDecorationItemsOtherWindows(void);
|
||
|
static bool8 IsDecorationIndexInSecretBase(u8 idx);
|
||
|
static bool8 IsDecorationIndexInPlayersRoom(u8 idx);
|
||
|
static void IdentifyOwnedDecorationsCurrentlyInUse(u8 taskId);
|
||
|
static void InitDecorationItemsWindow(u8 taskId);
|
||
|
static void ShowDecorationCategorySummaryWindow(u8 category);
|
||
|
static void DontTossDecoration(u8 taskId);
|
||
|
static void DecorationItemsMenuAction_Cancel(u8 taskId);
|
||
|
static void DecorationItemsMenuAction_AttemptPlace(u8 taskId);
|
||
|
static void Task_PlaceDecoration(u8 taskId);
|
||
|
static void ConfigureCameraObjectForPlacingDecoration(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor);
|
||
|
static void SetUpPlacingDecorationPlayerAvatar(u8 taskId, struct PlaceDecorationGraphicsDataBuffer *data);
|
||
|
static void SetUpDecorationShape(u8 taskId);
|
||
|
static void AttemptPlaceDecoration(u8 taskId);
|
||
|
static void AttemptCancelPlaceDecoration(u8 taskId);
|
||
|
static void AttemptPlaceDecoration_(u8 taskId);
|
||
|
static void PlaceDecorationPrompt(u8 taskId);
|
||
|
static void PlaceDecoration(u8 taskId);
|
||
|
static void PlaceDecoration_(u8 taskId);
|
||
|
static void CancelDecoratingPrompt(u8 taskId);
|
||
|
static void CancelDecorating(u8 taskId);
|
||
|
static void CancelDecorating_(u8 taskId);
|
||
|
static void c1_overworld_prev_quest(u8 taskId);
|
||
|
static void FieldCB_InitDecorationItemsWindow(void);
|
||
|
static void ResetCursorMovement(void);
|
||
|
static void ContinueDecorating(u8 taskId);
|
||
|
static void CantPlaceDecorationPrompt(u8 taskId);
|
||
|
static void InitializePuttingAwayCursorSprite(struct Sprite *sprite);
|
||
|
static void InitializePuttingAwayCursorSprite2(struct Sprite *sprite);
|
||
|
static u8 gpu_pal_decompress_alloc_tag_and_upload(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor);
|
||
|
static const u32 *GetDecorationIconPicOrPalette(u16 decor, u8 mode);
|
||
|
static bool8 HasDecorationsInUse(u8 taskId);
|
||
|
static void Task_ContinuePuttingAwayDecorations(u8 taskId);
|
||
|
static void ContinuePuttingAwayDecorations(u8 taskId);
|
||
|
static void AttemptPutAwayDecoration(u8 taskId);
|
||
|
static void AttemptCancelPutAwayDecoration(u8 taskId);
|
||
|
static void AttemptPutAwayDecoration_(u8 taskId);
|
||
|
static void ContinuePuttingAwayDecorationsPrompt(u8 taskId);
|
||
|
static void AttemptMarkDecorUnderCursorForRemoval(u8 taskId);
|
||
|
static void ReturnDecorationPrompt(u8 taskId);
|
||
|
static void PutAwayDecoration(u8 taskId);
|
||
|
static void StopPuttingAwayDecorationsPrompt(u8 taskId);
|
||
|
static void StopPuttingAwayDecorations(u8 taskId);
|
||
|
static void StopPuttingAwayDecorations_(u8 taskId);
|
||
|
static void Task_StopPuttingAwayDecorations(u8 taskId);
|
||
|
static void FieldCB_StopPuttingAwayDecorations(void);
|
||
|
static void InitializeCameraSprite1(struct Sprite *sprite);
|
||
|
static void LoadPlayerSpritePalette(void);
|
||
|
static void FreePlayerSpritePalette(void);
|
||
|
static void DecorationItemsMenuAction_AttemptToss(u8 taskId);
|
||
|
static void TossDecorationPrompt(u8 taskId);
|
||
|
static void TossDecoration(u8 taskId);
|
||
|
|
||
|
#include "data/decoration/tiles.h"
|
||
|
#include "data/decoration/description.h"
|
||
|
#include "data/decoration/header.h"
|
||
|
|
||
|
static const u8 *const sDecorationCategoryNames[] =
|
||
|
{
|
||
|
gText_Desk,
|
||
|
gText_Chair,
|
||
|
gText_Plant,
|
||
|
gText_Ornament,
|
||
|
gText_Mat,
|
||
|
gText_Poster,
|
||
|
gText_Doll,
|
||
|
gText_Cushion
|
||
|
};
|
||
|
|
||
|
static const struct MenuAction sDecorationMainMenuActions[] =
|
||
|
{
|
||
|
{
|
||
|
.text = gText_Decorate,
|
||
|
.func = { .void_u8 = DecorationMenuAction_Decorate },
|
||
|
},
|
||
|
{
|
||
|
.text = gText_PutAway,
|
||
|
.func = { .void_u8 = DecorationMenuAction_PutAway },
|
||
|
},
|
||
|
{
|
||
|
.text = gText_Toss2,
|
||
|
.func = { .void_u8 = DecorationMenuAction_Toss },
|
||
|
},
|
||
|
{
|
||
|
.text = gText_Cancel,
|
||
|
.func = { .void_u8 = DecorationMenuAction_Cancel },
|
||
|
},
|
||
|
};
|
||
|
|
||
|
static const u8 *const sSecretBasePCMenuItemDescriptions[] =
|
||
|
{
|
||
|
gText_PutOutSelectedDecorItem,
|
||
|
gText_StoreChosenDecorInPC,
|
||
|
gText_ThrowAwayUnwantedDecors,
|
||
|
gText_GoBackPrevMenu
|
||
|
};
|
||
|
|
||
|
static const TaskFunc sSecretBasePC_SelectedDecorationActions[][2] =
|
||
|
{
|
||
|
{ DecorationItemsMenuAction_AttemptPlace, DecorationItemsMenuAction_Cancel },
|
||
|
{ DecorationItemsMenuAction_AttemptToss, DecorationItemsMenuAction_Cancel },
|
||
|
{ DecorationItemsMenuAction_Trade, DecorationItemsMenuAction_Cancel },
|
||
|
};
|
||
|
|
||
|
static const struct WindowTemplate sDecorationWindowTemplates[WINDOW_COUNT] =
|
||
|
{
|
||
|
{
|
||
|
.bg = 0,
|
||
|
.tilemapLeft = 1,
|
||
|
.tilemapTop = 1,
|
||
|
.width = 18,
|
||
|
.height = 2 * ARRAY_COUNT(sDecorationMainMenuActions),
|
||
|
.paletteNum = 15,
|
||
|
.baseBlock = 0x0001
|
||
|
},
|
||
|
{
|
||
|
.bg = 0,
|
||
|
.tilemapLeft = 1,
|
||
|
.tilemapTop = 1,
|
||
|
.width = 13,
|
||
|
.height = 18,
|
||
|
.paletteNum = 13,
|
||
|
.baseBlock = 0x0091
|
||
|
},
|
||
|
{
|
||
|
.bg = 0,
|
||
|
.tilemapLeft = 17,
|
||
|
.tilemapTop = 1,
|
||
|
.width = 12,
|
||
|
.height = 2,
|
||
|
.paletteNum = 15,
|
||
|
.baseBlock = 0x017b
|
||
|
},
|
||
|
{
|
||
|
.bg = 0,
|
||
|
.tilemapLeft = 16,
|
||
|
.tilemapTop = 13,
|
||
|
.width = 13,
|
||
|
.height = 6,
|
||
|
.paletteNum = 15,
|
||
|
.baseBlock = 0x0193
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static const u16 sDecorationMenuPalette[] = INCBIN_U16("graphics/decorations/decoration_menu.gbapal");
|
||
|
|
||
|
static const struct ListMenuTemplate sDecorationItemsListMenuTemplate =
|
||
|
{
|
||
|
.items = NULL,
|
||
|
.moveCursorFunc = DecorationItemsMenu_OnCursorMove,
|
||
|
.itemPrintFunc = DecorationItemsMenu_PrintDecorationInUse,
|
||
|
.totalItems = 0,
|
||
|
.maxShowed = 0,
|
||
|
.windowId = 0,
|
||
|
.header_X = 0,
|
||
|
.item_X = 8,
|
||
|
.cursor_X = 0,
|
||
|
.upText_Y = 9,
|
||
|
.cursorPal = 2,
|
||
|
.fillValue = 1,
|
||
|
.cursorShadowPal = 3,
|
||
|
.lettersSpacing = FALSE,
|
||
|
.itemVerticalPadding = 0,
|
||
|
.scrollMultiple = FALSE,
|
||
|
.fontId = FONT_NARROW
|
||
|
};
|
||
|
|
||
|
#include "data/decoration/icon.h"
|
||
|
#include "data/decoration/tilemaps.h"
|
||
|
|
||
|
static const struct {
|
||
|
u8 shape;
|
||
|
u8 size;
|
||
|
u8 cameraX;
|
||
|
u8 cameraY;
|
||
|
} sDecorationMovementInfo[] =
|
||
|
{
|
||
|
[DECORSHAPE_1x1] = {SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), 120, 78},
|
||
|
[DECORSHAPE_2x1] = {SPRITE_SHAPE(32x16), SPRITE_SIZE(32x16), 128, 78},
|
||
|
[DECORSHAPE_3x1] = {SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), 144, 86},
|
||
|
[DECORSHAPE_4x2] = {SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), 144, 70},
|
||
|
[DECORSHAPE_2x2] = {SPRITE_SHAPE(32x32), SPRITE_SIZE(32x32), 128, 70},
|
||
|
[DECORSHAPE_1x2] = {SPRITE_SHAPE(16x32), SPRITE_SIZE(16x32), 120, 70},
|
||
|
[DECORSHAPE_1x3] = {SPRITE_SHAPE(32x64), SPRITE_SIZE(32x64), 128, 86},
|
||
|
[DECORSHAPE_2x4] = {SPRITE_SHAPE(32x64), SPRITE_SIZE(32x64), 128, 54},
|
||
|
[DECORSHAPE_3x3] = {SPRITE_SHAPE(64x64), SPRITE_SIZE(64x64), 144, 70},
|
||
|
[DECORSHAPE_3x2] = {SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), 144, 70},
|
||
|
};
|
||
|
|
||
|
static const union AnimCmd sDecorSelectorAnimCmd0[] =
|
||
|
{
|
||
|
ANIMCMD_FRAME(0, 0, FALSE, FALSE),
|
||
|
ANIMCMD_END
|
||
|
};
|
||
|
|
||
|
static const union AnimCmd *const sDecorSelectorAnimCmds[] = { sDecorSelectorAnimCmd0 };
|
||
|
|
||
|
static const struct SpriteFrameImage sDecorSelectorSpriteFrameImages =
|
||
|
{
|
||
|
.data = (const u8 *)&sPlaceDecorationGraphicsDataBuffer.image,
|
||
|
.size = 0x800,
|
||
|
};
|
||
|
|
||
|
static const struct SpriteTemplate sDecorationSelectorSpriteTemplate =
|
||
|
{
|
||
|
TAG_NONE,
|
||
|
PLACE_DECORATION_SELECTOR_TAG,
|
||
|
&sDecorSelectorOam,
|
||
|
sDecorSelectorAnimCmds,
|
||
|
&sDecorSelectorSpriteFrameImages,
|
||
|
gDummySpriteAffineAnimTable,
|
||
|
SpriteCallbackDummy
|
||
|
};
|
||
|
|
||
|
static const struct SpriteTemplate sDecorWhilePlacingSpriteTemplate =
|
||
|
{
|
||
|
0x0000,
|
||
|
0x0000,
|
||
|
&sDecorSelectorOam,
|
||
|
sDecorSelectorAnimCmds,
|
||
|
NULL,
|
||
|
gDummySpriteAffineAnimTable,
|
||
|
SpriteCallbackDummy
|
||
|
};
|
||
|
|
||
|
static const struct SpritePalette sSpritePal_PlaceDecoration =
|
||
|
{
|
||
|
.data = (const u16 *)&sPlaceDecorationGraphicsDataBuffer.palette,
|
||
|
.tag = PLACE_DECORATION_SELECTOR_TAG,
|
||
|
};
|
||
|
|
||
|
static const struct YesNoFuncTable sPlaceDecorationYesNoFunctions =
|
||
|
{
|
||
|
.yesFunc = PlaceDecoration,
|
||
|
.noFunc = ContinueDecorating,
|
||
|
};
|
||
|
|
||
|
static const struct YesNoFuncTable sCancelDecoratingYesNoFunctions =
|
||
|
{
|
||
|
.yesFunc = CancelDecorating,
|
||
|
.noFunc = ContinueDecorating,
|
||
|
};
|
||
|
|
||
|
static const struct YesNoFuncTable sPlacePutAwayYesNoFunctions[] =
|
||
|
{
|
||
|
{
|
||
|
.yesFunc = AttemptPlaceDecoration,
|
||
|
.noFunc = AttemptCancelPlaceDecoration,
|
||
|
},
|
||
|
{
|
||
|
.yesFunc = AttemptPutAwayDecoration,
|
||
|
.noFunc = AttemptCancelPutAwayDecoration,
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static const u8 sDecorationStandElevations[] =
|
||
|
{
|
||
|
4, 4, 4, 4,
|
||
|
0, 3, 3, 0
|
||
|
};
|
||
|
|
||
|
static const u8 sDecorationSlideElevation[] =
|
||
|
{
|
||
|
4, 4,
|
||
|
4, 4,
|
||
|
0, 4,
|
||
|
3, 0,
|
||
|
};
|
||
|
|
||
|
static const u16 sDecorShapeSizes[] = {
|
||
|
0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x20
|
||
|
};
|
||
|
|
||
|
static const u16 sBrendanPalette[] = INCBIN_U16("graphics/decorations/brendan.gbapal");
|
||
|
|
||
|
static const u16 sMayPalette[] = INCBIN_U16("graphics/decorations/may.gbapal");
|
||
|
|
||
|
static const struct YesNoFuncTable sReturnDecorationYesNoFunctions =
|
||
|
{
|
||
|
.yesFunc = PutAwayDecoration,
|
||
|
.noFunc = ContinuePuttingAwayDecorations,
|
||
|
};
|
||
|
|
||
|
static const struct YesNoFuncTable sStopPuttingAwayDecorationsYesNoFunctions =
|
||
|
{
|
||
|
.yesFunc = StopPuttingAwayDecorations,
|
||
|
.noFunc = ContinuePuttingAwayDecorations,
|
||
|
};
|
||
|
|
||
|
static const u8 sDecorationPuttingAwayCursor[] = INCBIN_U8("graphics/misc/decoration_putting_away_cursor.4bpp");
|
||
|
|
||
|
static const struct SpritePalette sSpritePal_PuttingAwayCursorBrendan =
|
||
|
{
|
||
|
.data = sBrendanPalette,
|
||
|
.tag = PLACE_DECORATION_PLAYER_TAG,
|
||
|
};
|
||
|
|
||
|
static const struct SpritePalette sSpritePal_PuttingAwayCursorMay =
|
||
|
{
|
||
|
.data = sMayPalette,
|
||
|
.tag = PLACE_DECORATION_PLAYER_TAG,
|
||
|
};
|
||
|
|
||
|
static const struct OamData sPuttingAwayCursorOamData =
|
||
|
{
|
||
|
.y = 0,
|
||
|
.affineMode = ST_OAM_AFFINE_OFF,
|
||
|
.objMode = ST_OAM_OBJ_NORMAL,
|
||
|
.bpp = ST_OAM_4BPP,
|
||
|
.shape = SPRITE_SHAPE(16x16),
|
||
|
.x = 0,
|
||
|
.size = SPRITE_SIZE(16x16),
|
||
|
.tileNum = 0,
|
||
|
.priority = 1,
|
||
|
.paletteNum = 0,
|
||
|
};
|
||
|
|
||
|
static const union AnimCmd sPuttingAwayCursorAnimCmd0[] =
|
||
|
{
|
||
|
ANIMCMD_FRAME(0, 0, 0),
|
||
|
ANIMCMD_END
|
||
|
};
|
||
|
|
||
|
static const union AnimCmd *const sPuttingAwayCursorAnimCmds[] =
|
||
|
{
|
||
|
sPuttingAwayCursorAnimCmd0,
|
||
|
};
|
||
|
|
||
|
static const struct SpriteFrameImage sPuttingAwayCursorPicTable =
|
||
|
{
|
||
|
.data = sDecorationPuttingAwayCursor,
|
||
|
.size = sizeof(sDecorationPuttingAwayCursor),
|
||
|
};
|
||
|
|
||
|
static const struct SpriteTemplate sPuttingAwayCursorSpriteTemplate =
|
||
|
{
|
||
|
TAG_NONE,
|
||
|
PLACE_DECORATION_PLAYER_TAG,
|
||
|
&sPuttingAwayCursorOamData,
|
||
|
sPuttingAwayCursorAnimCmds,
|
||
|
&sPuttingAwayCursorPicTable,
|
||
|
gDummySpriteAffineAnimTable,
|
||
|
InitializeCameraSprite1
|
||
|
};
|
||
|
|
||
|
static const struct YesNoFuncTable sTossDecorationYesNoFunctions =
|
||
|
{
|
||
|
.yesFunc = TossDecoration,
|
||
|
.noFunc = DontTossDecoration,
|
||
|
};
|
||
|
|
||
|
void InitDecorationContextItems(void)
|
||
|
{
|
||
|
if (sCurDecorationCategory < DECORCAT_COUNT)
|
||
|
gCurDecorationItems = gDecorationInventories[sCurDecorationCategory].items;
|
||
|
|
||
|
if (sDecorationContext.isPlayerRoom == FALSE)
|
||
|
{
|
||
|
sDecorationContext.items = gSaveBlock1Ptr->secretBases[0].decorations;
|
||
|
sDecorationContext.pos = gSaveBlock1Ptr->secretBases[0].decorationPositions;
|
||
|
}
|
||
|
|
||
|
if (sDecorationContext.isPlayerRoom == TRUE)
|
||
|
{
|
||
|
sDecorationContext.items = gSaveBlock1Ptr->playerRoomDecorations;
|
||
|
sDecorationContext.pos = gSaveBlock1Ptr->playerRoomDecorationPositions;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static u8 AddDecorationWindow(u8 windowIndex)
|
||
|
{
|
||
|
u8 *windowId;
|
||
|
struct WindowTemplate template;
|
||
|
|
||
|
windowId = &sDecorMenuWindowIds[windowIndex];
|
||
|
if (windowIndex == WINDOW_MAIN_MENU)
|
||
|
{
|
||
|
template = sDecorationWindowTemplates[WINDOW_MAIN_MENU];
|
||
|
template.width = GetMaxWidthInMenuTable(sDecorationMainMenuActions, ARRAY_COUNT(sDecorationMainMenuActions));
|
||
|
if (template.width > 18)
|
||
|
template.width = 18;
|
||
|
|
||
|
*windowId = AddWindow(&template);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*windowId = AddWindow(&sDecorationWindowTemplates[windowIndex]);
|
||
|
}
|
||
|
|
||
|
DrawStdFrameWithCustomTileAndPalette(*windowId, FALSE, 0x214, 14);
|
||
|
ScheduleBgCopyTilemapToVram(0);
|
||
|
return *windowId;
|
||
|
}
|
||
|
|
||
|
static void RemoveDecorationWindow(u8 windowIndex)
|
||
|
{
|
||
|
ClearStdWindowAndFrameToTransparent(sDecorMenuWindowIds[windowIndex], FALSE);
|
||
|
ClearWindowTilemap(sDecorMenuWindowIds[windowIndex]);
|
||
|
RemoveWindow(sDecorMenuWindowIds[windowIndex]);
|
||
|
ScheduleBgCopyTilemapToVram(0);
|
||
|
}
|
||
|
|
||
|
static void AddDecorationActionsWindow(void)
|
||
|
{
|
||
|
u8 windowId = AddDecorationWindow(WINDOW_MAIN_MENU);
|
||
|
PrintMenuTable(windowId, ARRAY_COUNT(sDecorationMainMenuActions), sDecorationMainMenuActions);
|
||
|
InitMenuInUpperLeftCornerNormal(windowId, ARRAY_COUNT(sDecorationMainMenuActions), sDecorationActionsCursorPos);
|
||
|
}
|
||
|
|
||
|
static void InitDecorationActionsWindow(void)
|
||
|
{
|
||
|
sDecorationActionsCursorPos = 0;
|
||
|
ScriptContext2_Enable();
|
||
|
AddDecorationActionsWindow();
|
||
|
PrintCurMainMenuDescription();
|
||
|
}
|
||
|
|
||
|
void DoSecretBaseDecorationMenu(u8 taskId)
|
||
|
{
|
||
|
InitDecorationActionsWindow();
|
||
|
sDecorationContext.items = gSaveBlock1Ptr->secretBases[0].decorations;
|
||
|
sDecorationContext.pos = gSaveBlock1Ptr->secretBases[0].decorationPositions;
|
||
|
sDecorationContext.size = DECOR_MAX_SECRET_BASE;
|
||
|
sDecorationContext.isPlayerRoom = FALSE;
|
||
|
gTasks[taskId].func = HandleDecorationActionsMenuInput;
|
||
|
}
|
||
|
|
||
|
void DoPlayerRoomDecorationMenu(u8 taskId)
|
||
|
{
|
||
|
InitDecorationActionsWindow();
|
||
|
sDecorationContext.items = gSaveBlock1Ptr->playerRoomDecorations;
|
||
|
sDecorationContext.pos = gSaveBlock1Ptr->playerRoomDecorationPositions;
|
||
|
sDecorationContext.size = DECOR_MAX_PLAYERS_HOUSE;
|
||
|
sDecorationContext.isPlayerRoom = TRUE;
|
||
|
gTasks[taskId].func = HandleDecorationActionsMenuInput;
|
||
|
}
|
||
|
|
||
|
static void HandleDecorationActionsMenuInput(u8 taskId)
|
||
|
{
|
||
|
if (!gPaletteFade.active)
|
||
|
{
|
||
|
s8 menuPos = Menu_GetCursorPos();
|
||
|
switch (Menu_ProcessInput())
|
||
|
{
|
||
|
default:
|
||
|
PlaySE(SE_SELECT);
|
||
|
sDecorationMainMenuActions[sDecorationActionsCursorPos].func.void_u8(taskId);
|
||
|
break;
|
||
|
case MENU_NOTHING_CHOSEN:
|
||
|
sDecorationActionsCursorPos = Menu_GetCursorPos();
|
||
|
if (menuPos != sDecorationActionsCursorPos)
|
||
|
PrintCurMainMenuDescription();
|
||
|
break;
|
||
|
case MENU_B_PRESSED:
|
||
|
PlaySE(SE_SELECT);
|
||
|
DecorationMenuAction_Cancel(taskId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void PrintCurMainMenuDescription(void)
|
||
|
{
|
||
|
FillWindowPixelBuffer(0, PIXEL_FILL(1));
|
||
|
AddTextPrinterParameterized2(0, FONT_NORMAL, sSecretBasePCMenuItemDescriptions[sDecorationActionsCursorPos], 0, 0, 2, 1, 3);
|
||
|
}
|
||
|
|
||
|
static void DecorationMenuAction_Decorate(u8 taskId)
|
||
|
{
|
||
|
if (GetNumOwnedDecorations() == 0)
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_NoDecorations);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationActionsAfterInvalidSelection);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gTasks[taskId].tDecorationMenuCommand = DECOR_MENU_PLACE;
|
||
|
sCurDecorationCategory = DECORCAT_DESK;
|
||
|
SecretBasePC_PrepMenuForSelectingStoredDecors(taskId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DecorationMenuAction_PutAway(u8 taskId)
|
||
|
{
|
||
|
if (!HasDecorationsInUse(taskId))
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_NoDecorationsInUse);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationActionsAfterInvalidSelection);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RemoveDecorationWindow(WINDOW_MAIN_MENU);
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
FadeScreen(FADE_TO_BLACK, 0);
|
||
|
gTasks[taskId].tState = 0;
|
||
|
gTasks[taskId].func = Task_ContinuePuttingAwayDecorations;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DecorationMenuAction_Toss(u8 taskId)
|
||
|
{
|
||
|
if (GetNumOwnedDecorations() == 0)
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_NoDecorations);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationActionsAfterInvalidSelection);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gTasks[taskId].tDecorationMenuCommand = DECOR_MENU_TOSS;
|
||
|
sCurDecorationCategory = DECORCAT_DESK;
|
||
|
SecretBasePC_PrepMenuForSelectingStoredDecors(taskId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DecorationMenuAction_Cancel(u8 taskId)
|
||
|
{
|
||
|
RemoveDecorationWindow(WINDOW_MAIN_MENU);
|
||
|
if (!sDecorationContext.isPlayerRoom)
|
||
|
{
|
||
|
ScriptContext1_SetupScript(SecretBase_EventScript_PCCancel);
|
||
|
DestroyTask(taskId);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ReshowPlayerPC(taskId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ReturnToDecorationActionsAfterInvalidSelection(u8 taskId)
|
||
|
{
|
||
|
PrintCurMainMenuDescription();
|
||
|
gTasks[taskId].func = HandleDecorationActionsMenuInput;
|
||
|
}
|
||
|
|
||
|
static void SecretBasePC_PrepMenuForSelectingStoredDecors(u8 taskId)
|
||
|
{
|
||
|
LoadPalette(sDecorationMenuPalette, 0xd0, 0x20);
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
RemoveDecorationWindow(WINDOW_MAIN_MENU);
|
||
|
InitDecorationCategoriesWindow(taskId);
|
||
|
}
|
||
|
|
||
|
static void InitDecorationCategoriesWindow(u8 taskId)
|
||
|
{
|
||
|
u8 windowId = AddDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
PrintDecorationCategoryMenuItems(taskId);
|
||
|
InitMenuInUpperLeftCornerNormal(windowId, DECORCAT_COUNT + 1, sCurDecorationCategory);
|
||
|
gTasks[taskId].func = HandleDecorationCategoriesMenuInput;
|
||
|
}
|
||
|
|
||
|
static void ReinitDecorationCategoriesWindow(u8 taskId)
|
||
|
{
|
||
|
FillWindowPixelBuffer(sDecorMenuWindowIds[WINDOW_DECORATION_CATEGORIES], PIXEL_FILL(1));
|
||
|
PrintDecorationCategoryMenuItems(taskId);
|
||
|
InitMenuInUpperLeftCornerNormal(sDecorMenuWindowIds[WINDOW_DECORATION_CATEGORIES], DECORCAT_COUNT + 1, sCurDecorationCategory);
|
||
|
gTasks[taskId].func = HandleDecorationCategoriesMenuInput;
|
||
|
}
|
||
|
|
||
|
static void PrintDecorationCategoryMenuItems(u8 taskId)
|
||
|
{
|
||
|
u8 i;
|
||
|
s16 *data = gTasks[taskId].data;
|
||
|
u8 windowId = sDecorMenuWindowIds[WINDOW_DECORATION_CATEGORIES];
|
||
|
bool8 isPlayerRoom = sDecorationContext.isPlayerRoom;
|
||
|
bool8 shouldDisable = FALSE;
|
||
|
if (isPlayerRoom == TRUE && tDecorationMenuCommand == DECOR_MENU_PLACE)
|
||
|
shouldDisable = TRUE;
|
||
|
|
||
|
for (i = 0; i < DECORCAT_COUNT; i++)
|
||
|
{
|
||
|
// Only DOLL and CUSHION decorations are enabled when decorating the player's room.
|
||
|
if (shouldDisable == TRUE && i != DECORCAT_DOLL && i != DECORCAT_CUSHION)
|
||
|
PrintDecorationCategoryMenuItem(windowId, i, 8, i * 16, TRUE, TEXT_SKIP_DRAW);
|
||
|
else
|
||
|
PrintDecorationCategoryMenuItem(windowId, i, 8, i * 16, FALSE, TEXT_SKIP_DRAW);
|
||
|
}
|
||
|
|
||
|
AddTextPrinterParameterized(windowId, FONT_NORMAL, gTasks[taskId].tDecorationMenuCommand == DECOR_MENU_TRADE ? gText_Exit : gText_Cancel, 8, i * 16 + 1, 0, NULL);
|
||
|
ScheduleBgCopyTilemapToVram(0);
|
||
|
}
|
||
|
|
||
|
static void PrintDecorationCategoryMenuItem(u8 winid, u8 category, u8 x, u8 y, bool8 disabled, u8 speed)
|
||
|
{
|
||
|
u8 width;
|
||
|
u8 *str;
|
||
|
|
||
|
width = x == 8 ? 104 : 96;
|
||
|
y++;
|
||
|
ColorMenuItemString(gStringVar4, disabled);
|
||
|
str = StringLength(gStringVar4) + gStringVar4;
|
||
|
StringCopy(str, sDecorationCategoryNames[category]);
|
||
|
AddTextPrinterParameterized(winid, FONT_NORMAL, gStringVar4, x, y, speed, NULL);
|
||
|
str = ConvertIntToDecimalStringN(str, GetNumOwnedDecorationsInCategory(category), STR_CONV_MODE_RIGHT_ALIGN, 2);
|
||
|
*(str++) = CHAR_SLASH;
|
||
|
ConvertIntToDecimalStringN(str, gDecorationInventories[category].size, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
||
|
x = GetStringRightAlignXOffset(FONT_NORMAL, gStringVar4, width);
|
||
|
AddTextPrinterParameterized(winid, FONT_NORMAL, gStringVar4, x, y, speed, NULL);
|
||
|
}
|
||
|
|
||
|
static void ColorMenuItemString(u8 *str, bool8 disabled)
|
||
|
{
|
||
|
StringCopy(str, gText_Color161Shadow161);
|
||
|
if (disabled == TRUE)
|
||
|
{
|
||
|
str[2] = 4;
|
||
|
str[5] = 5;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
str[2] = 2;
|
||
|
str[5] = 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void HandleDecorationCategoriesMenuInput(u8 taskId)
|
||
|
{
|
||
|
if (!gPaletteFade.active)
|
||
|
{
|
||
|
s8 input = Menu_ProcessInput();
|
||
|
switch (input)
|
||
|
{
|
||
|
case MENU_B_PRESSED:
|
||
|
case DECORCAT_COUNT: // CANCEL
|
||
|
PlaySE(SE_SELECT);
|
||
|
ExitDecorationCategoriesMenu(taskId);
|
||
|
break;
|
||
|
case MENU_NOTHING_CHOSEN:
|
||
|
break;
|
||
|
default:
|
||
|
PlaySE(SE_SELECT);
|
||
|
sCurDecorationCategory = input;
|
||
|
SelectDecorationCategory(taskId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void SelectDecorationCategory(u8 taskId)
|
||
|
{
|
||
|
sNumOwnedDecorationsInCurCategory = GetNumOwnedDecorationsInCategory(sCurDecorationCategory);
|
||
|
if (sNumOwnedDecorationsInCurCategory != 0)
|
||
|
{
|
||
|
CondenseDecorationsInCategory(sCurDecorationCategory);
|
||
|
gCurDecorationItems = gDecorationInventories[sCurDecorationCategory].items;
|
||
|
IdentifyOwnedDecorationsCurrentlyInUse(taskId);
|
||
|
sDecorationsScrollOffset = 0;
|
||
|
sDecorationsCursorPos = 0;
|
||
|
gTasks[taskId].func = ShowDecorationItemsWindow;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RemoveDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
StringExpandPlaceholders(gStringVar4, gText_NoDecorations);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationCategoriesAfterInvalidSelection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ReturnToDecorationCategoriesAfterInvalidSelection(u8 taskId)
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
InitDecorationCategoriesWindow(taskId);
|
||
|
}
|
||
|
|
||
|
static void ExitDecorationCategoriesMenu(u8 taskId)
|
||
|
{
|
||
|
if (gTasks[taskId].tDecorationMenuCommand != DECOR_MENU_TRADE)
|
||
|
ReturnToActionsMenuFromCategories(taskId);
|
||
|
else
|
||
|
ExitTraderDecorationMenu(taskId);
|
||
|
}
|
||
|
|
||
|
static void ReturnToActionsMenuFromCategories(u8 taskId)
|
||
|
{
|
||
|
RemoveDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
AddDecorationActionsWindow();
|
||
|
DrawDialogueFrame(0, 0);
|
||
|
PrintCurMainMenuDescription();
|
||
|
gTasks[taskId].func = HandleDecorationActionsMenuInput;
|
||
|
}
|
||
|
|
||
|
void ShowDecorationCategoriesWindow(u8 taskId)
|
||
|
{
|
||
|
LoadPalette(sDecorationMenuPalette, 0xd0, 0x20);
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
gTasks[taskId].tDecorationMenuCommand = DECOR_MENU_TRADE;
|
||
|
sCurDecorationCategory = DECORCAT_DESK;
|
||
|
InitDecorationCategoriesWindow(taskId);
|
||
|
}
|
||
|
|
||
|
void CopyDecorationCategoryName(u8 *dest, u8 category)
|
||
|
{
|
||
|
StringCopy(dest, sDecorationCategoryNames[category]);
|
||
|
}
|
||
|
|
||
|
static void ExitTraderDecorationMenu(u8 taskId)
|
||
|
{
|
||
|
RemoveDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
ExitTraderMenu(taskId);
|
||
|
}
|
||
|
|
||
|
static void InitDecorationItemsMenuLimits(void)
|
||
|
{
|
||
|
sDecorationItemsMenu->numMenuItems = sNumOwnedDecorationsInCurCategory + 1;
|
||
|
if (sDecorationItemsMenu->numMenuItems > 8)
|
||
|
sDecorationItemsMenu->maxShownItems = 8;
|
||
|
else
|
||
|
sDecorationItemsMenu->maxShownItems = sDecorationItemsMenu->numMenuItems;
|
||
|
}
|
||
|
|
||
|
static void InitDecorationItemsMenuScrollAndCursor(void)
|
||
|
{
|
||
|
SetCursorWithinListBounds(&sDecorationsScrollOffset, &sDecorationsCursorPos, sDecorationItemsMenu->maxShownItems, sDecorationItemsMenu->numMenuItems);
|
||
|
}
|
||
|
|
||
|
static void InitDecorationItemsMenuScrollAndCursor2(void)
|
||
|
{
|
||
|
SetCursorScrollWithinListBounds(&sDecorationsScrollOffset, &sDecorationsCursorPos, sDecorationItemsMenu->maxShownItems, sDecorationItemsMenu->numMenuItems, 8);
|
||
|
}
|
||
|
|
||
|
static void PrintDecorationItemMenuItems(u8 taskId)
|
||
|
{
|
||
|
s16 *data;
|
||
|
u16 i;
|
||
|
|
||
|
data = gTasks[taskId].data;
|
||
|
if ((sCurDecorationCategory < DECORCAT_DOLL || sCurDecorationCategory > DECORCAT_CUSHION) && sDecorationContext.isPlayerRoom == TRUE && tDecorationMenuCommand == DECOR_MENU_PLACE)
|
||
|
ColorMenuItemString(gStringVar1, TRUE);
|
||
|
else
|
||
|
ColorMenuItemString(gStringVar1, FALSE);
|
||
|
|
||
|
for (i = 0; i < sDecorationItemsMenu->numMenuItems - 1; i++)
|
||
|
{
|
||
|
CopyDecorationMenuItemName(sDecorationItemsMenu->names[i], gCurDecorationItems[i]);
|
||
|
sDecorationItemsMenu->items[i].name = sDecorationItemsMenu->names[i];
|
||
|
sDecorationItemsMenu->items[i].id = i;
|
||
|
}
|
||
|
|
||
|
StringCopy(sDecorationItemsMenu->names[i], gText_Cancel);
|
||
|
sDecorationItemsMenu->items[i].name = sDecorationItemsMenu->names[i];
|
||
|
sDecorationItemsMenu->items[i].id = -2;
|
||
|
gMultiuseListMenuTemplate = sDecorationItemsListMenuTemplate;
|
||
|
gMultiuseListMenuTemplate.windowId = sDecorMenuWindowIds[WINDOW_DECORATION_CATEGORIES];
|
||
|
gMultiuseListMenuTemplate.totalItems = sDecorationItemsMenu->numMenuItems;
|
||
|
gMultiuseListMenuTemplate.items = sDecorationItemsMenu->items;
|
||
|
gMultiuseListMenuTemplate.maxShowed = sDecorationItemsMenu->maxShownItems;
|
||
|
}
|
||
|
|
||
|
static void CopyDecorationMenuItemName(u8 *dest, u16 decoration)
|
||
|
{
|
||
|
StringCopy(dest, gStringVar1);
|
||
|
StringAppend(dest, gDecorations[decoration].name);
|
||
|
}
|
||
|
|
||
|
static void DecorationItemsMenu_OnCursorMove(s32 itemIndex, bool8 flag, struct ListMenu *menu)
|
||
|
{
|
||
|
if (flag != TRUE)
|
||
|
PlaySE(SE_SELECT);
|
||
|
|
||
|
PrintDecorationItemDescription(itemIndex);
|
||
|
}
|
||
|
|
||
|
static void DecorationItemsMenu_PrintDecorationInUse(u8 windowId, u32 itemIndex, u8 y)
|
||
|
{
|
||
|
if (itemIndex != LIST_CANCEL)
|
||
|
{
|
||
|
if (IsDecorationIndexInSecretBase(itemIndex + 1) == TRUE)
|
||
|
BlitMenuInfoIcon(windowId, MENU_INFO_ICON_BALL_RED, 92, y + 2);
|
||
|
else if (IsDecorationIndexInPlayersRoom(itemIndex + 1) == TRUE)
|
||
|
BlitMenuInfoIcon(windowId, MENU_INFO_ICON_BALL_BLUE, 92, y + 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void AddDecorationItemsScrollIndicators(void)
|
||
|
{
|
||
|
if (sDecorationItemsMenu->scrollIndicatorsTaskId == TASK_NONE)
|
||
|
{
|
||
|
sDecorationItemsMenu->scrollIndicatorsTaskId = AddScrollIndicatorArrowPairParameterized(
|
||
|
SCROLL_ARROW_UP,
|
||
|
0x3c,
|
||
|
0x0c,
|
||
|
0x94,
|
||
|
sDecorationItemsMenu->numMenuItems - sDecorationItemsMenu->maxShownItems,
|
||
|
0x6e,
|
||
|
0x6e,
|
||
|
&sDecorationsScrollOffset);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void RemoveDecorationItemsScrollIndicators(void)
|
||
|
{
|
||
|
if (sDecorationItemsMenu->scrollIndicatorsTaskId != TASK_NONE)
|
||
|
{
|
||
|
RemoveScrollIndicatorArrowPair(sDecorationItemsMenu->scrollIndicatorsTaskId);
|
||
|
sDecorationItemsMenu->scrollIndicatorsTaskId = TASK_NONE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void AddDecorationItemsWindow(u8 taskId)
|
||
|
{
|
||
|
AddDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
InitDecorationItemsWindow(taskId);
|
||
|
}
|
||
|
|
||
|
static void InitDecorationItemsWindow(u8 taskId)
|
||
|
{
|
||
|
s16 *data = gTasks[taskId].data;
|
||
|
AddDecorationWindow(WINDOW_DECORATION_CATEGORY_ITEMS);
|
||
|
ShowDecorationCategorySummaryWindow(sCurDecorationCategory);
|
||
|
sDecorationItemsMenu = AllocZeroed(sizeof(*sDecorationItemsMenu));
|
||
|
sDecorationItemsMenu->scrollIndicatorsTaskId = TASK_NONE;
|
||
|
InitDecorationItemsMenuLimits();
|
||
|
InitDecorationItemsMenuScrollAndCursor();
|
||
|
InitDecorationItemsMenuScrollAndCursor2();
|
||
|
PrintDecorationItemMenuItems(taskId);
|
||
|
tMenuTaskId = ListMenuInit(&gMultiuseListMenuTemplate, sDecorationsScrollOffset, sDecorationsCursorPos);
|
||
|
AddDecorationItemsScrollIndicators();
|
||
|
}
|
||
|
|
||
|
static void ShowDecorationItemsWindow(u8 taskId)
|
||
|
{
|
||
|
InitDecorationItemsWindow(taskId);
|
||
|
gTasks[taskId].func = HandleDecorationItemsMenuInput;
|
||
|
}
|
||
|
|
||
|
static void HandleDecorationItemsMenuInput(u8 taskId)
|
||
|
{
|
||
|
s16 *data;
|
||
|
s32 input;
|
||
|
|
||
|
data = gTasks[taskId].data;
|
||
|
if (!gPaletteFade.active)
|
||
|
{
|
||
|
input = ListMenu_ProcessInput(tMenuTaskId);
|
||
|
ListMenuGetScrollAndRow(tMenuTaskId, &sDecorationsScrollOffset, &sDecorationsCursorPos);
|
||
|
switch (input)
|
||
|
{
|
||
|
case LIST_NOTHING_CHOSEN:
|
||
|
break;
|
||
|
case LIST_CANCEL:
|
||
|
PlaySE(SE_SELECT);
|
||
|
sSecretBasePC_SelectedDecorationActions[tDecorationMenuCommand][1](taskId);
|
||
|
break;
|
||
|
default:
|
||
|
PlaySE(SE_SELECT);
|
||
|
gCurDecorationIndex = input;
|
||
|
RemoveDecorationItemsScrollIndicators();
|
||
|
DestroyListMenuTask(tMenuTaskId, &sDecorationsScrollOffset, &sDecorationsCursorPos);
|
||
|
RemoveDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
RemoveDecorationItemsOtherWindows();
|
||
|
free(sDecorationItemsMenu);
|
||
|
sSecretBasePC_SelectedDecorationActions[tDecorationMenuCommand][0](taskId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ShowDecorationCategorySummaryWindow(u8 category)
|
||
|
{
|
||
|
PrintDecorationCategoryMenuItem(AddDecorationWindow(WINDOW_DECORATION_CATEGORY_SUMMARY), category, 0, 0, 0, 0);
|
||
|
}
|
||
|
|
||
|
static void PrintDecorationItemDescription(s32 itemIndex)
|
||
|
{
|
||
|
u8 windowId;
|
||
|
const u8 *str;
|
||
|
|
||
|
windowId = sDecorMenuWindowIds[WINDOW_DECORATION_CATEGORY_ITEMS];
|
||
|
FillWindowPixelBuffer(windowId, PIXEL_FILL(1));
|
||
|
if ((u32)itemIndex >= sNumOwnedDecorationsInCurCategory)
|
||
|
str = gText_GoBackPrevMenu;
|
||
|
else
|
||
|
str = gDecorations[gCurDecorationItems[itemIndex]].description;
|
||
|
|
||
|
AddTextPrinterParameterized(windowId, FONT_NORMAL, str, 0, 1, 0, 0);
|
||
|
}
|
||
|
|
||
|
static void RemoveDecorationItemsOtherWindows(void)
|
||
|
{
|
||
|
RemoveDecorationWindow(WINDOW_DECORATION_CATEGORY_ITEMS);
|
||
|
RemoveDecorationWindow(WINDOW_DECORATION_CATEGORY_SUMMARY);
|
||
|
}
|
||
|
|
||
|
static bool8 IsDecorationIndexInSecretBase(u8 idx)
|
||
|
{
|
||
|
u8 i;
|
||
|
for (i = 0; i < ARRAY_COUNT(sSecretBaseItemsIndicesBuffer); i++)
|
||
|
{
|
||
|
if (sSecretBaseItemsIndicesBuffer[i] == idx)
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static bool8 IsDecorationIndexInPlayersRoom(u8 idx)
|
||
|
{
|
||
|
u8 i;
|
||
|
for (i = 0; i < ARRAY_COUNT(sPlayerRoomItemsIndicesBuffer); i++)
|
||
|
{
|
||
|
if (sPlayerRoomItemsIndicesBuffer[i] == idx)
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void IdentifyOwnedDecorationsCurrentlyInUseInternal(u8 taskId)
|
||
|
{
|
||
|
u16 i, j, k;
|
||
|
u16 count;
|
||
|
|
||
|
count = 0;
|
||
|
memset(sSecretBaseItemsIndicesBuffer, 0, sizeof(sSecretBaseItemsIndicesBuffer));
|
||
|
memset(sPlayerRoomItemsIndicesBuffer, 0, sizeof(sPlayerRoomItemsIndicesBuffer));
|
||
|
|
||
|
for (i = 0; i < ARRAY_COUNT(sSecretBaseItemsIndicesBuffer); i++)
|
||
|
{
|
||
|
if (gSaveBlock1Ptr->secretBases[0].decorations[i] != DECOR_NONE)
|
||
|
{
|
||
|
for (j = 0; j < gDecorationInventories[sCurDecorationCategory].size; j++)
|
||
|
{
|
||
|
if (gCurDecorationItems[j] == gSaveBlock1Ptr->secretBases[0].decorations[i])
|
||
|
{
|
||
|
for (k = 0; k < count && sSecretBaseItemsIndicesBuffer[k] != j + 1; k++)
|
||
|
;
|
||
|
|
||
|
if (k == count)
|
||
|
{
|
||
|
sSecretBaseItemsIndicesBuffer[count] = j + 1;
|
||
|
count++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
count = 0;
|
||
|
for (i = 0; i < ARRAY_COUNT(sPlayerRoomItemsIndicesBuffer); i++)
|
||
|
{
|
||
|
if (gSaveBlock1Ptr->playerRoomDecorations[i] != DECOR_NONE)
|
||
|
{
|
||
|
for (j = 0; j < gDecorationInventories[sCurDecorationCategory].size; j++)
|
||
|
{
|
||
|
if (gCurDecorationItems[j] == gSaveBlock1Ptr->playerRoomDecorations[i] && IsDecorationIndexInSecretBase(j + 1) != TRUE)
|
||
|
{
|
||
|
for (k = 0; k < count && sPlayerRoomItemsIndicesBuffer[k] != j + 1; k++);
|
||
|
if (k == count)
|
||
|
{
|
||
|
sPlayerRoomItemsIndicesBuffer[count] = j + 1;
|
||
|
count++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void IdentifyOwnedDecorationsCurrentlyInUse(u8 taskId)
|
||
|
{
|
||
|
IdentifyOwnedDecorationsCurrentlyInUseInternal(taskId);
|
||
|
}
|
||
|
|
||
|
bool8 IsSelectedDecorInThePC(void)
|
||
|
{
|
||
|
u16 i;
|
||
|
for (i = 0; i < ARRAY_COUNT(sSecretBaseItemsIndicesBuffer); i++)
|
||
|
{
|
||
|
if (sSecretBaseItemsIndicesBuffer[i] == sDecorationsScrollOffset + sDecorationsCursorPos + 1)
|
||
|
return FALSE;
|
||
|
|
||
|
if (i < ARRAY_COUNT(sPlayerRoomItemsIndicesBuffer)
|
||
|
&& sPlayerRoomItemsIndicesBuffer[i] == sDecorationsScrollOffset + sDecorationsCursorPos + 1)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void Task_ShowDecorationItemsWindow(u8 taskId)
|
||
|
{
|
||
|
AddDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
ShowDecorationItemsWindow(taskId);
|
||
|
}
|
||
|
|
||
|
static void DontTossDecoration(u8 taskId)
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
gTasks[taskId].func = Task_ShowDecorationItemsWindow;
|
||
|
}
|
||
|
|
||
|
static void ReturnToDecorationItemsAfterInvalidSelection(u8 taskId)
|
||
|
{
|
||
|
if (JOY_NEW(A_BUTTON | B_BUTTON))
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
AddDecorationWindow(WINDOW_DECORATION_CATEGORIES);
|
||
|
ShowDecorationItemsWindow(taskId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DecorationItemsMenuAction_Cancel(u8 taskId)
|
||
|
{
|
||
|
s16 *data = gTasks[taskId].data;
|
||
|
RemoveDecorationItemsScrollIndicators();
|
||
|
RemoveDecorationItemsOtherWindows();
|
||
|
DestroyListMenuTask(tMenuTaskId, NULL, NULL);
|
||
|
free(sDecorationItemsMenu);
|
||
|
ReinitDecorationCategoriesWindow(taskId);
|
||
|
}
|
||
|
|
||
|
static void SetInitialPositions(u8 taskId)
|
||
|
{
|
||
|
gTasks[taskId].tInitialX = gSaveBlock1Ptr->pos.x;
|
||
|
gTasks[taskId].tInitialY = gSaveBlock1Ptr->pos.y;
|
||
|
PlayerGetDestCoords(&gTasks[taskId].tCursorX, &gTasks[taskId].tCursorY);
|
||
|
}
|
||
|
|
||
|
static void WarpToInitialPosition(u8 taskId)
|
||
|
{
|
||
|
DrawWholeMapView();
|
||
|
SetWarpDestination(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, WARP_ID_NONE, gTasks[taskId].tInitialX, gTasks[taskId].tInitialY);
|
||
|
WarpIntoMap();
|
||
|
}
|
||
|
|
||
|
static u16 GetDecorationElevation(u8 decoration, u8 tileIndex)
|
||
|
{
|
||
|
u16 elevation = -1;
|
||
|
switch (decoration)
|
||
|
{
|
||
|
case DECOR_STAND:
|
||
|
elevation = sDecorationStandElevations[tileIndex] << METATILE_ELEVATION_SHIFT;
|
||
|
return elevation;
|
||
|
case DECOR_SLIDE:
|
||
|
elevation = sDecorationSlideElevation[tileIndex] << METATILE_ELEVATION_SHIFT;
|
||
|
return elevation;
|
||
|
default:
|
||
|
return elevation;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ShowDecorationOnMap_(u16 mapX, u16 mapY, u8 decWidth, u8 decHeight, u16 decoration)
|
||
|
{
|
||
|
u16 i, j;
|
||
|
s16 x, y;
|
||
|
u16 behavior;
|
||
|
u16 impassableFlag;
|
||
|
u16 overlapsWall;
|
||
|
u16 elevation;
|
||
|
|
||
|
for (j = 0; j < decHeight; j++)
|
||
|
{
|
||
|
y = mapY - decHeight + 1 + j;
|
||
|
for (i = 0; i < decWidth; i++)
|
||
|
{
|
||
|
x = mapX + i;
|
||
|
behavior = GetBehaviorByMetatileId(NUM_TILES_IN_PRIMARY + gDecorations[decoration].tiles[j * decWidth + i]);
|
||
|
if (MetatileBehavior_IsSecretBaseImpassable(behavior) == TRUE || (gDecorations[decoration].permission != DECORPERM_PASS_FLOOR && (behavior >> METATILE_ELEVATION_SHIFT)))
|
||
|
impassableFlag = METATILE_COLLISION_MASK;
|
||
|
else
|
||
|
impassableFlag = 0;
|
||
|
|
||
|
// Choose the metatile that has the wall background instead of the floor if overlapping a wall.
|
||
|
if (gDecorations[decoration].permission != DECORPERM_NA_WALL && MetatileBehavior_IsSecretBaseNorthWall(MapGridGetMetatileBehaviorAt(x, y)) == TRUE)
|
||
|
overlapsWall = 1;
|
||
|
else
|
||
|
overlapsWall = 0;
|
||
|
|
||
|
elevation = GetDecorationElevation(gDecorations[decoration].id, j * decWidth + i);
|
||
|
if (elevation != 0xFFFF)
|
||
|
MapGridSetMetatileEntryAt(x, y, (gDecorations[decoration].tiles[j * decWidth + i] + (NUM_TILES_IN_PRIMARY | overlapsWall)) | impassableFlag | elevation);
|
||
|
else
|
||
|
MapGridSetMetatileIdAt(x, y, (gDecorations[decoration].tiles[j * decWidth + i] + (NUM_TILES_IN_PRIMARY | overlapsWall)) | impassableFlag);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ShowDecorationOnMap(u16 mapX, u16 mapY, u16 decoration)
|
||
|
{
|
||
|
switch (gDecorations[decoration].shape)
|
||
|
{
|
||
|
case DECORSHAPE_1x1:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 1, 1, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_2x1:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 2, 1, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_3x1: // unused
|
||
|
ShowDecorationOnMap_(mapX, mapY, 3, 1, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_4x2:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 4, 2, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_2x2:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 2, 2, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_1x2:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 1, 2, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_1x3: // unused
|
||
|
ShowDecorationOnMap_(mapX, mapY, 1, 3, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_2x4:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 2, 4, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_3x3:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 3, 3, decoration);
|
||
|
break;
|
||
|
case DECORSHAPE_3x2:
|
||
|
ShowDecorationOnMap_(mapX, mapY, 3, 2, decoration);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SetDecoration(void)
|
||
|
{
|
||
|
u8 i;
|
||
|
u8 j;
|
||
|
|
||
|
for (i = 0; i < NUM_DECORATION_FLAGS; i++)
|
||
|
{
|
||
|
if (FlagGet(FLAG_DECORATION_1 + i) == TRUE)
|
||
|
{
|
||
|
FlagClear(FLAG_DECORATION_1 + i);
|
||
|
for (j = 0; j < gMapHeader.events->objectEventCount; j++)
|
||
|
{
|
||
|
if (gMapHeader.events->objectEvents[j].flagId == FLAG_DECORATION_1 + i)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
VarSet(
|
||
|
VAR_OBJ_GFX_ID_0 + (gMapHeader.events->objectEvents[j].graphicsId - OBJ_EVENT_GFX_VAR_0),
|
||
|
sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0]);
|
||
|
|
||
|
gSpecialVar_0x8005 = gMapHeader.events->objectEvents[j].localId;
|
||
|
gSpecialVar_0x8006 = sCurDecorMapX;
|
||
|
gSpecialVar_0x8007 = sCurDecorMapY;
|
||
|
TrySpawnObjectEvent(gSpecialVar_0x8005, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
|
||
|
TryMoveObjectEventToMapCoords(gSpecialVar_0x8005, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, gSpecialVar_0x8006, gSpecialVar_0x8007);
|
||
|
TryOverrideObjectEventTemplateCoords(gSpecialVar_0x8005, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool8 HasDecorationSpace(void)
|
||
|
{
|
||
|
u16 i;
|
||
|
for (i = 0; i < sDecorationContext.size; i++)
|
||
|
{
|
||
|
if (sDecorationContext.items[i] == DECOR_NONE)
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void DecorationItemsMenuAction_AttemptPlace(u8 taskId)
|
||
|
{
|
||
|
if (sDecorationContext.isPlayerRoom == TRUE && sCurDecorationCategory != DECORCAT_DOLL && sCurDecorationCategory != DECORCAT_CUSHION)
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_CantPlaceInRoom);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationItemsAfterInvalidSelection);
|
||
|
}
|
||
|
else if (IsSelectedDecorInThePC() == TRUE)
|
||
|
{
|
||
|
if (HasDecorationSpace() == TRUE)
|
||
|
{
|
||
|
FadeScreen(FADE_TO_BLACK, 0);
|
||
|
gTasks[taskId].tState = 0;
|
||
|
gTasks[taskId].func = Task_PlaceDecoration;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ConvertIntToDecimalStringN(gStringVar1, sDecorationContext.size, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
||
|
if (sDecorationContext.isPlayerRoom == FALSE) {
|
||
|
StringExpandPlaceholders(gStringVar4, gText_NoMoreDecorations);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_NoMoreDecorations2);
|
||
|
}
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationItemsAfterInvalidSelection);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_InUseAlready);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationItemsAfterInvalidSelection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Task_PlaceDecoration(u8 taskId)
|
||
|
{
|
||
|
switch (gTasks[taskId].tState)
|
||
|
{
|
||
|
case 0:
|
||
|
if (!gPaletteFade.active)
|
||
|
{
|
||
|
SetInitialPositions(taskId);
|
||
|
gTasks[taskId].tState = 1;
|
||
|
}
|
||
|
break;
|
||
|
case 1:
|
||
|
gPaletteFade.bufferTransferDisabled = TRUE;
|
||
|
ConfigureCameraObjectForPlacingDecoration(&sPlaceDecorationGraphicsDataBuffer, gCurDecorationItems[gCurDecorationIndex]);
|
||
|
SetUpDecorationShape(taskId);
|
||
|
SetUpPlacingDecorationPlayerAvatar(taskId, &sPlaceDecorationGraphicsDataBuffer);
|
||
|
FadeInFromBlack();
|
||
|
gPaletteFade.bufferTransferDisabled = FALSE;
|
||
|
gTasks[taskId].tState = 2;
|
||
|
break;
|
||
|
case 2:
|
||
|
if (IsWeatherNotFadingIn() == TRUE)
|
||
|
{
|
||
|
gTasks[taskId].tDecorationItemsMenuCommand = DECOR_ITEMS_MENU_PLACE;
|
||
|
ContinueDecorating(taskId);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ConfigureCameraObjectForPlacingDecoration(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor)
|
||
|
{
|
||
|
sDecor_CameraSpriteObjectIdx1 = gSprites[gFieldCamera.spriteId].data[0];
|
||
|
gFieldCamera.spriteId = gpu_pal_decompress_alloc_tag_and_upload(data, decor);
|
||
|
gSprites[gFieldCamera.spriteId].oam.priority = 1;
|
||
|
gSprites[gFieldCamera.spriteId].callback = InitializePuttingAwayCursorSprite;
|
||
|
gSprites[gFieldCamera.spriteId].x = sDecorationMovementInfo[data->decoration->shape].cameraX;
|
||
|
gSprites[gFieldCamera.spriteId].y = sDecorationMovementInfo[data->decoration->shape].cameraY;
|
||
|
}
|
||
|
|
||
|
static void SetUpPlacingDecorationPlayerAvatar(u8 taskId, struct PlaceDecorationGraphicsDataBuffer *data)
|
||
|
{
|
||
|
u8 x;
|
||
|
|
||
|
x = 16 * (u8)gTasks[taskId].tDecorWidth + sDecorationMovementInfo[data->decoration->shape].cameraX - 8 * ((u8)gTasks[taskId].tDecorWidth - 1);
|
||
|
if (data->decoration->shape == DECORSHAPE_3x1 || data->decoration->shape == DECORSHAPE_3x3 || data->decoration->shape == DECORSHAPE_3x2)
|
||
|
x -= 8;
|
||
|
|
||
|
if (gSaveBlock2Ptr->playerGender == MALE)
|
||
|
sDecor_CameraSpriteObjectIdx2 = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_BRENDAN_DECORATING, SpriteCallbackDummy, x, 72, 0);
|
||
|
else
|
||
|
sDecor_CameraSpriteObjectIdx2 = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MAY_DECORATING, SpriteCallbackDummy, x, 72, 0);
|
||
|
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].oam.priority = 1;
|
||
|
DestroySprite(&gSprites[sDecor_CameraSpriteObjectIdx1]);
|
||
|
sDecor_CameraSpriteObjectIdx1 = gFieldCamera.spriteId;
|
||
|
}
|
||
|
|
||
|
static void SetUpDecorationShape(u8 taskId)
|
||
|
{
|
||
|
switch (gDecorations[gCurDecorationItems[gCurDecorationIndex]].shape)
|
||
|
{
|
||
|
case DECORSHAPE_1x1:
|
||
|
gTasks[taskId].tDecorWidth = 1;
|
||
|
gTasks[taskId].tDecorHeight = 1;
|
||
|
break;
|
||
|
case DECORSHAPE_2x1:
|
||
|
gTasks[taskId].tDecorWidth = 2;
|
||
|
gTasks[taskId].tDecorHeight = 1;
|
||
|
break;
|
||
|
case DECORSHAPE_3x1:
|
||
|
gTasks[taskId].tDecorWidth = 3;
|
||
|
gTasks[taskId].tDecorHeight = 1;
|
||
|
break;
|
||
|
case DECORSHAPE_4x2:
|
||
|
gTasks[taskId].tDecorWidth = 4;
|
||
|
gTasks[taskId].tDecorHeight = 2;
|
||
|
break;
|
||
|
case DECORSHAPE_2x2:
|
||
|
gTasks[taskId].tDecorWidth = 2;
|
||
|
gTasks[taskId].tDecorHeight = 2;
|
||
|
break;
|
||
|
case DECORSHAPE_1x2:
|
||
|
gTasks[taskId].tDecorWidth = 1;
|
||
|
gTasks[taskId].tDecorHeight = 2;
|
||
|
break;
|
||
|
case DECORSHAPE_1x3:
|
||
|
gTasks[taskId].tDecorWidth = 1;
|
||
|
gTasks[taskId].tDecorHeight = 3;
|
||
|
gTasks[taskId].tCursorY++;
|
||
|
break;
|
||
|
case DECORSHAPE_2x4:
|
||
|
gTasks[taskId].tDecorWidth = 2;
|
||
|
gTasks[taskId].tDecorHeight = 4;
|
||
|
break;
|
||
|
case DECORSHAPE_3x3:
|
||
|
gTasks[taskId].tDecorWidth = 3;
|
||
|
gTasks[taskId].tDecorHeight = 3;
|
||
|
break;
|
||
|
case DECORSHAPE_3x2:
|
||
|
gTasks[taskId].tDecorWidth = 3;
|
||
|
gTasks[taskId].tDecorHeight = 2;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void AttemptPlaceDecoration(u8 taskId)
|
||
|
{
|
||
|
gTasks[taskId].tButton = 0;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[7] = 1;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].data[7] = 1;
|
||
|
ResetCursorMovement();
|
||
|
AttemptPlaceDecoration_(taskId);
|
||
|
}
|
||
|
|
||
|
static void AttemptCancelPlaceDecoration(u8 taskId)
|
||
|
{
|
||
|
gTasks[taskId].tButton = 0;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[7] = 1;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].data[7] = 1;
|
||
|
ResetCursorMovement();
|
||
|
StringExpandPlaceholders(gStringVar4, gText_CancelDecorating);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, CancelDecoratingPrompt);
|
||
|
}
|
||
|
|
||
|
// Note: behaviorBy is pre-anded with METATILE_ELEVATION_MASK.
|
||
|
static bool8 IsNonBlockNonElevated(u8 behaviorAt, u16 behaviorBy)
|
||
|
{
|
||
|
if (MetatileBehavior_IsBlockDecoration(behaviorAt) != TRUE || behaviorBy != 0)
|
||
|
return FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static bool8 IsntInitialPosition(u8 taskId, s16 x, s16 y, u16 behaviorBy)
|
||
|
{
|
||
|
if (x == gTasks[taskId].tInitialX + MAP_OFFSET && y == gTasks[taskId].tInitialY + MAP_OFFSET && behaviorBy != 0)
|
||
|
return FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static bool8 IsFloorOrBoardAndHole(u16 behaviorAt, const struct Decoration *decoration)
|
||
|
{
|
||
|
if (MetatileBehavior_IsBlockDecoration(behaviorAt) != TRUE)
|
||
|
{
|
||
|
if (decoration->id == DECOR_SOLID_BOARD && MetatileBehavior_IsSecretBaseHole(behaviorAt) == TRUE)
|
||
|
return TRUE;
|
||
|
|
||
|
if (MetatileBehavior_IsNormal(behaviorAt))
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static bool8 CanPlaceDecoration(u8 taskId, const struct Decoration *decoration)
|
||
|
{
|
||
|
u8 i;
|
||
|
u8 j;
|
||
|
u8 behaviorAt;
|
||
|
u16 behaviorBy;
|
||
|
u8 mapY;
|
||
|
u8 mapX;
|
||
|
s16 curY;
|
||
|
s16 curX;
|
||
|
mapY = gTasks[taskId].tDecorHeight;
|
||
|
mapX = gTasks[taskId].tDecorWidth;
|
||
|
|
||
|
switch (decoration->permission)
|
||
|
{
|
||
|
case DECORPERM_SOLID_FLOOR:
|
||
|
case DECORPERM_PASS_FLOOR:
|
||
|
for (i = 0; i < mapY; i++)
|
||
|
{
|
||
|
curY = gTasks[taskId].tCursorY - i;
|
||
|
for (j = 0; j < mapX; j++)
|
||
|
{
|
||
|
curX = gTasks[taskId].tCursorX + j;
|
||
|
behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY);
|
||
|
behaviorBy = GetBehaviorByMetatileId(NUM_TILES_IN_PRIMARY + decoration->tiles[(mapY - 1 - i) * mapX + j]) & METATILE_ELEVATION_MASK;
|
||
|
if (!IsFloorOrBoardAndHole(behaviorAt, decoration))
|
||
|
return FALSE;
|
||
|
|
||
|
if (!IsntInitialPosition(taskId, curX, curY, behaviorBy))
|
||
|
return FALSE;
|
||
|
|
||
|
behaviorAt = GetObjectEventIdByXYZ(curX, curY, 0);
|
||
|
if (behaviorAt != 0 && behaviorAt != OBJECT_EVENTS_COUNT)
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case DECORPERM_BEHIND_FLOOR:
|
||
|
for (i = 0; i < mapY - 1; i++)
|
||
|
{
|
||
|
curY = gTasks[taskId].tCursorY - i;
|
||
|
for (j = 0; j < mapX; j++)
|
||
|
{
|
||
|
curX = gTasks[taskId].tCursorX + j;
|
||
|
behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY);
|
||
|
behaviorBy = GetBehaviorByMetatileId(NUM_TILES_IN_PRIMARY + decoration->tiles[(mapY - 1 - i) * mapX + j]) & METATILE_ELEVATION_MASK;
|
||
|
if (!MetatileBehavior_IsNormal(behaviorAt) && !IsNonBlockNonElevated(behaviorAt, behaviorBy))
|
||
|
return FALSE;
|
||
|
|
||
|
if (!IsntInitialPosition(taskId, curX, curY, behaviorBy))
|
||
|
return FALSE;
|
||
|
|
||
|
if (GetObjectEventIdByXYZ(curX, curY, 0) != OBJECT_EVENTS_COUNT)
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
curY = gTasks[taskId].tCursorY - mapY + 1;
|
||
|
for (j = 0; j < mapX; j++)
|
||
|
{
|
||
|
curX = gTasks[taskId].tCursorX + j;
|
||
|
behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY);
|
||
|
behaviorBy = GetBehaviorByMetatileId(NUM_TILES_IN_PRIMARY + decoration->tiles[j]) & METATILE_ELEVATION_MASK;
|
||
|
if (!MetatileBehavior_IsNormal(behaviorAt) && !MetatileBehavior_IsSecretBaseNorthWall(behaviorAt))
|
||
|
return FALSE;
|
||
|
|
||
|
if (!IsntInitialPosition(taskId, curX, curY, behaviorBy))
|
||
|
return FALSE;
|
||
|
|
||
|
behaviorAt = GetObjectEventIdByXYZ(curX, curY, 0);
|
||
|
if (behaviorAt != 0 && behaviorAt != OBJECT_EVENTS_COUNT)
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
case DECORPERM_NA_WALL:
|
||
|
for (i = 0; i < mapY; i++)
|
||
|
{
|
||
|
curY = gTasks[taskId].tCursorY - i;
|
||
|
for (j = 0; j < mapX; j++)
|
||
|
{
|
||
|
curX = gTasks[taskId].tCursorX + j;
|
||
|
if (!MetatileBehavior_IsSecretBaseNorthWall(MapGridGetMetatileBehaviorAt(curX, curY)))
|
||
|
return FALSE;
|
||
|
|
||
|
if (MapGridGetMetatileIdAt(curX, curY + 1) == METATILE_SecretBase_SandOrnament_BrokenBase)
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case DECORPERM_SPRITE:
|
||
|
curY = gTasks[taskId].tCursorY;
|
||
|
for (j = 0; j < mapX; j++)
|
||
|
{
|
||
|
curX = gTasks[taskId].tCursorX + j;
|
||
|
behaviorAt = MapGridGetMetatileBehaviorAt(curX, curY);
|
||
|
if (decoration->shape == DECORSHAPE_1x2)
|
||
|
{
|
||
|
if (!MetatileBehavior_HoldsLargeDecoration(behaviorAt))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if (!MetatileBehavior_HoldsSmallDecoration(behaviorAt))
|
||
|
{
|
||
|
if (!MetatileBehavior_HoldsLargeDecoration(behaviorAt))
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (GetObjectEventIdByXYZ(curX, curY, 0) != OBJECT_EVENTS_COUNT)
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void AttemptPlaceDecoration_(u8 taskId)
|
||
|
{
|
||
|
if (CanPlaceDecoration(taskId, &gDecorations[gCurDecorationItems[gCurDecorationIndex]]) == TRUE)
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_PlaceItHere);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, PlaceDecorationPrompt);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PlaySE(SE_FAILURE);
|
||
|
StringExpandPlaceholders(gStringVar4, gText_CantBePlacedHere);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, CantPlaceDecorationPrompt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void PlaceDecorationPrompt(u8 taskId)
|
||
|
{
|
||
|
DisplayYesNoMenuDefaultYes();
|
||
|
DoYesNoFuncWithChoice(taskId, &sPlaceDecorationYesNoFunctions);
|
||
|
}
|
||
|
|
||
|
static void PlaceDecoration(u8 taskId)
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
PlaceDecoration_(taskId);
|
||
|
if (gDecorations[gCurDecorationItems[gCurDecorationIndex]].permission != DECORPERM_SPRITE)
|
||
|
{
|
||
|
ShowDecorationOnMap(gTasks[taskId].tCursorX, gTasks[taskId].tCursorY, gCurDecorationItems[gCurDecorationIndex]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sCurDecorMapX = gTasks[taskId].tCursorX - MAP_OFFSET;
|
||
|
sCurDecorMapY = gTasks[taskId].tCursorY - MAP_OFFSET;
|
||
|
ScriptContext1_SetupScript(SecretBase_EventScript_SetDecoration);
|
||
|
}
|
||
|
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].y += 2;
|
||
|
if (gMapHeader.regionMapSectionId == MAPSEC_SECRET_BASE)
|
||
|
TryPutSecretBaseVisitOnAir();
|
||
|
|
||
|
CancelDecorating_(taskId);
|
||
|
}
|
||
|
|
||
|
static void PlaceDecoration_(u8 taskId)
|
||
|
{
|
||
|
u16 i;
|
||
|
|
||
|
for (i = 0; i < sDecorationContext.size; i++)
|
||
|
{
|
||
|
if (sDecorationContext.items[i] == DECOR_NONE)
|
||
|
{
|
||
|
sDecorationContext.items[i] = gCurDecorationItems[gCurDecorationIndex];
|
||
|
sDecorationContext.pos[i] = ((gTasks[taskId].tCursorX - MAP_OFFSET) << 4) + (gTasks[taskId].tCursorY - MAP_OFFSET);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!sDecorationContext.isPlayerRoom)
|
||
|
{
|
||
|
for (i = 0; i < DECOR_MAX_SECRET_BASE; i++)
|
||
|
{
|
||
|
if (sSecretBaseItemsIndicesBuffer[i] == DECOR_NONE)
|
||
|
{
|
||
|
sSecretBaseItemsIndicesBuffer[i] = gCurDecorationIndex + 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (i = 0; i < DECOR_MAX_PLAYERS_HOUSE; i++)
|
||
|
{
|
||
|
if (sPlayerRoomItemsIndicesBuffer[i] == DECOR_NONE)
|
||
|
{
|
||
|
sPlayerRoomItemsIndicesBuffer[i] = gCurDecorationIndex + 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void CancelDecoratingPrompt(u8 taskId)
|
||
|
{
|
||
|
DisplayYesNoMenuDefaultYes();
|
||
|
DoYesNoFuncWithChoice(taskId, &sCancelDecoratingYesNoFunctions);
|
||
|
}
|
||
|
|
||
|
static void CancelDecorating(u8 taskId)
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
CancelDecorating_(taskId);
|
||
|
}
|
||
|
|
||
|
static void CancelDecorating_(u8 taskId)
|
||
|
{
|
||
|
FadeScreen(FADE_TO_BLACK, 0);
|
||
|
gTasks[taskId].tState = 0;
|
||
|
gTasks[taskId].func = c1_overworld_prev_quest;
|
||
|
}
|
||
|
|
||
|
static void c1_overworld_prev_quest(u8 taskId)
|
||
|
{
|
||
|
switch (gTasks[taskId].tState)
|
||
|
{
|
||
|
case 0:
|
||
|
ScriptContext2_Enable();
|
||
|
if (!gPaletteFade.active)
|
||
|
{
|
||
|
WarpToInitialPosition(taskId);
|
||
|
gTasks[taskId].tState = 1;
|
||
|
}
|
||
|
break;
|
||
|
case 1:
|
||
|
FreePlayerSpritePalette();
|
||
|
FreeSpritePaletteByTag(PLACE_DECORATION_SELECTOR_TAG);
|
||
|
gFieldCallback = FieldCB_InitDecorationItemsWindow;
|
||
|
SetMainCallback2(CB2_ReturnToField);
|
||
|
DestroyTask(taskId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Task_InitDecorationItemsWindow(u8 taskId)
|
||
|
{
|
||
|
s16 *data = gTasks[taskId].data;
|
||
|
switch (tState)
|
||
|
{
|
||
|
case 0:
|
||
|
HideSecretBaseDecorationSprites();
|
||
|
tState++;
|
||
|
break;
|
||
|
case 1:
|
||
|
ScriptContext1_SetupScript(SecretBase_EventScript_InitDecorations);
|
||
|
tState++;
|
||
|
break;
|
||
|
case 2:
|
||
|
ScriptContext2_Enable();
|
||
|
tState++;
|
||
|
break;
|
||
|
case 3:
|
||
|
if (IsWeatherNotFadingIn() == TRUE)
|
||
|
gTasks[taskId].func = HandleDecorationItemsMenuInput;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void FieldCB_InitDecorationItemsWindow(void)
|
||
|
{
|
||
|
u8 taskId;
|
||
|
|
||
|
ScriptContext2_Enable();
|
||
|
FadeInFromBlack();
|
||
|
taskId = CreateTask(Task_InitDecorationItemsWindow, 8);
|
||
|
AddDecorationItemsWindow(taskId);
|
||
|
gTasks[taskId].tState = 0;
|
||
|
}
|
||
|
|
||
|
static bool8 ApplyCursorMovement_IsInvalid(u8 taskId)
|
||
|
{
|
||
|
s16 *data = gTasks[taskId].data;
|
||
|
if (sDecorationLastDirectionMoved == DIR_SOUTH && tCursorY - tDecorHeight - 6 < 0)
|
||
|
{
|
||
|
tCursorY++;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (sDecorationLastDirectionMoved == DIR_NORTH && tCursorY - 7 >= gMapHeader.mapLayout->height)
|
||
|
{
|
||
|
tCursorY--;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (sDecorationLastDirectionMoved == DIR_WEST && tCursorX - 7 < 0)
|
||
|
{
|
||
|
tCursorX++;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (sDecorationLastDirectionMoved == DIR_EAST && tCursorX + tDecorWidth - 8 >= gMapHeader.mapLayout->width)
|
||
|
{
|
||
|
tCursorX--;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static bool8 IsHoldingDirection(void)
|
||
|
{
|
||
|
u16 heldKeys = JOY_HELD(DPAD_ANY);
|
||
|
if (heldKeys != DPAD_UP && heldKeys != DPAD_DOWN && heldKeys != DPAD_LEFT && heldKeys != DPAD_RIGHT)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void ResetCursorMovement(void)
|
||
|
{
|
||
|
sDecorationLastDirectionMoved = 0;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[2] = 0;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[3] = 0;
|
||
|
}
|
||
|
|
||
|
static void Task_SelectLocation(u8 taskId)
|
||
|
{
|
||
|
s16 *data = gTasks[taskId].data;
|
||
|
if (!gSprites[sDecor_CameraSpriteObjectIdx1].data[4])
|
||
|
{
|
||
|
if (tButton == A_BUTTON)
|
||
|
{
|
||
|
sPlacePutAwayYesNoFunctions[tDecorationItemsMenuCommand].yesFunc(taskId);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (tButton == B_BUTTON)
|
||
|
{
|
||
|
sPlacePutAwayYesNoFunctions[tDecorationItemsMenuCommand].noFunc(taskId);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((JOY_HELD(DPAD_ANY)) == DPAD_UP)
|
||
|
{
|
||
|
sDecorationLastDirectionMoved = DIR_SOUTH;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[2] = 0;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[3] = -2;
|
||
|
tCursorY--;
|
||
|
}
|
||
|
|
||
|
if ((JOY_HELD(DPAD_ANY)) == DPAD_DOWN)
|
||
|
{
|
||
|
sDecorationLastDirectionMoved = DIR_NORTH;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[2] = 0;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[3] = 2;
|
||
|
tCursorY++;
|
||
|
}
|
||
|
|
||
|
if ((JOY_HELD(DPAD_ANY)) == DPAD_LEFT)
|
||
|
{
|
||
|
sDecorationLastDirectionMoved = DIR_WEST;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[2] = -2;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[3] = 0;
|
||
|
tCursorX--;
|
||
|
}
|
||
|
|
||
|
if ((JOY_HELD(DPAD_ANY)) == DPAD_RIGHT)
|
||
|
{
|
||
|
sDecorationLastDirectionMoved = DIR_EAST;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[2] = 2;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[3] = 0;
|
||
|
tCursorX++;
|
||
|
}
|
||
|
|
||
|
if (!IsHoldingDirection() || !ApplyCursorMovement_IsInvalid(taskId))
|
||
|
ResetCursorMovement();
|
||
|
}
|
||
|
|
||
|
if (sDecorationLastDirectionMoved)
|
||
|
{
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[4]++;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[4] &= 7;
|
||
|
}
|
||
|
|
||
|
if (!tButton)
|
||
|
{
|
||
|
if (JOY_NEW(A_BUTTON))
|
||
|
tButton = A_BUTTON;
|
||
|
|
||
|
if (JOY_NEW(B_BUTTON))
|
||
|
tButton = B_BUTTON;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ContinueDecorating(u8 taskId)
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 1);
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[7] = 0;
|
||
|
gTasks[taskId].tButton = 0;
|
||
|
gTasks[taskId].func = Task_SelectLocation;
|
||
|
}
|
||
|
|
||
|
static void CantPlaceDecorationPrompt(u8 taskId)
|
||
|
{
|
||
|
if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON))
|
||
|
ContinueDecorating(taskId);
|
||
|
}
|
||
|
|
||
|
static void ClearPlaceDecorationGraphicsDataBuffer(struct PlaceDecorationGraphicsDataBuffer *data)
|
||
|
{
|
||
|
CpuFill16(0, data, sizeof(*data));
|
||
|
}
|
||
|
|
||
|
static void CopyPalette(u16 *dest, u16 pal)
|
||
|
{
|
||
|
CpuFastCopy(&((u16 *)gTilesetPointer_SecretBase->palettes)[pal * 16], dest, sizeof(u16) * 16);
|
||
|
}
|
||
|
|
||
|
static void CopyTile(u8 *dest, u16 tile)
|
||
|
{
|
||
|
u8 buffer[TILE_SIZE_4BPP];
|
||
|
u16 mode;
|
||
|
u16 i;
|
||
|
|
||
|
mode = tile >> 10;
|
||
|
if (tile != 0)
|
||
|
tile &= 0x03FF;
|
||
|
|
||
|
CpuFastCopy(&((u8 *)gTilesetPointer_SecretBase->tiles)[tile * TILE_SIZE_4BPP], buffer, TILE_SIZE_4BPP);
|
||
|
switch (mode)
|
||
|
{
|
||
|
case 0:
|
||
|
CpuFastCopy(buffer, dest, TILE_SIZE_4BPP);
|
||
|
break;
|
||
|
case BG_TILE_H_FLIP(0) >> 10:
|
||
|
for (i = 0; i < 8; i++)
|
||
|
{
|
||
|
dest[4 * i + 0] = (buffer[4 * (i + 1) - 1] >> 4) + ((buffer[4 * (i + 1) - 1] & 0x0F) << 4);
|
||
|
dest[4 * i + 1] = (buffer[4 * (i + 1) - 2] >> 4) + ((buffer[4 * (i + 1) - 2] & 0x0F) << 4);
|
||
|
dest[4 * i + 2] = (buffer[4 * (i + 1) - 3] >> 4) + ((buffer[4 * (i + 1) - 3] & 0x0F) << 4);
|
||
|
dest[4 * i + 3] = (buffer[4 * (i + 1) - 4] >> 4) + ((buffer[4 * (i + 1) - 4] & 0x0F) << 4);
|
||
|
}
|
||
|
break;
|
||
|
case BG_TILE_V_FLIP(0) >> 10:
|
||
|
for (i = 0; i < 8; i++)
|
||
|
{
|
||
|
dest[4 * i + 0] = buffer[4 * (7 - i) + 0];
|
||
|
dest[4 * i + 1] = buffer[4 * (7 - i) + 1];
|
||
|
dest[4 * i + 2] = buffer[4 * (7 - i) + 2];
|
||
|
dest[4 * i + 3] = buffer[4 * (7 - i) + 3];
|
||
|
}
|
||
|
break;
|
||
|
case BG_TILE_H_FLIP(BG_TILE_V_FLIP(0)) >> 10:
|
||
|
for (i = 0; i < 32; i++)
|
||
|
{
|
||
|
dest[i] = (buffer[31 - i] >> 4) + ((buffer[31 - i] & 0x0F) << 4);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void SetDecorSelectionBoxTiles(struct PlaceDecorationGraphicsDataBuffer *data)
|
||
|
{
|
||
|
u16 i;
|
||
|
for (i = 0; i < 64; i++)
|
||
|
CopyTile(&data->image[i * TILE_SIZE_4BPP], data->tiles[i]);
|
||
|
}
|
||
|
|
||
|
static u16 GetMetatile(u16 tile)
|
||
|
{
|
||
|
return ((u16 *)gTilesetPointer_SecretBaseRedCave->metatiles)[tile] & 0xFFF;
|
||
|
}
|
||
|
|
||
|
static void SetDecorSelectionMetatiles(struct PlaceDecorationGraphicsDataBuffer *data)
|
||
|
{
|
||
|
u8 i;
|
||
|
u8 shape;
|
||
|
|
||
|
shape = data->decoration->shape;
|
||
|
for (i = 0; i < sDecorTilemaps[shape].size; i++)
|
||
|
{
|
||
|
data->tiles[sDecorTilemaps[shape].tiles[i]] = GetMetatile(data->decoration->tiles[sDecorTilemaps[shape].y[i]] * 8 + sDecorTilemaps[shape].x[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void SetDecorSelectionBoxOamAttributes(u8 decorShape)
|
||
|
{
|
||
|
sDecorSelectorOam.y = 0;
|
||
|
sDecorSelectorOam.affineMode = ST_OAM_AFFINE_OFF;
|
||
|
sDecorSelectorOam.objMode = ST_OAM_OBJ_NORMAL;
|
||
|
sDecorSelectorOam.mosaic = 0;
|
||
|
sDecorSelectorOam.bpp = ST_OAM_4BPP;
|
||
|
sDecorSelectorOam.shape = sDecorationMovementInfo[decorShape].shape;
|
||
|
sDecorSelectorOam.x = 0;
|
||
|
sDecorSelectorOam.matrixNum = 0;
|
||
|
sDecorSelectorOam.size = sDecorationMovementInfo[decorShape].size;
|
||
|
sDecorSelectorOam.tileNum = 0;
|
||
|
sDecorSelectorOam.priority = 0;
|
||
|
sDecorSelectorOam.paletteNum = 0;
|
||
|
}
|
||
|
|
||
|
static void InitializePuttingAwayCursorSprite(struct Sprite *sprite)
|
||
|
{
|
||
|
sprite->data[2] = 0;
|
||
|
sprite->data[3] = 0;
|
||
|
sprite->data[4] = 0;
|
||
|
sprite->data[5] = 0;
|
||
|
sprite->data[6] = 0;
|
||
|
sprite->data[7] = 0;
|
||
|
sprite->callback = InitializePuttingAwayCursorSprite2;
|
||
|
}
|
||
|
|
||
|
static void InitializePuttingAwayCursorSprite2(struct Sprite *sprite)
|
||
|
{
|
||
|
if (sprite->data[7] == 0)
|
||
|
{
|
||
|
if (sprite->data[6] < 15)
|
||
|
sprite->invisible = 0;
|
||
|
else
|
||
|
sprite->invisible = 1;
|
||
|
|
||
|
sprite->data[6]++;
|
||
|
sprite->data[6] &= 0x1F;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sprite->invisible = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static u8 gpu_pal_decompress_alloc_tag_and_upload(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor)
|
||
|
{
|
||
|
ClearPlaceDecorationGraphicsDataBuffer(data);
|
||
|
data->decoration = &gDecorations[decor];
|
||
|
if (data->decoration->permission == DECORPERM_SPRITE)
|
||
|
return CreateObjectGraphicsSprite(data->decoration->tiles[0], SpriteCallbackDummy, 0, 0, 1);
|
||
|
|
||
|
FreeSpritePaletteByTag(PLACE_DECORATION_SELECTOR_TAG);
|
||
|
SetDecorSelectionMetatiles(data);
|
||
|
SetDecorSelectionBoxOamAttributes(data->decoration->shape);
|
||
|
SetDecorSelectionBoxTiles(data);
|
||
|
CopyPalette(data->palette, ((u16 *)gTilesetPointer_SecretBaseRedCave->metatiles)[(data->decoration->tiles[0] * 8) + 7] >> 12);
|
||
|
LoadSpritePalette(&sSpritePal_PlaceDecoration);
|
||
|
return CreateSprite(&sDecorationSelectorSpriteTemplate, 0, 0, 0);
|
||
|
}
|
||
|
|
||
|
static u8 AddDecorationIconObjectFromIconTable(u16 tilesTag, u16 paletteTag, u8 decor)
|
||
|
{
|
||
|
struct SpriteSheet sheet;
|
||
|
struct CompressedSpritePalette palette;
|
||
|
struct SpriteTemplate *template;
|
||
|
u8 spriteId;
|
||
|
|
||
|
if (!AllocItemIconTemporaryBuffers())
|
||
|
return MAX_SPRITES;
|
||
|
|
||
|
LZDecompressWram(GetDecorationIconPicOrPalette(decor, 0), gItemIconDecompressionBuffer);
|
||
|
CopyItemIconPicTo4x4Buffer(gItemIconDecompressionBuffer, gItemIcon4x4Buffer);
|
||
|
sheet.data = gItemIcon4x4Buffer;
|
||
|
sheet.size = 0x200;
|
||
|
sheet.tag = tilesTag;
|
||
|
LoadSpriteSheet(&sheet);
|
||
|
palette.data = GetDecorationIconPicOrPalette(decor, 1);
|
||
|
palette.tag = paletteTag;
|
||
|
LoadCompressedSpritePalette(&palette);
|
||
|
template = malloc(sizeof(struct SpriteTemplate));
|
||
|
*template = gItemIconSpriteTemplate;
|
||
|
template->tileTag = tilesTag;
|
||
|
template->paletteTag = paletteTag;
|
||
|
spriteId = CreateSprite(template, 0, 0, 0);
|
||
|
FreeItemIconTemporaryBuffers();
|
||
|
free(template);
|
||
|
return spriteId;
|
||
|
}
|
||
|
|
||
|
static const u32 *GetDecorationIconPicOrPalette(u16 decor, u8 mode)
|
||
|
{
|
||
|
if (decor > NUM_DECORATIONS)
|
||
|
decor = DECOR_NONE;
|
||
|
|
||
|
return gDecorIconTable[decor][mode];
|
||
|
}
|
||
|
|
||
|
static u8 AddDecorationIconObjectFromObjectEvent(u16 tilesTag, u16 paletteTag, u8 decor)
|
||
|
{
|
||
|
u8 spriteId;
|
||
|
struct SpriteSheet sheet;
|
||
|
struct SpritePalette palette;
|
||
|
struct SpriteTemplate *template;
|
||
|
|
||
|
ClearPlaceDecorationGraphicsDataBuffer(&sPlaceDecorationGraphicsDataBuffer);
|
||
|
sPlaceDecorationGraphicsDataBuffer.decoration = &gDecorations[decor];
|
||
|
if (sPlaceDecorationGraphicsDataBuffer.decoration->permission != DECORPERM_SPRITE)
|
||
|
{
|
||
|
SetDecorSelectionMetatiles(&sPlaceDecorationGraphicsDataBuffer);
|
||
|
SetDecorSelectionBoxOamAttributes(sPlaceDecorationGraphicsDataBuffer.decoration->shape);
|
||
|
SetDecorSelectionBoxTiles(&sPlaceDecorationGraphicsDataBuffer);
|
||
|
CopyPalette(sPlaceDecorationGraphicsDataBuffer.palette, ((u16 *)gTilesetPointer_SecretBaseRedCave->metatiles)[(sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0] * 8) + 7] >> 12);
|
||
|
sheet.data = sPlaceDecorationGraphicsDataBuffer.image;
|
||
|
sheet.size = sDecorShapeSizes[sPlaceDecorationGraphicsDataBuffer.decoration->shape] * TILE_SIZE_4BPP;
|
||
|
sheet.tag = tilesTag;
|
||
|
LoadSpriteSheet(&sheet);
|
||
|
palette.data = sPlaceDecorationGraphicsDataBuffer.palette;
|
||
|
palette.tag = paletteTag;
|
||
|
LoadSpritePalette(&palette);
|
||
|
template = Alloc(sizeof(struct SpriteTemplate));
|
||
|
*template = sDecorWhilePlacingSpriteTemplate;
|
||
|
template->tileTag = tilesTag;
|
||
|
template->paletteTag = paletteTag;
|
||
|
spriteId = CreateSprite(template, 0, 0, 0);
|
||
|
free(template);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
spriteId = CreateObjectGraphicsSprite(sPlaceDecorationGraphicsDataBuffer.decoration->tiles[0], SpriteCallbackDummy, 0, 0, 1);
|
||
|
}
|
||
|
return spriteId;
|
||
|
}
|
||
|
|
||
|
u8 AddDecorationIconObject(u8 decor, s16 x, s16 y, u8 priority, u16 tilesTag, u16 paletteTag)
|
||
|
{
|
||
|
u8 spriteId;
|
||
|
|
||
|
if (decor > NUM_DECORATIONS)
|
||
|
{
|
||
|
spriteId = AddDecorationIconObjectFromIconTable(tilesTag, paletteTag, DECOR_NONE);
|
||
|
if (spriteId == MAX_SPRITES)
|
||
|
return MAX_SPRITES;
|
||
|
|
||
|
gSprites[spriteId].x2 = x + 4;
|
||
|
gSprites[spriteId].y2 = y + 4;
|
||
|
}
|
||
|
else if (gDecorIconTable[decor][0] == NULL)
|
||
|
{
|
||
|
spriteId = AddDecorationIconObjectFromObjectEvent(tilesTag, paletteTag, decor);
|
||
|
if (spriteId == MAX_SPRITES)
|
||
|
return MAX_SPRITES;
|
||
|
|
||
|
gSprites[spriteId].x2 = x;
|
||
|
if (decor == DECOR_SILVER_SHIELD || decor == DECOR_GOLD_SHIELD)
|
||
|
gSprites[spriteId].y2 = y - 4;
|
||
|
else
|
||
|
gSprites[spriteId].y2 = y;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
spriteId = AddDecorationIconObjectFromIconTable(tilesTag, paletteTag, decor);
|
||
|
if (spriteId == MAX_SPRITES)
|
||
|
return MAX_SPRITES;
|
||
|
|
||
|
gSprites[spriteId].x2 = x + 4;
|
||
|
gSprites[spriteId].y2 = y + 4;
|
||
|
}
|
||
|
|
||
|
gSprites[spriteId].oam.priority = priority;
|
||
|
return spriteId;
|
||
|
}
|
||
|
|
||
|
static void ClearDecorationContextIndex(u8 idx)
|
||
|
{
|
||
|
sDecorationContext.items[idx] = DECOR_NONE;
|
||
|
sDecorationContext.pos[idx] = 0;
|
||
|
}
|
||
|
|
||
|
// Input
|
||
|
// gSpecialVar_0x8004: Current iteration.
|
||
|
//
|
||
|
// Output
|
||
|
// gSpecialVar_Result: TRUE if all iterations complete.
|
||
|
// gSpecialVar_0x8005: flagId of decoration (if any).
|
||
|
// gSpecialVar_0x8006: localId of decoration object event (if any).
|
||
|
void PutAwayDecorationIteration(void)
|
||
|
{
|
||
|
u16 i;
|
||
|
|
||
|
gSpecialVar_0x8005 = 0;
|
||
|
gSpecialVar_Result = FALSE;
|
||
|
if (gSpecialVar_0x8004 == sCurDecorSelectedInRearrangement)
|
||
|
{
|
||
|
gSpecialVar_Result = TRUE;
|
||
|
}
|
||
|
else if (gDecorations[sDecorationContext.items[sDecorRearrangementDataBuffer[gSpecialVar_0x8004].idx]].permission == DECORPERM_SPRITE)
|
||
|
{
|
||
|
gSpecialVar_0x8005 = sDecorRearrangementDataBuffer[gSpecialVar_0x8004].flagId;
|
||
|
ClearDecorationContextIndex(sDecorRearrangementDataBuffer[gSpecialVar_0x8004].idx);
|
||
|
for (i = 0; i < gMapHeader.events->objectEventCount; i++)
|
||
|
{
|
||
|
if (gMapHeader.events->objectEvents[i].flagId == gSpecialVar_0x8005)
|
||
|
{
|
||
|
gSpecialVar_0x8006 = gMapHeader.events->objectEvents[i].localId;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Unused
|
||
|
void GetObjectEventLocalIdByFlag(void)
|
||
|
{
|
||
|
u8 i;
|
||
|
|
||
|
for (i = 0; i < gMapHeader.events->objectEventCount; i++)
|
||
|
{
|
||
|
if (gMapHeader.events->objectEvents[i].flagId == gSpecialVar_0x8004)
|
||
|
{
|
||
|
gSpecialVar_0x8005 = gMapHeader.events->objectEvents[i].localId;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ClearRearrangementNonSprites(void)
|
||
|
{
|
||
|
u8 i;
|
||
|
u8 y;
|
||
|
u8 x;
|
||
|
int posX;
|
||
|
int posY;
|
||
|
u8 perm;
|
||
|
|
||
|
for (i = 0; i < sCurDecorSelectedInRearrangement; i++)
|
||
|
{
|
||
|
perm = gDecorations[sDecorationContext.items[sDecorRearrangementDataBuffer[i].idx]].permission;
|
||
|
posX = sDecorationContext.pos[sDecorRearrangementDataBuffer[i].idx] >> 4;
|
||
|
posY = sDecorationContext.pos[sDecorRearrangementDataBuffer[i].idx] & 0x0F;
|
||
|
if (perm != DECORPERM_SPRITE)
|
||
|
{
|
||
|
for (y = 0; y < sDecorRearrangementDataBuffer[i].height; y++)
|
||
|
{
|
||
|
for (x = 0; x < sDecorRearrangementDataBuffer[i].width; x++)
|
||
|
{
|
||
|
MapGridSetMetatileEntryAt(posX + MAP_OFFSET + x, posY + MAP_OFFSET - y, gMapHeader.mapLayout->map[posX + x + gMapHeader.mapLayout->width * (posY - y)] | 0x3000);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ClearDecorationContextIndex(sDecorRearrangementDataBuffer[i].idx);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Task_PutAwayDecoration(u8 taskId)
|
||
|
{
|
||
|
switch (gTasks[taskId].tState)
|
||
|
{
|
||
|
case 0:
|
||
|
ClearRearrangementNonSprites();
|
||
|
gTasks[taskId].tState = 1;
|
||
|
break;
|
||
|
case 1:
|
||
|
if (!gPaletteFade.active) {
|
||
|
DrawWholeMapView();
|
||
|
ScriptContext1_SetupScript(SecretBase_EventScript_PutAwayDecoration);
|
||
|
ClearDialogWindowAndFrame(0, 1);
|
||
|
gTasks[taskId].tState = 2;
|
||
|
}
|
||
|
break;
|
||
|
case 2:
|
||
|
ScriptContext2_Enable();
|
||
|
IdentifyOwnedDecorationsCurrentlyInUseInternal(taskId);
|
||
|
FadeInFromBlack();
|
||
|
gTasks[taskId].tState = 3;
|
||
|
break;
|
||
|
case 3:
|
||
|
if (IsWeatherNotFadingIn() == TRUE)
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_DecorationReturnedToPC);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ContinuePuttingAwayDecorationsPrompt);
|
||
|
if (gMapHeader.regionMapSectionId == MAPSEC_SECRET_BASE)
|
||
|
TryPutSecretBaseVisitOnAir();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool8 HasDecorationsInUse(u8 taskId)
|
||
|
{
|
||
|
u16 i;
|
||
|
for (i = 0; i < sDecorationContext.size; i++)
|
||
|
{
|
||
|
if (sDecorationContext.items[i] != DECOR_NONE)
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void SetUpPuttingAwayDecorationPlayerAvatar(void)
|
||
|
{
|
||
|
GetPlayerFacingDirection();
|
||
|
sDecor_CameraSpriteObjectIdx1 = gSprites[gFieldCamera.spriteId].data[0];
|
||
|
LoadPlayerSpritePalette();
|
||
|
gFieldCamera.spriteId = CreateSprite(&sPuttingAwayCursorSpriteTemplate, 120, 80, 0);
|
||
|
if (gSaveBlock2Ptr->playerGender == MALE)
|
||
|
sDecor_CameraSpriteObjectIdx2 = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_BRENDAN_DECORATING, SpriteCallbackDummy, 136, 72, 0);
|
||
|
else
|
||
|
sDecor_CameraSpriteObjectIdx2 = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_MAY_DECORATING, SpriteCallbackDummy, 136, 72, 0);
|
||
|
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].oam.priority = 1;
|
||
|
DestroySprite(&gSprites[sDecor_CameraSpriteObjectIdx1]);
|
||
|
sDecor_CameraSpriteObjectIdx1 = gFieldCamera.spriteId;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].oam.priority = 1;
|
||
|
}
|
||
|
|
||
|
static void Task_ContinuePuttingAwayDecorations(u8 taskId)
|
||
|
{
|
||
|
s16 *data;
|
||
|
|
||
|
data = gTasks[taskId].data;
|
||
|
switch (tState)
|
||
|
{
|
||
|
case 0:
|
||
|
if (!gPaletteFade.active)
|
||
|
{
|
||
|
SetInitialPositions(taskId);
|
||
|
tState = 1;
|
||
|
tDecorHeight = 1;
|
||
|
tDecorWidth = 1;
|
||
|
}
|
||
|
break;
|
||
|
case 1:
|
||
|
SetUpPuttingAwayDecorationPlayerAvatar();
|
||
|
FadeInFromBlack();
|
||
|
tState = 2;
|
||
|
break;
|
||
|
case 2:
|
||
|
if (IsWeatherNotFadingIn() == TRUE)
|
||
|
{
|
||
|
tDecorationItemsMenuCommand = DECOR_ITEMS_MENU_PUT_AWAY;
|
||
|
ContinuePuttingAwayDecorations(taskId);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ContinuePuttingAwayDecorations(u8 taskId)
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 1);
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].data[7] = 0;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].invisible = FALSE;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].callback = InitializeCameraSprite1;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].x = 136;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].y = 72;
|
||
|
gTasks[taskId].tButton = 0;
|
||
|
gTasks[taskId].func = Task_SelectLocation;
|
||
|
}
|
||
|
|
||
|
static void AttemptPutAwayDecoration(u8 taskId)
|
||
|
{
|
||
|
gTasks[taskId].tButton = 0;
|
||
|
ResetCursorMovement();
|
||
|
AttemptPutAwayDecoration_(taskId);
|
||
|
}
|
||
|
|
||
|
static void AttemptCancelPutAwayDecoration(u8 taskId)
|
||
|
{
|
||
|
gTasks[taskId].tButton = 0;
|
||
|
ResetCursorMovement();
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].invisible = FALSE;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].callback = SpriteCallbackDummy;
|
||
|
StringExpandPlaceholders(gStringVar4, gText_StopPuttingAwayDecorations);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, StopPuttingAwayDecorationsPrompt);
|
||
|
}
|
||
|
|
||
|
static void AttemptPutAwayDecoration_(u8 taskId)
|
||
|
{
|
||
|
s16 *data;
|
||
|
u8 behavior;
|
||
|
|
||
|
AttemptMarkDecorUnderCursorForRemoval(taskId);
|
||
|
if (sCurDecorSelectedInRearrangement != 0)
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_ReturnDecorationToPC);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnDecorationPrompt);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
data = gTasks[taskId].data;
|
||
|
behavior = MapGridGetMetatileBehaviorAt(tCursorX, tCursorY);
|
||
|
if (MetatileBehavior_IsSecretBasePC(behavior) == TRUE || MetatileBehavior_IsPlayerRoomPCOn(behavior) == TRUE)
|
||
|
{
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].invisible = FALSE;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].callback = SpriteCallbackDummy;
|
||
|
StringExpandPlaceholders(gStringVar4, gText_StopPuttingAwayDecorations);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, StopPuttingAwayDecorationsPrompt);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_NoDecorationHere);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ContinuePuttingAwayDecorationsPrompt);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ContinuePuttingAwayDecorationsPrompt(u8 taskId)
|
||
|
{
|
||
|
if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON))
|
||
|
ContinuePuttingAwayDecorations(taskId);
|
||
|
}
|
||
|
|
||
|
static void SetDecorRearrangementShape(u8 decor, struct DecorRearrangementDataBuffer *data)
|
||
|
{
|
||
|
if (gDecorations[decor].shape == DECORSHAPE_1x1)
|
||
|
{
|
||
|
data->width = 1;
|
||
|
data->height = 1;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_2x1)
|
||
|
{
|
||
|
data->width = 2;
|
||
|
data->height = 1;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_3x1)
|
||
|
{
|
||
|
data->width = 3;
|
||
|
data->height = 1;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_4x2)
|
||
|
{
|
||
|
data->width = 4;
|
||
|
data->height = 2;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_2x2)
|
||
|
{
|
||
|
data->width = 2;
|
||
|
data->height = 2;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_1x2)
|
||
|
{
|
||
|
data->width = 1;
|
||
|
data->height = 2;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_1x3)
|
||
|
{
|
||
|
data->width = 1;
|
||
|
data->height = 3;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_2x4)
|
||
|
{
|
||
|
data->width = 2;
|
||
|
data->height = 4;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_3x3)
|
||
|
{
|
||
|
data->width = 3;
|
||
|
data->height = 3;
|
||
|
}
|
||
|
else if (gDecorations[decor].shape == DECORSHAPE_3x2)
|
||
|
{
|
||
|
data->width = 3;
|
||
|
data->height = 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void SetCameraSpritePosition(u8 x, u8 y)
|
||
|
{
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].invisible = TRUE;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx1].callback = SpriteCallbackDummy;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].x = x * 16 + 136;
|
||
|
gSprites[sDecor_CameraSpriteObjectIdx2].y = y * 16 + 72;
|
||
|
}
|
||
|
|
||
|
static bool8 DecorationIsUnderCursor(u8 taskId, u8 idx, struct DecorRearrangementDataBuffer *data)
|
||
|
{
|
||
|
u8 x;
|
||
|
u8 y;
|
||
|
u8 xOff;
|
||
|
u8 yOff;
|
||
|
u8 ht;
|
||
|
|
||
|
x = gTasks[taskId].tCursorX - MAP_OFFSET;
|
||
|
y = gTasks[taskId].tCursorY - MAP_OFFSET;
|
||
|
xOff = sDecorationContext.pos[idx] >> 4;
|
||
|
yOff = sDecorationContext.pos[idx] & 0x0F;
|
||
|
ht = data->height;
|
||
|
if (sDecorationContext.items[idx] == DECOR_SAND_ORNAMENT && MapGridGetMetatileIdAt(xOff + MAP_OFFSET, yOff + MAP_OFFSET) == METATILE_SecretBase_SandOrnament_BrokenBase)
|
||
|
ht--;
|
||
|
|
||
|
if (x >= xOff && x < xOff + data->width && y > yOff - ht && y <= yOff)
|
||
|
{
|
||
|
SetCameraSpritePosition(data->width - (x - xOff + 1), yOff - y);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void SetDecorRearrangementFlagIdIfFlagUnset(void)
|
||
|
{
|
||
|
u8 xOff;
|
||
|
u8 yOff;
|
||
|
u16 i;
|
||
|
|
||
|
xOff = sDecorationContext.pos[sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].idx] >> 4;
|
||
|
yOff = sDecorationContext.pos[sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].idx] & 0x0F;
|
||
|
for (i = 0; i < OBJECT_EVENT_TEMPLATES_COUNT; i++)
|
||
|
{
|
||
|
if (gSaveBlock1Ptr->objectEventTemplates[i].x == xOff && gSaveBlock1Ptr->objectEventTemplates[i].y == yOff && !FlagGet(gSaveBlock1Ptr->objectEventTemplates[i].flagId))
|
||
|
{
|
||
|
sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].flagId = gSaveBlock1Ptr->objectEventTemplates[i].flagId;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool8 AttemptMarkSpriteDecorUnderCursorForRemoval(u8 taskId)
|
||
|
{
|
||
|
u16 i;
|
||
|
|
||
|
for (i = 0; i < sDecorationContext.size; i++)
|
||
|
{
|
||
|
if (sDecorationContext.items[i] != DECOR_NONE)
|
||
|
{
|
||
|
if (gDecorations[sDecorationContext.items[i]].permission == DECORPERM_SPRITE)
|
||
|
{
|
||
|
SetDecorRearrangementShape(sDecorationContext.items[i], sDecorRearrangementDataBuffer);
|
||
|
if (DecorationIsUnderCursor(taskId, i, sDecorRearrangementDataBuffer) == TRUE)
|
||
|
{
|
||
|
sDecorRearrangementDataBuffer->idx = i;
|
||
|
SetDecorRearrangementFlagIdIfFlagUnset();
|
||
|
sCurDecorSelectedInRearrangement = 1;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void MarkSpriteDecorsInBoundsForRemoval(u8 left, u8 top, u8 right, u8 bottom)
|
||
|
{
|
||
|
u8 i;
|
||
|
u8 xOff;
|
||
|
u8 yOff;
|
||
|
u8 decor;
|
||
|
|
||
|
for (i = 0; i < sDecorationContext.size; i++)
|
||
|
{
|
||
|
decor = sDecorationContext.items[i];
|
||
|
xOff = sDecorationContext.pos[i] >> 4;
|
||
|
yOff = sDecorationContext.pos[i] & 0x0F;
|
||
|
if (decor != DECOR_NONE && gDecorations[decor].permission == DECORPERM_SPRITE && left <= xOff && top <= yOff && right >= xOff && bottom >= yOff)
|
||
|
{
|
||
|
sDecorRearrangementDataBuffer[sCurDecorSelectedInRearrangement].idx = i;
|
||
|
SetDecorRearrangementFlagIdIfFlagUnset();
|
||
|
sCurDecorSelectedInRearrangement++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void AttemptMarkDecorUnderCursorForRemoval(u8 taskId)
|
||
|
{
|
||
|
u8 i;
|
||
|
u8 xOff;
|
||
|
u8 yOff;
|
||
|
u8 var1;
|
||
|
u32 var2;
|
||
|
|
||
|
sCurDecorSelectedInRearrangement = 0;
|
||
|
if (AttemptMarkSpriteDecorUnderCursorForRemoval(taskId) != TRUE)
|
||
|
{
|
||
|
// Not a sprite.
|
||
|
for (i = 0; i < sDecorationContext.size; i++)
|
||
|
{
|
||
|
var1 = sDecorationContext.items[i];
|
||
|
if (var1 != DECOR_NONE)
|
||
|
{
|
||
|
SetDecorRearrangementShape(var1, &sDecorRearrangementDataBuffer[0]);
|
||
|
if (DecorationIsUnderCursor(taskId, i, &sDecorRearrangementDataBuffer[0]) == TRUE)
|
||
|
{
|
||
|
sDecorRearrangementDataBuffer[0].idx = i;
|
||
|
sCurDecorSelectedInRearrangement++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (sCurDecorSelectedInRearrangement != 0)
|
||
|
{
|
||
|
xOff = sDecorationContext.pos[sDecorRearrangementDataBuffer[0].idx] >> 4;
|
||
|
yOff = sDecorationContext.pos[sDecorRearrangementDataBuffer[0].idx] & 0x0F;
|
||
|
var1 = yOff - sDecorRearrangementDataBuffer[0].height + 1;
|
||
|
var2 = sDecorRearrangementDataBuffer[0].width + xOff - 1;
|
||
|
|
||
|
// Remove any dolls/cushions on this decoration.
|
||
|
MarkSpriteDecorsInBoundsForRemoval(xOff, var1, var2, yOff);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void ReturnDecorationPrompt(u8 taskId)
|
||
|
{
|
||
|
DisplayYesNoMenuDefaultYes();
|
||
|
DoYesNoFuncWithChoice(taskId, &sReturnDecorationYesNoFunctions);
|
||
|
}
|
||
|
|
||
|
static void PutAwayDecoration(u8 taskId)
|
||
|
{
|
||
|
FadeScreen(FADE_TO_BLACK, 0);
|
||
|
gTasks[taskId].tState = 0;
|
||
|
gTasks[taskId].func = Task_PutAwayDecoration;
|
||
|
}
|
||
|
|
||
|
static void StopPuttingAwayDecorationsPrompt(u8 taskId)
|
||
|
{
|
||
|
DisplayYesNoMenuDefaultYes();
|
||
|
DoYesNoFuncWithChoice(taskId, &sStopPuttingAwayDecorationsYesNoFunctions);
|
||
|
}
|
||
|
|
||
|
static void StopPuttingAwayDecorations(u8 taskId)
|
||
|
{
|
||
|
ClearDialogWindowAndFrame(0, 0);
|
||
|
StopPuttingAwayDecorations_(taskId);
|
||
|
}
|
||
|
|
||
|
static void StopPuttingAwayDecorations_(u8 taskId)
|
||
|
{
|
||
|
FadeScreen(FADE_TO_BLACK, 0);
|
||
|
gTasks[taskId].tState = 0;
|
||
|
gTasks[taskId].func = Task_StopPuttingAwayDecorations;
|
||
|
}
|
||
|
|
||
|
static void Task_StopPuttingAwayDecorations(u8 taskId)
|
||
|
{
|
||
|
switch (gTasks[taskId].tState)
|
||
|
{
|
||
|
case 0:
|
||
|
if (!gPaletteFade.active)
|
||
|
{
|
||
|
WarpToInitialPosition(taskId);
|
||
|
gTasks[taskId].tState = 1;
|
||
|
}
|
||
|
break;
|
||
|
case 1:
|
||
|
FreePlayerSpritePalette();
|
||
|
gFieldCallback = FieldCB_StopPuttingAwayDecorations;
|
||
|
SetMainCallback2(CB2_ReturnToField);
|
||
|
DestroyTask(taskId);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Task_ReinitializeDecorationMenuHandler(u8 taskId)
|
||
|
{
|
||
|
s16 *data = gTasks[taskId].data;
|
||
|
switch (tState)
|
||
|
{
|
||
|
case 0:
|
||
|
HideSecretBaseDecorationSprites();
|
||
|
tState++;
|
||
|
break;
|
||
|
case 1:
|
||
|
ScriptContext1_SetupScript(SecretBase_EventScript_InitDecorations);
|
||
|
tState++;
|
||
|
break;
|
||
|
case 2:
|
||
|
ScriptContext2_Enable();
|
||
|
tState++;
|
||
|
break;
|
||
|
case 3:
|
||
|
if (IsWeatherNotFadingIn() == TRUE)
|
||
|
gTasks[taskId].func = HandleDecorationActionsMenuInput;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void FieldCB_StopPuttingAwayDecorations(void)
|
||
|
{
|
||
|
u8 taskId;
|
||
|
|
||
|
FadeInFromBlack();
|
||
|
DrawDialogueFrame(0, 1);
|
||
|
InitDecorationActionsWindow();
|
||
|
taskId = CreateTask(Task_ReinitializeDecorationMenuHandler, 8);
|
||
|
gTasks[taskId].tState = 0;
|
||
|
}
|
||
|
|
||
|
static void InitializeCameraSprite1(struct Sprite *sprite)
|
||
|
{
|
||
|
sprite->data[0]++;
|
||
|
sprite->data[0] &= 0x1F;
|
||
|
if (sprite->data[0] > 15)
|
||
|
sprite->invisible = TRUE;
|
||
|
else
|
||
|
sprite->invisible = FALSE;
|
||
|
}
|
||
|
|
||
|
static void LoadPlayerSpritePalette(void)
|
||
|
{
|
||
|
if (gSaveBlock2Ptr->playerGender == MALE)
|
||
|
LoadSpritePalette(&sSpritePal_PuttingAwayCursorBrendan);
|
||
|
else
|
||
|
LoadSpritePalette(&sSpritePal_PuttingAwayCursorMay);
|
||
|
}
|
||
|
|
||
|
static void FreePlayerSpritePalette(void)
|
||
|
{
|
||
|
FreeSpritePaletteByTag(PLACE_DECORATION_PLAYER_TAG);
|
||
|
}
|
||
|
|
||
|
static void DecorationItemsMenuAction_AttemptToss(u8 taskId)
|
||
|
{
|
||
|
if (IsSelectedDecorInThePC() == TRUE)
|
||
|
{
|
||
|
StringCopy(gStringVar1, gDecorations[gCurDecorationItems[gCurDecorationIndex]].name);
|
||
|
StringExpandPlaceholders(gStringVar4, gText_DecorationWillBeDiscarded);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, TossDecorationPrompt);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StringExpandPlaceholders(gStringVar4, gText_CantThrowAwayInUse);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationItemsAfterInvalidSelection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void TossDecorationPrompt(u8 taskId)
|
||
|
{
|
||
|
DisplayYesNoMenuDefaultYes();
|
||
|
DoYesNoFuncWithChoice(taskId, &sTossDecorationYesNoFunctions);
|
||
|
}
|
||
|
|
||
|
static void TossDecoration(u8 taskId)
|
||
|
{
|
||
|
gCurDecorationItems[gCurDecorationIndex] = DECOR_NONE;
|
||
|
sNumOwnedDecorationsInCurCategory = GetNumOwnedDecorationsInCategory(sCurDecorationCategory);
|
||
|
CondenseDecorationsInCategory(sCurDecorationCategory);
|
||
|
IdentifyOwnedDecorationsCurrentlyInUseInternal(taskId);
|
||
|
StringExpandPlaceholders(gStringVar4, gText_DecorationThrownAway);
|
||
|
DisplayItemMessageOnField(taskId, gStringVar4, ReturnToDecorationItemsAfterInvalidSelection);
|
||
|
}
|