#include "global.h" #include "pokemon.h" #include "egg_hatch.h" #include "pokedex.h" #include "constants/items.h" #include "script.h" #include "decompress.h" #include "task.h" #include "palette.h" #include "main.h" #include "event_data.h" #include "sound.h" #include "constants/songs.h" #include "text.h" #include "text_window.h" #include "string_util.h" #include "menu.h" #include "trig.h" #include "random.h" #include "malloc.h" #include "dma3.h" #include "gpu_regs.h" #include "bg.h" #include "m4a.h" #include "window.h" #include "graphics.h" #include "constants/abilities.h" #include "daycare.h" #include "overworld.h" #include "scanline_effect.h" #include "field_weather.h" #include "international_string_util.h" #include "naming_screen.h" #include "pokemon_storage_system.h" #include "field_screen_effect.h" #include "data.h" #include "battle.h" // to get rid of later #include "constants/rgb.h" struct EggHatchData { u8 eggSpriteID; u8 pokeSpriteID; u8 CB2_state; u8 CB2_PalCounter; u8 eggPartyID; u8 unused_5; u8 unused_6; u8 eggShardVelocityID; u8 windowId; u8 unused_9; u8 unused_A; u16 species; u8 textColor[3]; }; extern const u32 gTradePlatform_Tilemap[]; extern const u8 gText_HatchedFromEgg[]; extern const u8 gText_NicknameHatchPrompt[]; static void Task_EggHatch(u8 taskID); static void CB2_EggHatch_0(void); static void CB2_EggHatch_1(void); static void SpriteCB_Egg_0(struct Sprite* sprite); static void SpriteCB_Egg_1(struct Sprite* sprite); static void SpriteCB_Egg_2(struct Sprite* sprite); static void SpriteCB_Egg_3(struct Sprite* sprite); static void SpriteCB_Egg_4(struct Sprite* sprite); static void SpriteCB_Egg_5(struct Sprite* sprite); static void SpriteCB_EggShard(struct Sprite* sprite); static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed); static void CreateRandomEggShardSprite(void); static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex); // IWRAM bss static struct EggHatchData *sEggHatchData; // rom data static const u16 sEggPalette[] = INCBIN_U16("graphics/pokemon/egg/normal.gbapal"); static const u8 sEggHatchTiles[] = INCBIN_U8("graphics/misc/egg_hatch.4bpp"); static const u8 sEggShardTiles[] = INCBIN_U8("graphics/misc/egg_shard.4bpp"); static const struct OamData sOamData_EggHatch = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(32x32), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(32x32), .tileNum = 0, .priority = 1, .paletteNum = 0, .affineParam = 0, }; static const union AnimCmd sSpriteAnim_EggHatch0[] = { ANIMCMD_FRAME(0, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_EggHatch1[] = { ANIMCMD_FRAME(16, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_EggHatch2[] = { ANIMCMD_FRAME(32, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_EggHatch3[] = { ANIMCMD_FRAME(48, 5), ANIMCMD_END }; static const union AnimCmd *const sSpriteAnimTable_EggHatch[] = { sSpriteAnim_EggHatch0, sSpriteAnim_EggHatch1, sSpriteAnim_EggHatch2, sSpriteAnim_EggHatch3, }; static const struct SpriteSheet sEggHatch_Sheet = { .data = sEggHatchTiles, .size = 2048, .tag = 12345, }; static const struct SpriteSheet sEggShards_Sheet = { .data = sEggShardTiles, .size = 128, .tag = 23456, }; static const struct SpritePalette sEgg_SpritePalette = { .data = sEggPalette, .tag = 54321 }; static const struct SpriteTemplate sSpriteTemplate_EggHatch = { .tileTag = 12345, .paletteTag = 54321, .oam = &sOamData_EggHatch, .anims = sSpriteAnimTable_EggHatch, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; static const struct OamData sOamData_EggShard = { .y = 0, .affineMode = ST_OAM_AFFINE_OFF, .objMode = ST_OAM_OBJ_NORMAL, .mosaic = 0, .bpp = ST_OAM_4BPP, .shape = SPRITE_SHAPE(8x8), .x = 0, .matrixNum = 0, .size = SPRITE_SIZE(8x8), .tileNum = 0, .priority = 2, .paletteNum = 0, .affineParam = 0, }; static const union AnimCmd sSpriteAnim_EggShard0[] = { ANIMCMD_FRAME(0, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_EggShard1[] = { ANIMCMD_FRAME(1, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_EggShard2[] = { ANIMCMD_FRAME(2, 5), ANIMCMD_END }; static const union AnimCmd sSpriteAnim_EggShard3[] = { ANIMCMD_FRAME(3, 5), ANIMCMD_END }; static const union AnimCmd *const sSpriteAnimTable_EggShard[] = { sSpriteAnim_EggShard0, sSpriteAnim_EggShard1, sSpriteAnim_EggShard2, sSpriteAnim_EggShard3, }; static const struct SpriteTemplate sSpriteTemplate_EggShard = { .tileTag = 23456, .paletteTag = 54321, .oam = &sOamData_EggShard, .anims = sSpriteAnimTable_EggShard, .images = NULL, .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCB_EggShard }; static const struct BgTemplate sBgTemplates_EggHatch[2] = { { .bg = 0, .charBaseIndex = 2, .mapBaseIndex = 24, .screenSize = 3, .paletteMode = 0, .priority = 0, .baseTile = 0 }, { .bg = 1, .charBaseIndex = 0, .mapBaseIndex = 8, .screenSize = 1, .paletteMode = 0, .priority = 2, .baseTile = 0 }, }; static const struct WindowTemplate sWinTemplates_EggHatch[2] = { { .bg = 0, .tilemapLeft = 2, .tilemapTop = 15, .width = 26, .height = 4, .paletteNum = 0, .baseBlock = 64 }, DUMMY_WIN_TEMPLATE }; static const struct WindowTemplate sYesNoWinTemplate = { .bg = 0, .tilemapLeft = 21, .tilemapTop = 9, .width = 5, .height = 4, .paletteNum = 15, .baseBlock = 424 }; static const s16 sEggShardVelocities[][2] = { {Q_8_8(-1.5), Q_8_8(-3.75)}, {Q_8_8(-5), Q_8_8(-3)}, {Q_8_8(3.5), Q_8_8(-3)}, {Q_8_8(-4), Q_8_8(-3.75)}, {Q_8_8(2), Q_8_8(-1.5)}, {Q_8_8(-0.5), Q_8_8(-6.75)}, {Q_8_8(5), Q_8_8(-2.25)}, {Q_8_8(-1.5), Q_8_8(-3.75)}, {Q_8_8(4.5), Q_8_8(-1.5)}, {Q_8_8(-1), Q_8_8(-6.75)}, {Q_8_8(4), Q_8_8(-2.25)}, {Q_8_8(-3.5), Q_8_8(-3.75)}, {Q_8_8(1), Q_8_8(-1.5)}, {Q_8_8(-3.515625), Q_8_8(-6.75)}, {Q_8_8(4.5), Q_8_8(-2.25)}, {Q_8_8(-0.5), Q_8_8(-7.5)}, {Q_8_8(1), Q_8_8(-4.5)}, {Q_8_8(-2.5), Q_8_8(-2.25)}, {Q_8_8(2.5), Q_8_8(-7.5)}, }; // code static void CreateHatchedMon(struct Pokemon *egg, struct Pokemon *temp) { u16 species; u32 personality, pokerus; u8 i, friendship, language, gameMet, markings, isEventLegal; u16 moves[MAX_MON_MOVES]; u32 ivs[NUM_STATS]; species = GetMonData(egg, MON_DATA_SPECIES); for (i = 0; i < MAX_MON_MOVES; i++) { moves[i] = GetMonData(egg, MON_DATA_MOVE1 + i); } personality = GetMonData(egg, MON_DATA_PERSONALITY); for (i = 0; i < NUM_STATS; i++) { ivs[i] = GetMonData(egg, MON_DATA_HP_IV + i); } language = GetMonData(egg, MON_DATA_LANGUAGE); gameMet = GetMonData(egg, MON_DATA_MET_GAME); markings = GetMonData(egg, MON_DATA_MARKINGS); pokerus = GetMonData(egg, MON_DATA_POKERUS); isEventLegal = GetMonData(egg, MON_DATA_EVENT_LEGAL); CreateMon(temp, species, EGG_HATCH_LEVEL, USE_RANDOM_IVS, TRUE, personality, OT_ID_PLAYER_ID, 0); for (i = 0; i < MAX_MON_MOVES; i++) { SetMonData(temp, MON_DATA_MOVE1 + i, &moves[i]); } for (i = 0; i < NUM_STATS; i++) { SetMonData(temp, MON_DATA_HP_IV + i, &ivs[i]); } language = GAME_LANGUAGE; SetMonData(temp, MON_DATA_LANGUAGE, &language); SetMonData(temp, MON_DATA_MET_GAME, &gameMet); SetMonData(temp, MON_DATA_MARKINGS, &markings); friendship = 120; SetMonData(temp, MON_DATA_FRIENDSHIP, &friendship); SetMonData(temp, MON_DATA_POKERUS, &pokerus); SetMonData(temp, MON_DATA_EVENT_LEGAL, &isEventLegal); *egg = *temp; } static void AddHatchedMonToParty(u8 id) { u8 isEgg = 0x46; // ? u16 pokeNum; u8 name[12]; u16 ball; u16 caughtLvl; u8 mapNameID; struct Pokemon* mon = &gPlayerParty[id]; CreateHatchedMon(mon, &gEnemyParty[0]); SetMonData(mon, MON_DATA_IS_EGG, &isEgg); pokeNum = GetMonData(mon, MON_DATA_SPECIES); GetSpeciesName(name, pokeNum); SetMonData(mon, MON_DATA_NICKNAME, name); pokeNum = SpeciesToNationalPokedexNum(pokeNum); GetSetPokedexFlag(pokeNum, FLAG_SET_SEEN); GetSetPokedexFlag(pokeNum, FLAG_SET_CAUGHT); GetMonNickname2(mon, gStringVar1); ball = ITEM_POKE_BALL; SetMonData(mon, MON_DATA_POKEBALL, &ball); caughtLvl = 0; SetMonData(mon, MON_DATA_MET_LEVEL, &caughtLvl); mapNameID = GetCurrentRegionMapSectionId(); SetMonData(mon, MON_DATA_MET_LOCATION, &mapNameID); MonRestorePP(mon); CalculateMonStats(mon); } void ScriptHatchMon(void) { AddHatchedMonToParty(gSpecialVar_0x8004); } static bool8 _CheckDaycareMonReceivedMail(struct DayCare *daycare, u8 daycareId) { u8 nickname[32]; struct DaycareMon *daycareMon = &daycare->mons[daycareId]; GetBoxMonNickname(&daycareMon->mon, nickname); if (daycareMon->mail.message.itemId != ITEM_NONE && (StringCompareWithoutExtCtrlCodes(nickname, daycareMon->mail.monName) != 0 || StringCompareWithoutExtCtrlCodes(gSaveBlock2Ptr->playerName, daycareMon->mail.otName) != 0)) { StringCopy(gStringVar1, nickname); TVShowConvertInternationalString(gStringVar2, daycareMon->mail.otName, daycareMon->mail.gameLanguage); TVShowConvertInternationalString(gStringVar3, daycareMon->mail.monName, daycareMon->mail.monLanguage); return TRUE; } return FALSE; } bool8 CheckDaycareMonReceivedMail(void) { return _CheckDaycareMonReceivedMail(&gSaveBlock1Ptr->daycare, gSpecialVar_0x8004); } static u8 EggHatchCreateMonSprite(u8 useAlt, u8 switchID, u8 pokeID, u16* speciesLoc) { u8 position = 0; u8 spriteID = 0; struct Pokemon* mon = NULL; if (useAlt == FALSE) { mon = &gPlayerParty[pokeID]; position = B_POSITION_OPPONENT_LEFT; } if (useAlt == TRUE) { // Alternate sprite allocation position. Never reached. mon = &gPlayerParty[pokeID]; position = B_POSITION_OPPONENT_RIGHT; } switch (switchID) { case 0: { u16 species = GetMonData(mon, MON_DATA_SPECIES); u32 pid = GetMonData(mon, MON_DATA_PERSONALITY); HandleLoadSpecialPokePic_DontHandleDeoxys(&gMonFrontPicTable[species], gMonSpritesGfxPtr->sprites.ptr[(useAlt * 2) + B_POSITION_OPPONENT_LEFT], species, pid); LoadCompressedSpritePalette(GetMonSpritePalStruct(mon)); *speciesLoc = species; } break; case 1: SetMultiuseSpriteTemplateToPokemon(GetMonSpritePalStruct(mon)->tag, position); spriteID = CreateSprite(&gMultiuseSpriteTemplate, 120, 75, 6); gSprites[spriteID].invisible = TRUE; gSprites[spriteID].callback = SpriteCallbackDummy; break; } return spriteID; } static void VBlankCB_EggHatch(void) { LoadOam(); ProcessSpriteCopyRequests(); TransferPlttBuffer(); } void EggHatch(void) { ScriptContext2_Enable(); CreateTask(Task_EggHatch, 10); FadeScreen(FADE_TO_BLACK, 0); } static void Task_EggHatch(u8 taskID) { if (!gPaletteFade.active) { CleanupOverworldWindowsAndTilemaps(); SetMainCallback2(CB2_EggHatch_0); gFieldCallback = FieldCB_ContinueScriptHandleMusic; DestroyTask(taskID); } } static void CB2_EggHatch_0(void) { switch (gMain.state) { case 0: SetGpuReg(REG_OFFSET_DISPCNT, 0); sEggHatchData = Alloc(sizeof(struct EggHatchData)); AllocateMonSpritesGfx(); sEggHatchData->eggPartyID = gSpecialVar_0x8004; sEggHatchData->eggShardVelocityID = 0; SetVBlankCallback(VBlankCB_EggHatch); gSpecialVar_0x8005 = GetCurrentMapMusic(); ResetTempTileDataBuffers(); ResetBgsAndClearDma3BusyFlags(0); InitBgsFromTemplates(0, sBgTemplates_EggHatch, ARRAY_COUNT(sBgTemplates_EggHatch)); ChangeBgX(1, 0, BG_COORD_SET); ChangeBgY(1, 0, BG_COORD_SET); ChangeBgX(0, 0, BG_COORD_SET); ChangeBgY(0, 0, BG_COORD_SET); SetBgAttribute(1, BG_ATTR_PRIORITY, 2); SetBgTilemapBuffer(1, Alloc(0x1000)); SetBgTilemapBuffer(0, Alloc(0x2000)); DeactivateAllTextPrinters(); ResetPaletteFade(); FreeAllSpritePalettes(); ResetSpriteData(); ResetTasks(); ScanlineEffect_Stop(); m4aSoundVSyncOn(); gMain.state++; break; case 1: InitWindows(sWinTemplates_EggHatch); sEggHatchData->windowId = 0; gMain.state++; break; case 2: DecompressAndLoadBgGfxUsingHeap(0, gBattleTextboxTiles, 0, 0, 0); CopyToBgTilemapBuffer(0, gBattleTextboxTilemap, 0, 0); LoadCompressedPalette(gBattleTextboxPalette, 0, 0x20); gMain.state++; break; case 3: LoadSpriteSheet(&sEggHatch_Sheet); LoadSpriteSheet(&sEggShards_Sheet); LoadSpritePalette(&sEgg_SpritePalette); gMain.state++; break; case 4: CopyBgTilemapBufferToVram(0); AddHatchedMonToParty(sEggHatchData->eggPartyID); gMain.state++; break; case 5: EggHatchCreateMonSprite(FALSE, 0, sEggHatchData->eggPartyID, &sEggHatchData->species); gMain.state++; break; case 6: sEggHatchData->pokeSpriteID = EggHatchCreateMonSprite(FALSE, 1, sEggHatchData->eggPartyID, &sEggHatchData->species); gMain.state++; break; case 7: SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP); LoadPalette(gTradeGba2_Pal, 0x10, 0xA0); LoadBgTiles(1, gTradeGba_Gfx, 0x1420, 0); CopyToBgTilemapBuffer(1, gTradePlatform_Tilemap, 0x1000, 0); CopyBgTilemapBufferToVram(1); gMain.state++; break; case 8: SetMainCallback2(CB2_EggHatch_1); sEggHatchData->CB2_state = 0; break; } RunTasks(); RunTextPrinters(); AnimateSprites(); BuildOamBuffer(); UpdatePaletteFade(); } static void EggHatchSetMonNickname(void) { SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar3); FreeMonSpritesGfx(); Free(sEggHatchData); SetMainCallback2(CB2_ReturnToField); } static void Task_EggHatchPlayBGM(u8 taskID) { if (gTasks[taskID].data[0] == 0) { StopMapMusic(); PlayRainStoppingSoundEffect(); } if (gTasks[taskID].data[0] == 1) PlayBGM(MUS_EVOLUTION_INTRO); if (gTasks[taskID].data[0] > 60) { PlayBGM(MUS_EVOLUTION); DestroyTask(taskID); // UB: task is destroyed, yet the value is incremented #ifdef UBFIX return; #endif } gTasks[taskID].data[0]++; } static void CB2_EggHatch_1(void) { u16 species; u8 gender; u32 personality; switch (sEggHatchData->CB2_state) { case 0: BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK); sEggHatchData->eggSpriteID = CreateSprite(&sSpriteTemplate_EggHatch, 120, 75, 5); ShowBg(0); ShowBg(1); sEggHatchData->CB2_state++; CreateTask(Task_EggHatchPlayBGM, 5); break; case 1: if (!gPaletteFade.active) { FillWindowPixelBuffer(sEggHatchData->windowId, PIXEL_FILL(0)); sEggHatchData->CB2_PalCounter = 0; sEggHatchData->CB2_state++; } break; case 2: if (++sEggHatchData->CB2_PalCounter > 30) { sEggHatchData->CB2_state++; gSprites[sEggHatchData->eggSpriteID].callback = SpriteCB_Egg_0; } break; case 3: if (gSprites[sEggHatchData->eggSpriteID].callback == SpriteCallbackDummy) { species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); DoMonFrontSpriteAnimation(&gSprites[sEggHatchData->pokeSpriteID], species, FALSE, 1); sEggHatchData->CB2_state++; } break; case 4: if (gSprites[sEggHatchData->pokeSpriteID].callback == SpriteCallbackDummy) { sEggHatchData->CB2_state++; } break; case 5: GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_HatchedFromEgg); EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 3, TEXT_SKIP_DRAW); PlayFanfare(MUS_EVOLVED); sEggHatchData->CB2_state++; PutWindowTilemap(sEggHatchData->windowId); CopyWindowToVram(sEggHatchData->windowId, COPYWIN_FULL); break; case 6: if (IsFanfareTaskInactive()) sEggHatchData->CB2_state++; break; case 7: if (IsFanfareTaskInactive()) sEggHatchData->CB2_state++; break; case 8: GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_NicknameHatchPrompt); EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 2, 1); sEggHatchData->CB2_state++; break; case 9: if (!IsTextPrinterActive(sEggHatchData->windowId)) { LoadUserWindowBorderGfx(sEggHatchData->windowId, 0x140, 0xE0); CreateYesNoMenu(&sYesNoWinTemplate, 0x140, 0xE, 0); sEggHatchData->CB2_state++; } break; case 10: switch (Menu_ProcessInputNoWrapClearOnChoose()) { case 0: GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyID], gStringVar3); species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); gender = GetMonGender(&gPlayerParty[sEggHatchData->eggPartyID]); personality = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_PERSONALITY, 0); DoNamingScreen(NAMING_SCREEN_NICKNAME, gStringVar3, species, gender, personality, EggHatchSetMonNickname); break; case 1: case -1: sEggHatchData->CB2_state++; } break; case 11: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); sEggHatchData->CB2_state++; break; case 12: if (!gPaletteFade.active) { FreeMonSpritesGfx(); RemoveWindow(sEggHatchData->windowId); UnsetBgTilemapBuffer(0); UnsetBgTilemapBuffer(1); Free(sEggHatchData); SetMainCallback2(CB2_ReturnToField); } break; } RunTasks(); RunTextPrinters(); AnimateSprites(); BuildOamBuffer(); UpdatePaletteFade(); } static void SpriteCB_Egg_0(struct Sprite* sprite) { if (++sprite->data[0] > 20) { sprite->callback = SpriteCB_Egg_1; sprite->data[0] = 0; } else { sprite->data[1] = (sprite->data[1] + 20) & 0xFF; sprite->x2 = Sin(sprite->data[1], 1); if (sprite->data[0] == 15) { PlaySE(SE_BALL); StartSpriteAnim(sprite, 1); CreateRandomEggShardSprite(); } } } static void SpriteCB_Egg_1(struct Sprite* sprite) { if (++sprite->data[2] > 30) { if (++sprite->data[0] > 20) { sprite->callback = SpriteCB_Egg_2; sprite->data[0] = 0; sprite->data[2] = 0; } else { sprite->data[1] = (sprite->data[1] + 20) & 0xFF; sprite->x2 = Sin(sprite->data[1], 2); if (sprite->data[0] == 15) { PlaySE(SE_BALL); StartSpriteAnim(sprite, 2); } } } } static void SpriteCB_Egg_2(struct Sprite* sprite) { if (++sprite->data[2] > 30) { if (++sprite->data[0] > 38) { u16 species; sprite->callback = SpriteCB_Egg_3; sprite->data[0] = 0; species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyID], MON_DATA_SPECIES); gSprites[sEggHatchData->pokeSpriteID].x2 = 0; gSprites[sEggHatchData->pokeSpriteID].y2 = 0; } else { sprite->data[1] = (sprite->data[1] + 20) & 0xFF; sprite->x2 = Sin(sprite->data[1], 2); if (sprite->data[0] == 15) { PlaySE(SE_BALL); StartSpriteAnim(sprite, 2); CreateRandomEggShardSprite(); CreateRandomEggShardSprite(); } if (sprite->data[0] == 30) PlaySE(SE_BALL); } } } static void SpriteCB_Egg_3(struct Sprite* sprite) { if (++sprite->data[0] > 50) { sprite->callback = SpriteCB_Egg_4; sprite->data[0] = 0; } } static void SpriteCB_Egg_4(struct Sprite* sprite) { s16 i; if (sprite->data[0] == 0) BeginNormalPaletteFade(PALETTES_ALL, -1, 0, 0x10, RGB_WHITEALPHA); if (sprite->data[0] < 4u) { for (i = 0; i <= 3; i++) CreateRandomEggShardSprite(); } sprite->data[0]++; if (!gPaletteFade.active) { PlaySE(SE_EGG_HATCH); sprite->invisible = TRUE; sprite->callback = SpriteCB_Egg_5; sprite->data[0] = 0; } } static void SpriteCB_Egg_5(struct Sprite* sprite) { if (sprite->data[0] == 0) { gSprites[sEggHatchData->pokeSpriteID].invisible = FALSE; StartSpriteAffineAnim(&gSprites[sEggHatchData->pokeSpriteID], BATTLER_AFFINE_EMERGE); } if (sprite->data[0] == 8) BeginNormalPaletteFade(PALETTES_ALL, -1, 0x10, 0, RGB_WHITEALPHA); if (sprite->data[0] <= 9) gSprites[sEggHatchData->pokeSpriteID].y -= 1; if (sprite->data[0] > 40) sprite->callback = SpriteCallbackDummy; sprite->data[0]++; } static void SpriteCB_EggShard(struct Sprite* sprite) { sprite->data[4] += sprite->data[1]; sprite->data[5] += sprite->data[2]; sprite->x2 = sprite->data[4] / 256; sprite->y2 = sprite->data[5] / 256; sprite->data[2] += sprite->data[3]; if (sprite->y + sprite->y2 > sprite->y + 20 && sprite->data[2] > 0) DestroySprite(sprite); } static void CreateRandomEggShardSprite(void) { u16 spriteAnimIndex; s16 velocity1 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][0]; s16 velocity2 = sEggShardVelocities[sEggHatchData->eggShardVelocityID][1]; sEggHatchData->eggShardVelocityID++; spriteAnimIndex = Random() % 4; CreateEggShardSprite(120, 60, velocity1, velocity2, 100, spriteAnimIndex); } static void CreateEggShardSprite(u8 x, u8 y, s16 data1, s16 data2, s16 data3, u8 spriteAnimIndex) { u8 spriteID = CreateSprite(&sSpriteTemplate_EggShard, x, y, 4); gSprites[spriteID].data[1] = data1; gSprites[spriteID].data[2] = data2; gSprites[spriteID].data[3] = data3; StartSpriteAnim(&gSprites[spriteID], spriteAnimIndex); } static void EggHatchPrintMessage(u8 windowId, u8* string, u8 x, u8 y, u8 speed) { FillWindowPixelBuffer(windowId, PIXEL_FILL(15)); sEggHatchData->textColor[0] = 0; sEggHatchData->textColor[1] = 5; sEggHatchData->textColor[2] = 6; AddTextPrinterParameterized4(windowId, FONT_NORMAL, x, y, 0, 0, sEggHatchData->textColor, speed, string); } u8 GetEggCyclesToSubtract(void) { u8 count, i; for (count = CalculatePlayerPartyCount(), i = 0; i < count; i++) { if (!GetMonData(&gPlayerParty[i], MON_DATA_SANITY_IS_EGG)) { u8 ability = GetMonAbility(&gPlayerParty[i]); if (ability == ABILITY_MAGMA_ARMOR || ability == ABILITY_FLAME_BODY) return 2; } } return 1; } u16 CountPartyAliveNonEggMons(void) { u16 aliveNonEggMonsCount = CountStorageNonEggMons(); aliveNonEggMonsCount += CountPartyAliveNonEggMonsExcept(PARTY_SIZE); return aliveNonEggMonsCount; }