1321 lines
37 KiB
C
1321 lines
37 KiB
C
#include "global.h"
|
|
#include "gpu_regs.h"
|
|
#include "palette.h"
|
|
#include "script.h"
|
|
#include "sound.h"
|
|
#include "task.h"
|
|
#include "strings.h"
|
|
#include "party_menu.h"
|
|
#include "fieldmap.h"
|
|
#include "field_effect.h"
|
|
#include "field_camera.h"
|
|
#include "field_player_avatar.h"
|
|
#include "fldeff.h"
|
|
#include "fldeff_misc.h"
|
|
#include "secret_base.h"
|
|
#include "event_data.h"
|
|
#include "event_scripts.h"
|
|
#include "event_object_movement.h"
|
|
#include "metatile_behavior.h"
|
|
#include "string_util.h"
|
|
#include "constants/field_effects.h"
|
|
#include "constants/metatile_behaviors.h"
|
|
#include "constants/metatile_labels.h"
|
|
#include "constants/songs.h"
|
|
|
|
|
|
EWRAM_DATA struct MapPosition gPlayerFacingPosition = {0};
|
|
|
|
static void Task_ComputerScreenOpenEffect(u8);
|
|
static void Task_ComputerScreenCloseEffect(u8);
|
|
static void CreateComputerScreenEffectTask(TaskFunc, u16, u16, u8);
|
|
|
|
static void Task_SecretBasePCTurnOn(u8);
|
|
|
|
static void Task_PopSecretBaseBalloon(u8);
|
|
static void DoBalloonSoundEffect(s16);
|
|
|
|
static void Task_WateringBerryTreeAnim_Start(u8);
|
|
static void Task_WateringBerryTreeAnim_Continue(u8);
|
|
static void Task_WateringBerryTreeAnim_End(u8);
|
|
|
|
static void FieldCallback_SecretBaseCave(void);
|
|
static void SpriteCB_CaveEntranceInit(struct Sprite *);
|
|
static void SpriteCB_CaveEntranceOpen(struct Sprite *);
|
|
static void SpriteCB_CaveEntranceEnd(struct Sprite *);
|
|
static void StartSecretBaseCaveFieldEffect(void);
|
|
|
|
static void FieldCallback_SecretBaseTree(void);
|
|
static void SpriteCB_TreeEntranceInit(struct Sprite *);
|
|
static void SpriteCB_TreeEntranceOpen(struct Sprite *);
|
|
static void SpriteCB_TreeEntranceEnd(struct Sprite *);
|
|
static void StartSecretBaseTreeFieldEffect(void);
|
|
|
|
static void FieldCallback_SecretBaseShrub(void);
|
|
static void SpriteCB_ShrubEntranceInit(struct Sprite *);
|
|
static void SpriteCB_ShrubEntranceOpen(struct Sprite *);
|
|
static void SpriteCB_ShrubEntranceEnd(struct Sprite *);
|
|
static void StartSecretBaseShrubFieldEffect(void);
|
|
|
|
static void SpriteCB_SandPillar_BreakTop(struct Sprite *);
|
|
static void SpriteCB_SandPillar_BreakBase(struct Sprite *);
|
|
static void SpriteCB_SandPillar_End(struct Sprite *);
|
|
|
|
static const u8 sSecretPowerCave_Gfx[] = INCBIN_U8("graphics/field_effects/pics/secret_power_cave.4bpp");
|
|
static const u8 sFiller[32] = {0};
|
|
static const u16 sSecretPowerCave_Pal[] = INCBIN_U16("graphics/field_effects/palettes/secret_power_cave.gbapal");
|
|
static const u8 sSecretPowerShrub_Gfx[] = INCBIN_U8("graphics/field_effects/pics/secret_power_shrub.4bpp");
|
|
static const u8 sSecretPowerTree_Gfx[] = INCBIN_U8("graphics/field_effects/pics/secret_power_tree.4bpp");
|
|
static const u16 sSecretPowerPlant_Pal[] = INCBIN_U16("graphics/field_effects/palettes/secret_power_plant.gbapal");
|
|
|
|
// TODO: These should also be combined into a single image, not matching for some reason
|
|
static const u8 sSandPillar0_Gfx[] = INCBIN_U8("graphics/field_effects/pics/sand_pillar/0.4bpp");
|
|
static const u8 sSandPillar1_Gfx[] = INCBIN_U8("graphics/field_effects/pics/sand_pillar/1.4bpp");
|
|
static const u8 sSandPillar2_Gfx[] = INCBIN_U8("graphics/field_effects/pics/sand_pillar/2.4bpp");
|
|
|
|
static const struct OamData sOam_SecretPower =
|
|
{
|
|
.y = 0,
|
|
.x = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(16x16),
|
|
.size = SPRITE_SIZE(16x16),
|
|
.priority = 2,
|
|
};
|
|
|
|
static const union AnimCmd sAnim_SecretPowerCave[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 8),
|
|
ANIMCMD_FRAME(1, 8),
|
|
ANIMCMD_FRAME(2, 8),
|
|
ANIMCMD_FRAME(3, 8),
|
|
ANIMCMD_FRAME(4, 8),
|
|
ANIMCMD_END,
|
|
};
|
|
|
|
static const union AnimCmd sAnim_VineDropLeft[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 8),
|
|
ANIMCMD_FRAME(1, 8),
|
|
ANIMCMD_FRAME(2, 8),
|
|
ANIMCMD_FRAME(3, 8),
|
|
ANIMCMD_FRAME(4, 8),
|
|
ANIMCMD_END,
|
|
};
|
|
|
|
static const union AnimCmd sAnim_VineRiseLeft[] =
|
|
{
|
|
ANIMCMD_FRAME(4, 8),
|
|
ANIMCMD_FRAME(3, 8),
|
|
ANIMCMD_FRAME(2, 8),
|
|
ANIMCMD_FRAME(1, 8),
|
|
ANIMCMD_FRAME(0, 8),
|
|
ANIMCMD_END,
|
|
};
|
|
|
|
static const union AnimCmd sAnim_VineDropRight[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(1, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(2, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(3, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(4, 8, .hFlip = TRUE),
|
|
ANIMCMD_END,
|
|
};
|
|
|
|
static const union AnimCmd sAnim_VineRiseRight[] =
|
|
{
|
|
ANIMCMD_FRAME(4, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(3, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(2, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(1, 8, .hFlip = TRUE),
|
|
ANIMCMD_FRAME(0, 8, .hFlip = TRUE),
|
|
ANIMCMD_END,
|
|
};
|
|
|
|
static const union AnimCmd sAnim_SecretPowerShrub[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 8),
|
|
ANIMCMD_FRAME(1, 8),
|
|
ANIMCMD_FRAME(2, 8),
|
|
ANIMCMD_FRAME(3, 8),
|
|
ANIMCMD_FRAME(4, 8),
|
|
ANIMCMD_END,
|
|
};
|
|
|
|
static const union AnimCmd *const sAnimTable_SecretPowerCave[] =
|
|
{
|
|
sAnim_SecretPowerCave,
|
|
};
|
|
|
|
static const union AnimCmd *const sAnimTable_SecretPowerTree[] =
|
|
{
|
|
sAnim_VineDropLeft,
|
|
sAnim_VineRiseLeft,
|
|
sAnim_VineDropRight,
|
|
sAnim_VineRiseRight,
|
|
};
|
|
|
|
static const union AnimCmd *const sAnimTable_SecretPowerShrub[] =
|
|
{
|
|
sAnim_SecretPowerShrub,
|
|
};
|
|
|
|
static const struct SpriteFrameImage sPicTable_SecretPowerCave[] =
|
|
{
|
|
overworld_frame(sSecretPowerCave_Gfx, 2, 2, 0),
|
|
overworld_frame(sSecretPowerCave_Gfx, 2, 2, 1),
|
|
overworld_frame(sSecretPowerCave_Gfx, 2, 2, 2),
|
|
overworld_frame(sSecretPowerCave_Gfx, 2, 2, 3),
|
|
overworld_frame(sSecretPowerCave_Gfx, 2, 2, 4),
|
|
};
|
|
|
|
static const struct SpriteFrameImage sPicTable_SecretPowerTree[] =
|
|
{
|
|
overworld_frame(sSecretPowerTree_Gfx, 2, 2, 0),
|
|
overworld_frame(sSecretPowerTree_Gfx, 2, 2, 1),
|
|
overworld_frame(sSecretPowerTree_Gfx, 2, 2, 2),
|
|
overworld_frame(sSecretPowerTree_Gfx, 2, 2, 3),
|
|
overworld_frame(sSecretPowerTree_Gfx, 2, 2, 4),
|
|
// 6th frame exists but isnt accessed, the tree vine metatile is used instead
|
|
};
|
|
|
|
static const struct SpriteFrameImage sPicTable_SecretPowerShrub[] =
|
|
{
|
|
overworld_frame(sSecretPowerShrub_Gfx, 2, 2, 0),
|
|
overworld_frame(sSecretPowerShrub_Gfx, 2, 2, 1),
|
|
overworld_frame(sSecretPowerShrub_Gfx, 2, 2, 2),
|
|
overworld_frame(sSecretPowerShrub_Gfx, 2, 2, 3),
|
|
overworld_frame(sSecretPowerShrub_Gfx, 2, 2, 4),
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_SecretPowerCave =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = FLDEFF_PAL_TAG_SECRET_POWER_TREE,
|
|
.oam = &sOam_SecretPower,
|
|
.anims = sAnimTable_SecretPowerCave,
|
|
.images = sPicTable_SecretPowerCave,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_CaveEntranceInit,
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_SecretPowerTree =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = FLDEFF_PAL_TAG_SECRET_POWER_PLANT,
|
|
.oam = &sOam_SecretPower,
|
|
.anims = sAnimTable_SecretPowerTree,
|
|
.images = sPicTable_SecretPowerTree,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_TreeEntranceInit,
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_SecretPowerShrub =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = FLDEFF_PAL_TAG_SECRET_POWER_PLANT,
|
|
.oam = &sOam_SecretPower,
|
|
.anims = sAnimTable_SecretPowerShrub,
|
|
.images = sPicTable_SecretPowerShrub,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_ShrubEntranceInit,
|
|
};
|
|
|
|
const struct SpritePalette gSpritePalette_SecretPower_Cave = {sSecretPowerCave_Pal, FLDEFF_PAL_TAG_SECRET_POWER_TREE};
|
|
const struct SpritePalette gSpritePalette_SecretPower_Plant = {sSecretPowerPlant_Pal, FLDEFF_PAL_TAG_SECRET_POWER_PLANT};
|
|
|
|
static const struct OamData sOam_SandPillar =
|
|
{
|
|
.x = 0,
|
|
.y = 0,
|
|
.affineMode = ST_OAM_AFFINE_OFF,
|
|
.objMode = ST_OAM_OBJ_NORMAL,
|
|
.bpp = ST_OAM_4BPP,
|
|
.shape = SPRITE_SHAPE(16x32),
|
|
.size = SPRITE_SIZE(16x32),
|
|
.priority = 2,
|
|
};
|
|
|
|
static const union AnimCmd sAnim_SandPillar[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 6),
|
|
ANIMCMD_FRAME(1, 6),
|
|
ANIMCMD_FRAME(2, 6),
|
|
ANIMCMD_END,
|
|
};
|
|
|
|
static const union AnimCmd *const sAnimTable_SandPillar[] =
|
|
{
|
|
sAnim_SandPillar,
|
|
};
|
|
|
|
static const struct SpriteFrameImage sPicTable_SandPillar[] =
|
|
{
|
|
{sSandPillar0_Gfx, sizeof(sSandPillar0_Gfx)},
|
|
{sSandPillar1_Gfx, sizeof(sSandPillar1_Gfx)},
|
|
{sSandPillar2_Gfx, sizeof(sSandPillar2_Gfx)},
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_SandPillar =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = FLDEFF_PAL_TAG_SAND_PILLAR,
|
|
.oam = &sOam_SandPillar,
|
|
.anims = sAnimTable_SandPillar,
|
|
.images = sPicTable_SandPillar,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCB_SandPillar_BreakTop,
|
|
};
|
|
|
|
const struct SpritePalette gSpritePalette_SandPillar = {gTilesetPalettes_SecretBase[5], FLDEFF_PAL_TAG_SAND_PILLAR};
|
|
|
|
static const u8 sRecordMixLights_Gfx[] = INCBIN_U8("graphics/field_effects/pics/record_mix_lights.4bpp");
|
|
static const u16 sRecordMixLights_Pal[] = INCBIN_U16("graphics/field_effects/palettes/record_mix_lights.gbapal");
|
|
|
|
static const struct SpriteFrameImage sPicTable_RecordMixLights[] =
|
|
{
|
|
overworld_frame(sRecordMixLights_Gfx, 4, 1, 0),
|
|
overworld_frame(sRecordMixLights_Gfx, 4, 1, 1),
|
|
overworld_frame(sRecordMixLights_Gfx, 4, 1, 2),
|
|
};
|
|
|
|
static const struct SpritePalette sSpritePalette_RecordMixLights = {sRecordMixLights_Pal, 0x1000};
|
|
|
|
static const union AnimCmd sAnim_RecordMixLights[] =
|
|
{
|
|
ANIMCMD_FRAME(0, 30),
|
|
ANIMCMD_FRAME(1, 30),
|
|
ANIMCMD_FRAME(2, 30),
|
|
ANIMCMD_JUMP(0),
|
|
};
|
|
|
|
static const union AnimCmd *const sAnimTable_RecordMixLights[] =
|
|
{
|
|
sAnim_RecordMixLights,
|
|
};
|
|
|
|
static const struct SpriteTemplate sSpriteTemplate_RecordMixLights =
|
|
{
|
|
.tileTag = TAG_NONE,
|
|
.paletteTag = 0x1000,
|
|
.oam = &gObjectEventBaseOam_32x8,
|
|
.anims = sAnimTable_RecordMixLights,
|
|
.images = sPicTable_RecordMixLights,
|
|
.affineAnims = gDummySpriteAffineAnimTable,
|
|
.callback = SpriteCallbackDummy,
|
|
};
|
|
|
|
// For accessing pokemon storage PC or the Hall of Fame PC
|
|
void ComputerScreenOpenEffect(u16 increment, u16 unused, u8 priority)
|
|
{
|
|
CreateComputerScreenEffectTask(Task_ComputerScreenOpenEffect, increment, unused, priority);
|
|
}
|
|
|
|
void ComputerScreenCloseEffect(u16 increment, u16 unused, u8 priority)
|
|
{
|
|
CreateComputerScreenEffectTask(Task_ComputerScreenCloseEffect, increment, unused, priority);
|
|
}
|
|
|
|
bool8 IsComputerScreenOpenEffectActive(void)
|
|
{
|
|
return FuncIsActiveTask(Task_ComputerScreenOpenEffect);
|
|
}
|
|
|
|
bool8 IsComputerScreenCloseEffectActive(void)
|
|
{
|
|
return FuncIsActiveTask(Task_ComputerScreenCloseEffect);
|
|
}
|
|
|
|
#define tState data[0]
|
|
#define tHorzIncrement data[1]
|
|
#define tVertIncrement data[2]
|
|
#define tWinLeft data[3]
|
|
#define tWinRight data[4]
|
|
#define tWinTop data[5]
|
|
#define tWinBottom data[6]
|
|
#define tBlendCnt data[7]
|
|
#define tBlendY data[8]
|
|
|
|
static void CreateComputerScreenEffectTask(void (*taskfunc) (u8), u16 increment, u16 unused, u8 priority)
|
|
{
|
|
u8 taskId = CreateTask(taskfunc, priority);
|
|
|
|
gTasks[taskId].tState = 0;
|
|
gTasks[taskId].tHorzIncrement = increment == 0 ? 16 : increment;
|
|
gTasks[taskId].tVertIncrement = increment == 0 ? 20 : increment;
|
|
gTasks[taskId].func(taskId);
|
|
}
|
|
|
|
static void Task_ComputerScreenOpenEffect(u8 taskId)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
|
|
switch (task->tState)
|
|
{
|
|
case 0:
|
|
task->tWinLeft = DISPLAY_WIDTH / 2;
|
|
task->tWinRight = DISPLAY_WIDTH / 2;
|
|
task->tWinTop = DISPLAY_HEIGHT / 2;
|
|
task->tWinBottom = DISPLAY_HEIGHT / 2 + 1;
|
|
|
|
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON);
|
|
SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight));
|
|
SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom));
|
|
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
|
|
SetGpuReg(REG_OFFSET_WINOUT, 0);
|
|
|
|
break;
|
|
case 1:
|
|
task->tBlendCnt = GetGpuReg(REG_OFFSET_BLDCNT);
|
|
task->tBlendY = GetGpuReg(REG_OFFSET_BLDY);
|
|
|
|
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_ALL | BLDCNT_EFFECT_LIGHTEN);
|
|
SetGpuReg(REG_OFFSET_BLDY, 16);
|
|
|
|
break;
|
|
case 2:
|
|
task->tWinLeft -= task->tHorzIncrement;
|
|
task->tWinRight += task->tHorzIncrement;
|
|
|
|
if (task->tWinLeft < 1 || task->tWinRight > DISPLAY_WIDTH - 1)
|
|
{
|
|
task->tWinLeft = 0;
|
|
task->tWinRight = DISPLAY_WIDTH;
|
|
SetGpuReg(REG_OFFSET_BLDY, 0);
|
|
SetGpuReg(REG_OFFSET_BLDCNT, task->tBlendCnt);
|
|
BlendPalettes(PALETTES_ALL, 0, 0);
|
|
gPlttBufferFaded[0] = 0;
|
|
}
|
|
SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight));
|
|
|
|
if (task->tWinLeft != 0)
|
|
return;
|
|
break;
|
|
case 3:
|
|
task->tWinTop -= task->tVertIncrement;
|
|
task->tWinBottom += task->tVertIncrement;
|
|
|
|
if (task->tWinTop < 1 || task->tWinBottom > DISPLAY_HEIGHT - 1)
|
|
{
|
|
task->tWinTop = 0;
|
|
task->tWinBottom = DISPLAY_HEIGHT;
|
|
ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON);
|
|
}
|
|
SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom));
|
|
|
|
if (task->tWinTop != 0)
|
|
return;
|
|
break;
|
|
default:
|
|
SetGpuReg(REG_OFFSET_BLDCNT, task->tBlendCnt);
|
|
DestroyTask(taskId);
|
|
return;
|
|
}
|
|
task->tState++;
|
|
}
|
|
|
|
static void Task_ComputerScreenCloseEffect(u8 taskId)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
|
|
switch (task->tState)
|
|
{
|
|
case 0:
|
|
gPlttBufferFaded[0] = 0;
|
|
break;
|
|
case 1:
|
|
task->tWinLeft = 0;
|
|
task->tWinRight = DISPLAY_WIDTH;
|
|
task->tWinTop = 0;
|
|
task->tWinBottom = DISPLAY_HEIGHT;
|
|
|
|
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON);
|
|
SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight));
|
|
SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom));
|
|
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
|
|
SetGpuReg(REG_OFFSET_WINOUT, 0);
|
|
break;
|
|
case 2:
|
|
task->tWinTop += task->tVertIncrement;
|
|
task->tWinBottom -= task->tVertIncrement;
|
|
|
|
if (task->tWinTop >= DISPLAY_HEIGHT / 2 || task->tWinBottom <= DISPLAY_HEIGHT / 2 + 1)
|
|
{
|
|
task->tWinTop = DISPLAY_HEIGHT / 2;
|
|
task->tWinBottom = DISPLAY_HEIGHT / 2 + 1;
|
|
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_ALL | BLDCNT_EFFECT_LIGHTEN);
|
|
SetGpuReg(REG_OFFSET_BLDY, 16);
|
|
}
|
|
SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(task->tWinTop, task->tWinBottom));
|
|
|
|
if (task->tWinTop != DISPLAY_HEIGHT / 2)
|
|
return;
|
|
break;
|
|
case 3:
|
|
task->tWinLeft += task->tHorzIncrement;
|
|
task->tWinRight -= task->tHorzIncrement;
|
|
|
|
if (task->tWinLeft >= DISPLAY_WIDTH / 2 || task->tWinRight <= DISPLAY_WIDTH / 2)
|
|
{
|
|
task->tWinLeft = DISPLAY_WIDTH / 2;
|
|
task->tWinRight = DISPLAY_WIDTH / 2;
|
|
BlendPalettes(PALETTES_ALL, 16, 0);
|
|
gPlttBufferFaded[0] = 0;
|
|
}
|
|
SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(task->tWinLeft, task->tWinRight));
|
|
|
|
if (task->tWinLeft != DISPLAY_WIDTH / 2)
|
|
return;
|
|
break;
|
|
default:
|
|
ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_WIN0_ON);
|
|
SetGpuReg(REG_OFFSET_BLDY, 0);
|
|
SetGpuReg(REG_OFFSET_BLDCNT, 0);
|
|
DestroyTask(taskId);
|
|
return;
|
|
}
|
|
task->tState++;
|
|
}
|
|
|
|
#undef tState
|
|
#undef tHorzIncrement
|
|
#undef tVertIncrement
|
|
#undef tWinLeft
|
|
#undef tWinRight
|
|
#undef tWinTop
|
|
#undef tWinBottom
|
|
#undef tBlendCnt
|
|
#undef tBlendY
|
|
|
|
static void SetCurrentSecretBase(void)
|
|
{
|
|
SetCurSecretBaseIdFromPosition(&gPlayerFacingPosition, gMapHeader.events);
|
|
TrySetCurSecretBaseIndex();
|
|
}
|
|
|
|
static void AdjustSecretPowerSpritePixelOffsets(void)
|
|
{
|
|
if (gPlayerAvatar.flags & (PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE))
|
|
{
|
|
switch (gFieldEffectArguments[1])
|
|
{
|
|
case DIR_SOUTH:
|
|
gFieldEffectArguments[5] = 16;
|
|
gFieldEffectArguments[6] = 40;
|
|
break;
|
|
case DIR_NORTH:
|
|
gFieldEffectArguments[5] = 16;
|
|
gFieldEffectArguments[6] = 8;
|
|
break;
|
|
case DIR_WEST:
|
|
gFieldEffectArguments[5] = -8;
|
|
gFieldEffectArguments[6] = 24;
|
|
break;
|
|
case DIR_EAST:
|
|
gFieldEffectArguments[5] = 24;
|
|
gFieldEffectArguments[6] = 24;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (gFieldEffectArguments[1])
|
|
{
|
|
case DIR_SOUTH:
|
|
gFieldEffectArguments[5] = 8;
|
|
gFieldEffectArguments[6] = 40;
|
|
break;
|
|
case DIR_NORTH:
|
|
gFieldEffectArguments[5] = 8;
|
|
gFieldEffectArguments[6] = 8;
|
|
break;
|
|
case DIR_WEST:
|
|
gFieldEffectArguments[5] = -8;
|
|
gFieldEffectArguments[6] = 24;
|
|
break;
|
|
case DIR_EAST:
|
|
gFieldEffectArguments[5] = 24;
|
|
gFieldEffectArguments[6] = 24;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool8 SetUpFieldMove_SecretPower(void)
|
|
{
|
|
u8 mb;
|
|
|
|
CheckPlayerHasSecretBase();
|
|
|
|
if (gSpecialVar_Result == 1 || GetPlayerFacingDirection() != DIR_NORTH)
|
|
return FALSE;
|
|
|
|
GetXYCoordsOneStepInFrontOfPlayer(&gPlayerFacingPosition.x, &gPlayerFacingPosition.y);
|
|
mb = MapGridGetMetatileBehaviorAt(gPlayerFacingPosition.x, gPlayerFacingPosition.y);
|
|
|
|
if (MetatileBehavior_IsSecretBaseCave(mb) == TRUE)
|
|
{
|
|
SetCurrentSecretBase();
|
|
gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
|
|
gPostMenuFieldCallback = FieldCallback_SecretBaseCave;
|
|
return TRUE;
|
|
}
|
|
|
|
if (MetatileBehavior_IsSecretBaseTree(mb) == TRUE)
|
|
{
|
|
SetCurrentSecretBase();
|
|
gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
|
|
gPostMenuFieldCallback = FieldCallback_SecretBaseTree;
|
|
return TRUE;
|
|
}
|
|
|
|
if (MetatileBehavior_IsSecretBaseShrub(mb) == TRUE)
|
|
{
|
|
SetCurrentSecretBase();
|
|
gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
|
|
gPostMenuFieldCallback = FieldCallback_SecretBaseShrub;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void FieldCallback_SecretBaseCave(void)
|
|
{
|
|
gFieldEffectArguments[0] = GetCursorSelectionMonId();
|
|
ScriptContext1_SetupScript(SecretBase_EventScript_CaveUseSecretPower);
|
|
}
|
|
|
|
bool8 FldEff_UseSecretPowerCave(void)
|
|
{
|
|
u8 taskId = CreateFieldMoveTask();
|
|
|
|
gTasks[taskId].data[8] = (u32)StartSecretBaseCaveFieldEffect >> 16;
|
|
gTasks[taskId].data[9] = (u32)StartSecretBaseCaveFieldEffect;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void StartSecretBaseCaveFieldEffect(void)
|
|
{
|
|
FieldEffectActiveListRemove(FLDEFF_USE_SECRET_POWER_CAVE);
|
|
FieldEffectStart(FLDEFF_SECRET_POWER_CAVE);
|
|
}
|
|
|
|
bool8 FldEff_SecretPowerCave(void)
|
|
{
|
|
AdjustSecretPowerSpritePixelOffsets();
|
|
CreateSprite(&sSpriteTemplate_SecretPowerCave,
|
|
gSprites[gPlayerAvatar.spriteId].oam.x + gFieldEffectArguments[5],
|
|
gSprites[gPlayerAvatar.spriteId].oam.y + gFieldEffectArguments[6],
|
|
148);
|
|
return FALSE;
|
|
}
|
|
|
|
static void SpriteCB_CaveEntranceInit(struct Sprite *sprite)
|
|
{
|
|
PlaySE(SE_M_ROCK_THROW);
|
|
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_CaveEntranceOpen;
|
|
}
|
|
|
|
static void SpriteCB_CaveEntranceOpen(struct Sprite *sprite)
|
|
{
|
|
if (sprite->data[0] < 40)
|
|
{
|
|
if (++sprite->data[0] == 20)
|
|
ToggleSecretBaseEntranceMetatile();
|
|
}
|
|
else
|
|
{
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_CaveEntranceEnd;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_CaveEntranceEnd(struct Sprite *sprite)
|
|
{
|
|
FieldEffectStop(sprite, FLDEFF_SECRET_POWER_CAVE);
|
|
EnableBothScriptContexts();
|
|
}
|
|
|
|
static void FieldCallback_SecretBaseTree(void)
|
|
{
|
|
gFieldEffectArguments[0] = GetCursorSelectionMonId();
|
|
ScriptContext1_SetupScript(SecretBase_EventScript_TreeUseSecretPower);
|
|
}
|
|
|
|
bool8 FldEff_UseSecretPowerTree(void)
|
|
{
|
|
u8 taskId = CreateFieldMoveTask();
|
|
|
|
gTasks[taskId].data[8] = (u32)StartSecretBaseTreeFieldEffect >> 16;
|
|
gTasks[taskId].data[9] = (u32)StartSecretBaseTreeFieldEffect;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void StartSecretBaseTreeFieldEffect(void)
|
|
{
|
|
FieldEffectActiveListRemove(FLDEFF_USE_SECRET_POWER_TREE);
|
|
FieldEffectStart(FLDEFF_SECRET_POWER_TREE);
|
|
}
|
|
|
|
bool8 FldEff_SecretPowerTree(void)
|
|
{
|
|
s16 mb = MapGridGetMetatileBehaviorAt(gPlayerFacingPosition.x, gPlayerFacingPosition.y) & 0xFFF;
|
|
|
|
if (mb == MB_SECRET_BASE_SPOT_TREE_LEFT)
|
|
gFieldEffectArguments[7] = 0;
|
|
|
|
if (mb == MB_SECRET_BASE_SPOT_TREE_RIGHT)
|
|
gFieldEffectArguments[7] = 2;
|
|
|
|
AdjustSecretPowerSpritePixelOffsets();
|
|
|
|
CreateSprite(&sSpriteTemplate_SecretPowerTree,
|
|
gSprites[gPlayerAvatar.spriteId].oam.x + gFieldEffectArguments[5],
|
|
gSprites[gPlayerAvatar.spriteId].oam.y + gFieldEffectArguments[6],
|
|
148);
|
|
|
|
if (gFieldEffectArguments[7] == 1 || gFieldEffectArguments[7] == 3)
|
|
ToggleSecretBaseEntranceMetatile();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void SpriteCB_TreeEntranceInit(struct Sprite *sprite)
|
|
{
|
|
PlaySE(SE_M_SCRATCH);
|
|
|
|
sprite->animNum = gFieldEffectArguments[7];
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_TreeEntranceOpen;
|
|
}
|
|
|
|
static void SpriteCB_TreeEntranceOpen(struct Sprite *sprite)
|
|
{
|
|
sprite->data[0]++;
|
|
|
|
if (sprite->data[0] >= 40)
|
|
{
|
|
if (gFieldEffectArguments[7] == 0 || gFieldEffectArguments[7] == 2)
|
|
ToggleSecretBaseEntranceMetatile();
|
|
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_TreeEntranceEnd;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_TreeEntranceEnd(struct Sprite *sprite)
|
|
{
|
|
FieldEffectStop(sprite, FLDEFF_SECRET_POWER_TREE);
|
|
EnableBothScriptContexts();
|
|
}
|
|
|
|
static void FieldCallback_SecretBaseShrub(void)
|
|
{
|
|
gFieldEffectArguments[0] = GetCursorSelectionMonId();
|
|
ScriptContext1_SetupScript(SecretBase_EventScript_ShrubUseSecretPower);
|
|
}
|
|
|
|
bool8 FldEff_UseSecretPowerShrub(void)
|
|
{
|
|
u8 taskId = CreateFieldMoveTask();
|
|
|
|
gTasks[taskId].data[8] = (u32)StartSecretBaseShrubFieldEffect >> 16;
|
|
gTasks[taskId].data[9] = (u32)StartSecretBaseShrubFieldEffect;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void StartSecretBaseShrubFieldEffect(void)
|
|
{
|
|
FieldEffectActiveListRemove(FLDEFF_USE_SECRET_POWER_SHRUB);
|
|
FieldEffectStart(FLDEFF_SECRET_POWER_SHRUB);
|
|
}
|
|
|
|
bool8 FldEff_SecretPowerShrub(void)
|
|
{
|
|
AdjustSecretPowerSpritePixelOffsets();
|
|
|
|
CreateSprite(&sSpriteTemplate_SecretPowerShrub,
|
|
gSprites[gPlayerAvatar.spriteId].oam.x + gFieldEffectArguments[5],
|
|
gSprites[gPlayerAvatar.spriteId].oam.y + gFieldEffectArguments[6],
|
|
148);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void SpriteCB_ShrubEntranceInit(struct Sprite *sprite)
|
|
{
|
|
PlaySE(SE_M_POISON_POWDER);
|
|
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_ShrubEntranceOpen;
|
|
}
|
|
|
|
static void SpriteCB_ShrubEntranceOpen(struct Sprite *sprite)
|
|
{
|
|
if (sprite->data[0] < 40)
|
|
{
|
|
sprite->data[0]++;
|
|
|
|
if (sprite->data[0] == 20)
|
|
ToggleSecretBaseEntranceMetatile();
|
|
}
|
|
else
|
|
{
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_ShrubEntranceEnd;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_ShrubEntranceEnd(struct Sprite *sprite)
|
|
{
|
|
FieldEffectStop(sprite, FLDEFF_SECRET_POWER_SHRUB);
|
|
EnableBothScriptContexts();
|
|
}
|
|
|
|
#define tX data[0]
|
|
#define tY data[1]
|
|
#define tState data[2]
|
|
|
|
bool8 FldEff_SecretBasePCTurnOn(void)
|
|
{
|
|
s16 x, y;
|
|
u8 taskId;
|
|
|
|
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
|
|
|
|
taskId = CreateTask(Task_SecretBasePCTurnOn, 0);
|
|
gTasks[taskId].tX = x;
|
|
gTasks[taskId].tY = y;
|
|
gTasks[taskId].tState = 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_SecretBasePCTurnOn(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
switch (tState)
|
|
{
|
|
case 4:
|
|
case 12:
|
|
MapGridSetMetatileIdAt(tX, tY, METATILE_SecretBase_PC_On);
|
|
CurrentMapDrawMetatileAt(tX, tY);
|
|
break;
|
|
case 8:
|
|
case 16:
|
|
MapGridSetMetatileIdAt(tX, tY, METATILE_SecretBase_PC);
|
|
CurrentMapDrawMetatileAt(tX, tY);
|
|
break;
|
|
case 20:
|
|
MapGridSetMetatileIdAt(tX, tY, METATILE_SecretBase_PC_On);
|
|
CurrentMapDrawMetatileAt(tX, tY);
|
|
FieldEffectActiveListRemove(FLDEFF_PCTURN_ON);
|
|
EnableBothScriptContexts();
|
|
DestroyTask(taskId);
|
|
return;
|
|
}
|
|
|
|
tState++;
|
|
}
|
|
|
|
#undef tX
|
|
#undef tY
|
|
#undef tState
|
|
|
|
void DoSecretBasePCTurnOffEffect(void)
|
|
{
|
|
s16 x, y;
|
|
|
|
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
|
|
PlaySE(SE_PC_OFF);
|
|
|
|
if (!VarGet(VAR_CURRENT_SECRET_BASE))
|
|
MapGridSetMetatileIdAt(x, y, METATILE_SecretBase_PC | METATILE_COLLISION_MASK);
|
|
else
|
|
MapGridSetMetatileIdAt(x, y, METATILE_SecretBase_RegisterPC | METATILE_COLLISION_MASK);
|
|
|
|
CurrentMapDrawMetatileAt(x, y);
|
|
}
|
|
|
|
void PopSecretBaseBalloon(s16 metatileId, s16 x, s16 y)
|
|
{
|
|
u8 taskId = CreateTask(Task_PopSecretBaseBalloon, 0);
|
|
|
|
gTasks[taskId].data[0] = metatileId;
|
|
gTasks[taskId].data[1] = x;
|
|
gTasks[taskId].data[2] = y;
|
|
gTasks[taskId].data[3] = 0;
|
|
gTasks[taskId].data[4] = 1;
|
|
}
|
|
|
|
static void Task_PopSecretBaseBalloon(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
if (data[3] == 6)
|
|
data[3] = 0;
|
|
else
|
|
data[3]++;
|
|
|
|
if (data[3] == 0)
|
|
{
|
|
if (data[4] == 2)
|
|
DoBalloonSoundEffect(data[0]);
|
|
|
|
MapGridSetMetatileIdAt(data[1], data[2], data[0] + data[4]);
|
|
CurrentMapDrawMetatileAt(data[1], data[2]);
|
|
|
|
if (data[4] == 3)
|
|
DestroyTask(taskId);
|
|
else
|
|
data[4]++;
|
|
}
|
|
}
|
|
|
|
static void DoBalloonSoundEffect(s16 metatileId)
|
|
{
|
|
switch (metatileId)
|
|
{
|
|
case METATILE_SecretBase_RedBalloon:
|
|
PlaySE(SE_BALLOON_RED);
|
|
break;
|
|
case METATILE_SecretBase_BlueBalloon:
|
|
PlaySE(SE_BALLOON_BLUE);
|
|
break;
|
|
case METATILE_SecretBase_YellowBalloon:
|
|
PlaySE(SE_BALLOON_YELLOW);
|
|
break;
|
|
case METATILE_SecretBase_MudBall:
|
|
PlaySE(SE_MUD_BALL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool8 FldEff_Nop47(void)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 FldEff_Nop48(void)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void DoSecretBaseBreakableDoorEffect(s16 x, s16 y)
|
|
{
|
|
PlaySE(SE_BREAKABLE_DOOR);
|
|
MapGridSetMetatileIdAt(x, y, METATILE_SecretBase_BreakableDoor_BottomOpen);
|
|
MapGridSetMetatileIdAt(x, y - 1, METATILE_SecretBase_BreakableDoor_TopOpen);
|
|
CurrentMapDrawMetatileAt(x, y);
|
|
CurrentMapDrawMetatileAt(x, y - 1);
|
|
}
|
|
|
|
static void Task_ShatterSecretBaseBreakableDoor(u8 taskId)
|
|
{
|
|
if (gTasks[taskId].data[0] == 7)
|
|
{
|
|
DoSecretBaseBreakableDoorEffect(gTasks[taskId].data[1], gTasks[taskId].data[2]);
|
|
DestroyTask(taskId);
|
|
}
|
|
else
|
|
{
|
|
gTasks[taskId].data[0]++;
|
|
}
|
|
}
|
|
|
|
void ShatterSecretBaseBreakableDoor(s16 x, s16 y)
|
|
{
|
|
u8 dir = GetPlayerFacingDirection();
|
|
|
|
if (dir == DIR_SOUTH)
|
|
{
|
|
DoSecretBaseBreakableDoorEffect(x, y);
|
|
}
|
|
else if (dir == DIR_NORTH)
|
|
{
|
|
u8 taskId = CreateTask(Task_ShatterSecretBaseBreakableDoor, 5);
|
|
gTasks[taskId].data[0] = 0;
|
|
gTasks[taskId].data[1] = x;
|
|
gTasks[taskId].data[2] = y;
|
|
}
|
|
}
|
|
|
|
#define tMetatileID data[0]
|
|
static void Task_SecretBaseMusicNoteMatSound(u8 taskId)
|
|
{
|
|
if (gTasks[taskId].data[1] == 7)
|
|
{
|
|
switch (gTasks[taskId].tMetatileID)
|
|
{
|
|
case METATILE_SecretBase_NoteMat_C_Low:
|
|
PlaySE(SE_NOTE_C);
|
|
break;
|
|
case METATILE_SecretBase_NoteMat_D:
|
|
PlaySE(SE_NOTE_D);
|
|
break;
|
|
case METATILE_SecretBase_NoteMat_E:
|
|
PlaySE(SE_NOTE_E);
|
|
break;
|
|
case METATILE_SecretBase_NoteMat_F:
|
|
PlaySE(SE_NOTE_F);
|
|
break;
|
|
case METATILE_SecretBase_NoteMat_G:
|
|
PlaySE(SE_NOTE_G);
|
|
break;
|
|
case METATILE_SecretBase_NoteMat_A:
|
|
PlaySE(SE_NOTE_A);
|
|
break;
|
|
case METATILE_SecretBase_NoteMat_B:
|
|
PlaySE(SE_NOTE_B);
|
|
break;
|
|
case METATILE_SecretBase_NoteMat_C_High:
|
|
PlaySE(SE_NOTE_C_HIGH);
|
|
break;
|
|
}
|
|
|
|
DestroyTask(taskId);
|
|
}
|
|
else
|
|
{
|
|
gTasks[taskId].data[1]++;
|
|
}
|
|
}
|
|
|
|
void PlaySecretBaseMusicNoteMatSound(s16 metatileId)
|
|
{
|
|
u8 taskId = CreateTask(Task_SecretBaseMusicNoteMatSound, 5);
|
|
|
|
gTasks[taskId].tMetatileID = metatileId;
|
|
gTasks[taskId].data[1] = 0;
|
|
}
|
|
#undef tMetatileID
|
|
|
|
static void SpriteCB_GlitterMatSparkle(struct Sprite *sprite)
|
|
{
|
|
sprite->data[0]++;
|
|
|
|
if (sprite->data[0] == 8)
|
|
PlaySE(SE_M_HEAL_BELL);
|
|
|
|
if (sprite->data[0] >= 32)
|
|
DestroySprite(sprite);
|
|
}
|
|
|
|
void DoSecretBaseGlitterMatSparkle(void)
|
|
{
|
|
s16 x = gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x;
|
|
s16 y = gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y;
|
|
u8 spriteId;
|
|
|
|
SetSpritePosToOffsetMapCoords(&x, &y, 8, 4);
|
|
|
|
spriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[FLDEFFOBJ_SPARKLE], x, y, 0);
|
|
if (spriteId != MAX_SPRITES)
|
|
{
|
|
gSprites[spriteId].coordOffsetEnabled = TRUE;
|
|
gSprites[spriteId].oam.priority = 1;
|
|
gSprites[spriteId].oam.paletteNum = 5;
|
|
gSprites[spriteId].callback = SpriteCB_GlitterMatSparkle;
|
|
gSprites[spriteId].data[0] = 0;
|
|
}
|
|
}
|
|
|
|
bool8 FldEff_SandPillar(void)
|
|
{
|
|
s16 x, y;
|
|
|
|
ScriptContext2_Enable();
|
|
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
|
|
|
|
gFieldEffectArguments[5] = x;
|
|
gFieldEffectArguments[6] = y;
|
|
|
|
switch (GetPlayerFacingDirection())
|
|
{
|
|
case DIR_SOUTH:
|
|
CreateSprite(&sSpriteTemplate_SandPillar,
|
|
gSprites[gPlayerAvatar.spriteId].oam.x + 8,
|
|
gSprites[gPlayerAvatar.spriteId].oam.y + 32,
|
|
0);
|
|
|
|
break;
|
|
|
|
case DIR_NORTH:
|
|
CreateSprite(&sSpriteTemplate_SandPillar,
|
|
gSprites[gPlayerAvatar.spriteId].oam.x + 8,
|
|
gSprites[gPlayerAvatar.spriteId].oam.y,
|
|
148);
|
|
|
|
break;
|
|
|
|
case DIR_WEST:
|
|
CreateSprite(&sSpriteTemplate_SandPillar,
|
|
gSprites[gPlayerAvatar.spriteId].oam.x - 8,
|
|
gSprites[gPlayerAvatar.spriteId].oam.y + 16,
|
|
148);
|
|
|
|
break;
|
|
|
|
case DIR_EAST:
|
|
CreateSprite(&sSpriteTemplate_SandPillar,
|
|
gSprites[gPlayerAvatar.spriteId].oam.x + 24,
|
|
gSprites[gPlayerAvatar.spriteId].oam.y + 16,
|
|
148);
|
|
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void SpriteCB_SandPillar_BreakTop(struct Sprite *sprite)
|
|
{
|
|
PlaySE(SE_M_ROCK_THROW);
|
|
|
|
if (MapGridGetMetatileIdAt(gFieldEffectArguments[5], gFieldEffectArguments[6] - 1) == METATILE_SecretBase_SandOrnament_TopWall)
|
|
MapGridSetMetatileIdAt(gFieldEffectArguments[5], gFieldEffectArguments[6] - 1, METATILE_SecretBase_Wall_TopMid | METATILE_COLLISION_MASK);
|
|
else
|
|
MapGridSetMetatileIdAt(gFieldEffectArguments[5], gFieldEffectArguments[6] - 1, METATILE_SecretBase_SandOrnament_BrokenTop);
|
|
|
|
MapGridSetMetatileIdAt(gFieldEffectArguments[5], gFieldEffectArguments[6], METATILE_SecretBase_Ground);
|
|
CurrentMapDrawMetatileAt(gFieldEffectArguments[5], gFieldEffectArguments[6] - 1);
|
|
CurrentMapDrawMetatileAt(gFieldEffectArguments[5], gFieldEffectArguments[6]);
|
|
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_SandPillar_BreakBase;
|
|
}
|
|
|
|
static void SpriteCB_SandPillar_BreakBase(struct Sprite *sprite)
|
|
{
|
|
if (sprite->data[0] < 18)
|
|
{
|
|
sprite->data[0]++;
|
|
}
|
|
else
|
|
{
|
|
MapGridSetMetatileIdAt(gFieldEffectArguments[5], gFieldEffectArguments[6], METATILE_SecretBase_SandOrnament_BrokenBase | METATILE_COLLISION_MASK);
|
|
CurrentMapDrawMetatileAt(gFieldEffectArguments[5], gFieldEffectArguments[6]);
|
|
sprite->data[0] = 0;
|
|
sprite->callback = SpriteCB_SandPillar_End;
|
|
}
|
|
}
|
|
|
|
static void SpriteCB_SandPillar_End(struct Sprite *sprite)
|
|
{
|
|
FieldEffectStop(sprite, FLDEFF_SAND_PILLAR);
|
|
EnableBothScriptContexts();
|
|
}
|
|
|
|
void InteractWithShieldOrTVDecoration(void)
|
|
{
|
|
s16 x, y;
|
|
s32 metatileId;
|
|
|
|
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
|
|
|
|
metatileId = MapGridGetMetatileIdAt(x, y);
|
|
|
|
switch (metatileId)
|
|
{
|
|
case METATILE_SecretBase_GoldShield_Base1:
|
|
ConvertIntToDecimalStringN(gStringVar1, 100, STR_CONV_MODE_LEFT_ALIGN, 3);
|
|
StringCopy(gStringVar2, gText_Gold);
|
|
|
|
gSpecialVar_Result = 0;
|
|
|
|
if (!VarGet(VAR_CURRENT_SECRET_BASE))
|
|
return;
|
|
|
|
VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_GOLD_SHIELD);
|
|
break;
|
|
case METATILE_SecretBase_SilverShield_Base1:
|
|
ConvertIntToDecimalStringN(gStringVar1, 50, STR_CONV_MODE_LEFT_ALIGN, 2);
|
|
StringCopy(gStringVar2, gText_Silver);
|
|
|
|
gSpecialVar_Result = 0;
|
|
|
|
if (!VarGet(VAR_CURRENT_SECRET_BASE))
|
|
return;
|
|
|
|
VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_SILVER_SHIELD);
|
|
break;
|
|
case METATILE_SecretBase_TV:
|
|
gSpecialVar_Result = 1;
|
|
|
|
if (!VarGet(VAR_CURRENT_SECRET_BASE))
|
|
return;
|
|
|
|
VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_TV);
|
|
break;
|
|
case METATILE_SecretBase_RoundTV:
|
|
gSpecialVar_Result = 2;
|
|
|
|
if (!VarGet(VAR_CURRENT_SECRET_BASE))
|
|
return;
|
|
|
|
VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_TV);
|
|
break;
|
|
case METATILE_SecretBase_CuteTV:
|
|
gSpecialVar_Result = 3;
|
|
|
|
if (!VarGet(VAR_CURRENT_SECRET_BASE))
|
|
return;
|
|
|
|
VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_TV);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// As opposed to a small one (single metatile) like the balloons
|
|
bool8 IsLargeBreakableDecoration(u16 metatileId, bool8 checkBase)
|
|
{
|
|
if (!CurMapIsSecretBase())
|
|
return FALSE;
|
|
|
|
if (!checkBase)
|
|
{
|
|
if (metatileId == METATILE_SecretBase_SandOrnament_Top || metatileId == METATILE_SecretBase_SandOrnament_TopWall)
|
|
return TRUE;
|
|
if (metatileId == METATILE_SecretBase_BreakableDoor_TopClosed)
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (metatileId == METATILE_SecretBase_SandOrnament_Base1)
|
|
return TRUE;
|
|
if (metatileId == METATILE_SecretBase_BreakableDoor_BottomClosed)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void Task_FieldPoisonEffect(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
switch (data[0])
|
|
{
|
|
case 0:
|
|
data[1] += 2;
|
|
if (data[1] > 8)
|
|
data[0]++;
|
|
break;
|
|
case 1:
|
|
data[1] -= 2;
|
|
if (data[1] == 0)
|
|
data[0]++;
|
|
break;
|
|
case 2:
|
|
DestroyTask(taskId);
|
|
return;
|
|
}
|
|
SetGpuReg(REG_OFFSET_MOSAIC, (data[1] << 4) | data[1]);
|
|
}
|
|
|
|
void FldEffPoison_Start(void)
|
|
{
|
|
PlaySE(SE_FIELD_POISON);
|
|
CreateTask(Task_FieldPoisonEffect, 80);
|
|
}
|
|
|
|
bool32 FldEffPoison_IsActive(void)
|
|
{
|
|
return FuncIsActiveTask(Task_FieldPoisonEffect);
|
|
}
|
|
|
|
static void Task_WateringBerryTreeAnim(u8 taskId)
|
|
{
|
|
gTasks[taskId].func = Task_WateringBerryTreeAnim_Start;
|
|
}
|
|
|
|
static void Task_WateringBerryTreeAnim_Start(u8 taskId)
|
|
{
|
|
struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
|
|
|
|
if (!ObjectEventIsMovementOverridden(playerObjEvent)
|
|
|| ObjectEventClearHeldMovementIfFinished(playerObjEvent))
|
|
{
|
|
// Start watering
|
|
SetPlayerAvatarWatering(GetPlayerFacingDirection());
|
|
ObjectEventSetHeldMovement(playerObjEvent, GetWalkInPlaceNormalMovementAction(GetPlayerFacingDirection()));
|
|
gTasks[taskId].func = Task_WateringBerryTreeAnim_Continue;
|
|
}
|
|
}
|
|
|
|
static void Task_WateringBerryTreeAnim_Continue(u8 taskId)
|
|
{
|
|
struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId];
|
|
|
|
if (ObjectEventClearHeldMovementIfFinished(playerObjEvent))
|
|
{
|
|
s16 value = gTasks[taskId].data[1]++;
|
|
|
|
// Continue holding watering action 10 times, then end
|
|
if (value < 10)
|
|
ObjectEventSetHeldMovement(playerObjEvent, GetWalkInPlaceNormalMovementAction(GetPlayerFacingDirection()));
|
|
else
|
|
gTasks[taskId].func = Task_WateringBerryTreeAnim_End;
|
|
}
|
|
}
|
|
|
|
static void Task_WateringBerryTreeAnim_End(u8 taskId)
|
|
{
|
|
SetPlayerAvatarTransitionFlags(GetPlayerAvatarFlags());
|
|
DestroyTask(taskId);
|
|
EnableBothScriptContexts();
|
|
}
|
|
|
|
void DoWateringBerryTreeAnim(void)
|
|
{
|
|
CreateTask(Task_WateringBerryTreeAnim, 80);
|
|
}
|
|
|
|
// The lights that blink on the counter when mixing records in the cable club
|
|
u8 CreateRecordMixingLights(void)
|
|
{
|
|
u8 spriteId;
|
|
|
|
LoadSpritePalette(&sSpritePalette_RecordMixLights);
|
|
|
|
spriteId = CreateSprite(&sSpriteTemplate_RecordMixLights, 0, 0, 82);
|
|
|
|
if (spriteId == MAX_SPRITES)
|
|
{
|
|
return MAX_SPRITES;
|
|
}
|
|
else
|
|
{
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
GetMapCoordsFromSpritePos(16, 13, &sprite->x, &sprite->y);
|
|
sprite->coordOffsetEnabled = TRUE;
|
|
sprite->x += 16;
|
|
sprite->y += 2;
|
|
}
|
|
return spriteId;
|
|
}
|
|
|
|
void DestroyRecordMixingLights(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_SPRITES; i++)
|
|
{
|
|
if (gSprites[i].template == &sSpriteTemplate_RecordMixLights)
|
|
{
|
|
FreeSpritePalette(&gSprites[i]);
|
|
DestroySprite(&gSprites[i]);
|
|
}
|
|
}
|
|
}
|