diff --git a/graphics/pokedex/cry_screen_bg b/graphics/pokedex/cry_screen_bg new file mode 100644 index 000000000..e786232d9 Binary files /dev/null and b/graphics/pokedex/cry_screen_bg differ diff --git a/graphics/pokedex/85B8C10.png b/graphics/pokedex/cry_screen_bg.png similarity index 100% rename from graphics/pokedex/85B8C10.png rename to graphics/pokedex/cry_screen_bg.png diff --git a/include/pokedex_cry_screen.h b/include/pokedex_cry_screen.h index db995624c..4d2043292 100755 --- a/include/pokedex_cry_screen.h +++ b/include/pokedex_cry_screen.h @@ -1,7 +1,7 @@ #ifndef GUARD_POKEDEX_CRY_SCREEN_H #define GUARD_POKEDEX_CRY_SCREEN_H -struct CryRelatedStruct +struct CryScreenWindow { u16 unk0; // Assigned to val that's never read u8 unk2; // Never read @@ -12,10 +12,10 @@ struct CryRelatedStruct extern u8 gDexCryScreenState; -bool8 LoadCryWaveformWindow(struct CryRelatedStruct*, u8); +bool8 LoadCryWaveformWindow(struct CryScreenWindow*, u8); void UpdateCryWaveformWindow(u8); void CryScreenPlayButton(u16); -bool8 LoadCryMeter(struct CryRelatedStruct*, u8); +bool8 LoadCryMeter(struct CryScreenWindow*, u8); void FreeCryScreen(void); #endif diff --git a/src/pokedex.c b/src/pokedex.c index 7532f0c99..ba05969ae 100644 --- a/src/pokedex.c +++ b/src/pokedex.c @@ -3568,14 +3568,14 @@ static void Task_LoadCryScreen(u8 taskId) break; case 6: { - struct CryRelatedStruct sp4; + struct CryScreenWindow waveformWindow; - sp4.unk0 = 0x4020; - sp4.unk2 = 0x1F; - sp4.paletteNo = 8; - sp4.yPos = 0x1E; - sp4.xPos = 0xC; - if (LoadCryWaveformWindow(&sp4, 2)) + waveformWindow.unk0 = 0x4020; + waveformWindow.unk2 = 31; + waveformWindow.paletteNo = 8; + waveformWindow.yPos = 30; + waveformWindow.xPos = 12; + if (LoadCryWaveformWindow(&waveformWindow, 2)) { gMain.state++; gDexCryScreenState = 0; @@ -3584,12 +3584,12 @@ static void Task_LoadCryScreen(u8 taskId) break; case 7: { - struct CryRelatedStruct spC; + struct CryScreenWindow cryMeter; - spC.paletteNo = 9; - spC.xPos = 0x12; - spC.yPos = 3; - if (LoadCryMeter(&spC, 3)) + cryMeter.paletteNo = 9; + cryMeter.xPos = 18; + cryMeter.yPos = 3; + if (LoadCryMeter(&cryMeter, 3)) gMain.state++; CopyWindowToVram(WIN_VU_METER, 2); CopyWindowToVram(WIN_INFO, 3); diff --git a/src/pokedex_cry_screen.c b/src/pokedex_cry_screen.c index 02ce18d05..0a6f639ae 100644 --- a/src/pokedex_cry_screen.c +++ b/src/pokedex_cry_screen.c @@ -9,35 +9,53 @@ #include "trig.h" #include "window.h" -struct PokedexCryVolumeMeter { - s8 unk0; - s8 unk1; - u8 unk2; - u16 needleSpriteId; +// Cry meter needle positions +// +// 0 +// 32 . . -32 +// . . +// 64 . . -64 +// . . +// . . +// 96 . . -96 +// 127 +// +#define MIN_NEEDLE_POS 32 +#define MAX_NEEDLE_POS -32 + +#define NEEDLE_MOVE_INCREMENT 5 + +#define WAVEFORM_WINDOW_HEIGHT 56 + +struct PokedexCryMeterNeedle { + s8 rotation; + s8 targetRotation; + u8 moveIncrement; + u16 spriteId; }; struct PokedexCryScreen { - u8 unk0[16]; - u8 unk10; - u8 unk11; - u8 unk12; - u16 unk14; - u8 unk16; + u8 cryWaveformBuffer[16]; + u8 cryState; + u8 playhead; + u8 waveformPreviousY; + u16 unk; // Never read + u8 playStartPos; u16 species; - u8 unk1A; - u8 unk1B; + u8 cryOverrideCountdown; + u8 cryRepeatDelay; }; static void PlayCryScreenCry(u16); -static void sub_81455A8(void); +static void BufferCryWaveformSegment(void); static void DrawWaveformFlatline(void); -static void sub_8145648(u8); +static void AdvancePlayhead(u8); static void DrawWaveformSegment(u8, u8); -static void sub_8145814(u8); -static void sub_8145824(u8, s16, u8); +static void DrawWaveformWindow(u8); +static void ShiftWaveformOver(u8, s16, bool8); static void SpriteCB_CryMeterNeedle(struct Sprite *); -static void sub_8145B24(s8); +static void SetCryMeterNeedleTarget(s8); // IWRAM common u8 gDexCryScreenState; @@ -45,7 +63,7 @@ u8 gDexCryScreenState; // EWRAM vars static EWRAM_DATA struct PokedexCryScreen *sDexCryScreen = NULL; static EWRAM_DATA u8 *sCryWaveformWindowTiledata = NULL; -static EWRAM_DATA struct PokedexCryVolumeMeter *sCryVolumeMeter = NULL; +static EWRAM_DATA struct PokedexCryMeterNeedle *sCryMeterNeedle = NULL; static const u16 sCryMeterNeedle_Pal[] = INCBIN_U16("graphics/pokedex/cry_meter_needle.gbapal"); static const u8 sCryMeterNeedle_Gfx[] = INCBIN_U8("graphics/pokedex/cry_meter_needle.4bpp"); @@ -54,7 +72,7 @@ static const u16 sCryMeter_Tilemap[] = INCBIN_U16("graphics/pokedex/cry_meter_ma static const u16 sCryMeter_Pal[] = INCBIN_U16("graphics/pokedex/cry_meter.gbapal"); static const u8 sCryMeter_Gfx[] = INCBIN_U8("graphics/pokedex/cry_meter.4bpp.lz"); -const u16 gUnknown_085B8770[][72] = +static const u16 sWaveformOffsets[][72] = { { 0x0000, 0x0004, 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, @@ -139,18 +157,21 @@ const u16 gUnknown_085B8770[][72] = } }; -static const u16 sCryScreenBg_Pal[] = INCBIN_U16("graphics/pokedex/85B8C10.gbapal"); -static const u8 sCryScreenBg_Gfx[] = INCBIN_U8("graphics/pokedex/85B8C10.4bpp"); +static const u16 sCryScreenBg_Pal[] = INCBIN_U16("graphics/pokedex/cry_screen_bg.gbapal"); +static const u8 sCryScreenBg_Gfx[] = INCBIN_U8("graphics/pokedex/cry_screen_bg.4bpp"); -const u8 gUnknown_085B8C30[] = {0xF0, 0x0F}; -const u8 gUnknown_085B8C32[][16] = +static const u8 sWaveformTileDataNybbleMasks[] = {0xF0, 0x0F}; + +// Waveform is blue in the middle (8) grading to white at peaks (15) +// Split into two arrays for the two vertical slice halves +static const u8 sWaveformColor[][16] = { { - 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + 15, 14, 13, 12, 11, 10, 9, 8, + 8, 9, 10, 11, 12, 13, 14, 15, }, { - 0xF0, 0xE0, 0xD0, 0xC0, 0xB0, 0xA0, 0x90, 0x80, - 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0 + 15 << 4, 14 << 4, 13 << 4, 12 << 4, 11 << 4, 10 << 4, 9 << 4, 8 << 4, + 8 << 4, 9 << 4, 10 << 4, 11 << 4, 12 << 4, 13 << 4, 14 << 4, 15 << 4, } }; @@ -202,7 +223,7 @@ static const struct SpritePalette sCryMeterNeedleSpritePalettes[] = {} }; -bool8 LoadCryWaveformWindow(struct CryRelatedStruct *arg0, u8 windowId) +bool8 LoadCryWaveformWindow(struct CryScreenWindow *window, u8 windowId) { u8 i; u8 finished = FALSE; @@ -216,28 +237,28 @@ bool8 LoadCryWaveformWindow(struct CryRelatedStruct *arg0, u8 windowId) sCryWaveformWindowTiledata = (u8*)GetWindowAttribute(windowId, WINDOW_TILE_DATA); } - sDexCryScreen->unk14 = arg0->unk0; - sDexCryScreen->unk16 = arg0->yPos; - sDexCryScreen->unk1A = 0; - sDexCryScreen->unk1B = 0; - sDexCryScreen->unk10 = 0; - sDexCryScreen->unk12 = 28; - sDexCryScreen->unk11 = 0; - sub_8145824(windowId, -8 * arg0->xPos, 1); + sDexCryScreen->unk = window->unk0; + sDexCryScreen->playStartPos = window->yPos; + sDexCryScreen->cryOverrideCountdown = 0; + sDexCryScreen->cryRepeatDelay = 0; + sDexCryScreen->cryState = 0; + sDexCryScreen->waveformPreviousY = WAVEFORM_WINDOW_HEIGHT / 2; + sDexCryScreen->playhead = 0; + ShiftWaveformOver(windowId, -8 * window->xPos, TRUE); // Does nothing for (i = 0; i < 224; i++) CopyToWindowPixelBuffer(windowId, sCryScreenBg_Gfx, TILE_SIZE_4BPP, i); gDexCryScreenState++; break; case 1: - for (i = 0; i < sDexCryScreen->unk16 * 8; i++) + for (i = 0; i < sDexCryScreen->playStartPos * 8; i++) DrawWaveformSegment(i, 0); gDexCryScreenState++; break; case 2: - sub_8145814(windowId); - LoadPalette(sCryScreenBg_Pal, arg0->paletteNo * 16, 32); + DrawWaveformWindow(windowId); + LoadPalette(sCryScreenBg_Pal, window->paletteNo * 16, 32); finished = TRUE; break; } @@ -247,17 +268,20 @@ bool8 LoadCryWaveformWindow(struct CryRelatedStruct *arg0, u8 windowId) void UpdateCryWaveformWindow(u8 windowId) { - u8 var0; + u8 waveformIdx; - sub_8145814(windowId); - sub_8145648(windowId); - if (sDexCryScreen->unk1B) - sDexCryScreen->unk1B--; + DrawWaveformWindow(windowId); + AdvancePlayhead(windowId); - if (sDexCryScreen->unk1A) + // Cry cant be replayed until this counter is done + if (sDexCryScreen->cryRepeatDelay) + sDexCryScreen->cryRepeatDelay--; + + // Once a cry replay has started, it waits for this countdown before playing + if (sDexCryScreen->cryOverrideCountdown) { - sDexCryScreen->unk1A--; - if (!sDexCryScreen->unk1A) + sDexCryScreen->cryOverrideCountdown--; + if (!sDexCryScreen->cryOverrideCountdown) { PlayCryScreenCry(sDexCryScreen->species); DrawWaveformFlatline(); @@ -265,47 +289,51 @@ void UpdateCryWaveformWindow(u8 windowId) } } - if (sDexCryScreen->unk10 == 0) + // No cry playing + if (sDexCryScreen->cryState == 0) { DrawWaveformFlatline(); return; } - if (sDexCryScreen->unk10 == 1) + // Cry playing, buffer waveform + if (sDexCryScreen->cryState == 1) { - sub_81455A8(); + BufferCryWaveformSegment(); } - else if (sDexCryScreen->unk10 > 8) + else if (sDexCryScreen->cryState > 8) { + // Buffered waveform exhausted, end or buffer more if (!IsCryPlaying()) { DrawWaveformFlatline(); - sDexCryScreen->unk10 = 0; + sDexCryScreen->cryState = 0; return; } - sub_81455A8(); - sDexCryScreen->unk10 = 1; + BufferCryWaveformSegment(); + sDexCryScreen->cryState = 1; } - var0 = 2 * (sDexCryScreen->unk10 - 1); - DrawWaveformSegment(sDexCryScreen->unk16 * 8 + sDexCryScreen->unk11 - 2, sDexCryScreen->unk0[var0]); - DrawWaveformSegment(sDexCryScreen->unk16 * 8 + sDexCryScreen->unk11 - 1, sDexCryScreen->unk0[var0 + 1]); - sDexCryScreen->unk10++; + // Draw cry + waveformIdx = 2 * (sDexCryScreen->cryState - 1); + DrawWaveformSegment(sDexCryScreen->playStartPos * 8 + sDexCryScreen->playhead - 2, sDexCryScreen->cryWaveformBuffer[waveformIdx]); + DrawWaveformSegment(sDexCryScreen->playStartPos * 8 + sDexCryScreen->playhead - 1, sDexCryScreen->cryWaveformBuffer[waveformIdx + 1]); + sDexCryScreen->cryState++; } void CryScreenPlayButton(u16 species) { - if (gMPlayInfo_BGM.status & MUSICPLAYER_STATUS_PAUSE && !sDexCryScreen->unk1A) + if (gMPlayInfo_BGM.status & MUSICPLAYER_STATUS_PAUSE && !sDexCryScreen->cryOverrideCountdown) { - if (!sDexCryScreen->unk1B) + if (!sDexCryScreen->cryRepeatDelay) { - sDexCryScreen->unk1B = 4; + sDexCryScreen->cryRepeatDelay = 4; if (IsCryPlaying() == TRUE) { StopCry(); sDexCryScreen->species = species; - sDexCryScreen->unk1A = 2; + sDexCryScreen->cryOverrideCountdown = 2; } else { @@ -317,11 +345,11 @@ void CryScreenPlayButton(u16 species) static void PlayCryScreenCry(u16 species) { - PlayCry2(species, 0, 0x7d, 10); - sDexCryScreen->unk10 = 1; + PlayCry2(species, 0, 125, 10); + sDexCryScreen->cryState = 1; } -static void sub_81455A8(void) +static void BufferCryWaveformSegment(void) { u8 i; s8 *baseBuffer; @@ -333,102 +361,113 @@ static void sub_81455A8(void) baseBuffer = gSoundInfo.pcmBuffer + (gSoundInfo.pcmDmaPeriod + 1 - gPcmDmaCounter) * gSoundInfo.pcmSamplesPerVBlank; buffer = baseBuffer + 0x630; - for (i = 0; i < ARRAY_COUNT(sDexCryScreen->unk0); i++) - sDexCryScreen->unk0[i] = buffer[i * 2] * 2; + for (i = 0; i < ARRAY_COUNT(sDexCryScreen->cryWaveformBuffer); i++) + sDexCryScreen->cryWaveformBuffer[i] = buffer[i * 2] * 2; } static void DrawWaveformFlatline(void) { - DrawWaveformSegment(sDexCryScreen->unk16 * 8 + sDexCryScreen->unk11 - 2, 0); - DrawWaveformSegment(sDexCryScreen->unk16 * 8 + sDexCryScreen->unk11 - 1, 0); + DrawWaveformSegment(sDexCryScreen->playStartPos * 8 + sDexCryScreen->playhead - 2, 0); + DrawWaveformSegment(sDexCryScreen->playStartPos * 8 + sDexCryScreen->playhead - 1, 0); } -static void sub_8145648(u8 windowId) +static void AdvancePlayhead(u8 windowId) { u8 i; u16 offset; - sub_8145824(windowId, sDexCryScreen->unk11, 0); - sDexCryScreen->unk11 += 2; - offset = (sDexCryScreen->unk11 / 8 + sDexCryScreen->unk16 + 1) % 32; + ShiftWaveformOver(windowId, sDexCryScreen->playhead, FALSE); + sDexCryScreen->playhead += 2; + offset = (sDexCryScreen->playhead / 8 + sDexCryScreen->playStartPos + 1) % 32; for (i = 0; i < 7; i++) CopyToWindowPixelBuffer(windowId, sCryScreenBg_Gfx, TILE_SIZE_4BPP, offset + (i * TILE_SIZE_4BPP)); } -static void DrawWaveformSegment(u8 a0, u8 a1) +// Waveform segments are drawn in alternate vertical slices +// Note that the waveform isnt put on screen until DrawWaveformWindow +static void DrawWaveformSegment(u8 position, u8 amplitude) { - u8 sp0; - u8 r6; - u8 r8; - u16 offset; - u16 r1; - u8 i; + // Position is a bitfield containing the play start pos, the playhead pos, and which vertical slice half to draw + #define PLAY_START_POS (position >> 3) + #define PLAYHEAD_POS (position & ((1 << 3) - 1)) + #define VERT_SLICE (position & 1) - r1 = (a1 + 127) * 256; - i = r1 / 1152.0; - if (i > 55) - i = 55; - sp0 = i; - r6 = a0 & 1; - if (i > sDexCryScreen->unk12) + u8 currentPointY; + u8 nybble; + u16 offset; + u16 temp; + u8 y; + + temp = (amplitude + 127) * 256; + y = temp / 1152.0; + if (y > WAVEFORM_WINDOW_HEIGHT - 1) + y = WAVEFORM_WINDOW_HEIGHT - 1; + currentPointY = y; + nybble = VERT_SLICE; + if (y > sDexCryScreen->waveformPreviousY) { + // Current point lower than previous point, draw point and draw line up to previous do { - offset = gUnknown_085B8770[a0 & 0x7][i] + (a0 / 8) * TILE_SIZE_4BPP; - sCryWaveformWindowTiledata[offset] &= gUnknown_085B8C30[r6]; - sCryWaveformWindowTiledata[offset] |= gUnknown_085B8C32[r6][((i / 3) - 1) & 0x0F]; - i--; - } while (i > sDexCryScreen->unk12); + offset = sWaveformOffsets[PLAYHEAD_POS][y] + PLAY_START_POS * TILE_SIZE_4BPP; + sCryWaveformWindowTiledata[offset] &= sWaveformTileDataNybbleMasks[nybble]; + sCryWaveformWindowTiledata[offset] |= sWaveformColor[nybble][((y / 3) - 1) & 0x0F]; + y--; + } while (y > sDexCryScreen->waveformPreviousY); } else { + // Current point higher than previous point, draw point and draw line down to previous do { - offset = gUnknown_085B8770[a0 & 0x7][i] + (a0 / 8) * TILE_SIZE_4BPP; - sCryWaveformWindowTiledata[offset] &= gUnknown_085B8C30[r6]; - sCryWaveformWindowTiledata[offset] |= gUnknown_085B8C32[r6][((i / 3) - 1) & 0x0F]; - i++; - } while (i < sDexCryScreen->unk12); + offset = sWaveformOffsets[PLAYHEAD_POS][y] + PLAY_START_POS * TILE_SIZE_4BPP; + sCryWaveformWindowTiledata[offset] &= sWaveformTileDataNybbleMasks[nybble]; + sCryWaveformWindowTiledata[offset] |= sWaveformColor[nybble][((y / 3) - 1) & 0x0F]; + y++; + } while (y < sDexCryScreen->waveformPreviousY); } - sDexCryScreen->unk12 = sp0; + sDexCryScreen->waveformPreviousY = currentPointY; } -static void sub_8145814(u8 windowId) +static void DrawWaveformWindow(u8 windowId) { CopyWindowToVram(windowId, 2); } -static void sub_8145824(u8 windowId, s16 arg1, u8 arg2) +// rsVertical is leftover from a very different version of this function in RS +// In RS, when TRUE it would use VOFS and when FALSE it would use HOFS (only FALSE was used) +// Here when TRUE it does nothing +static void ShiftWaveformOver(u8 windowId, s16 offset, bool8 rsVertical) { - if (!arg2) + if (!rsVertical) { u8 bg = GetWindowAttribute(windowId, WINDOW_BG); - ChangeBgX(bg, arg1 << 8, 0); + ChangeBgX(bg, offset << 8, 0); } } -bool8 LoadCryMeter(struct CryRelatedStruct *arg0, u8 windowId) +bool8 LoadCryMeter(struct CryScreenWindow *window, u8 windowId) { bool8 finished = FALSE; switch (gDexCryScreenState) { case 0: - if (!sCryVolumeMeter) - sCryVolumeMeter = AllocZeroed(sizeof(*sCryVolumeMeter)); + if (!sCryMeterNeedle) + sCryMeterNeedle = AllocZeroed(sizeof(*sCryMeterNeedle)); CopyToWindowPixelBuffer(windowId, sCryMeter_Gfx, 0, 0); - LoadPalette(sCryMeter_Pal, arg0->paletteNo * 16, 32); + LoadPalette(sCryMeter_Pal, window->paletteNo * 16, 32); gDexCryScreenState++; break; case 1: LoadSpriteSheets(sCryMeterNeedleSpriteSheets); LoadSpritePalettes(sCryMeterNeedleSpritePalettes); - sCryVolumeMeter->needleSpriteId = CreateSprite(&sCryMeterNeedleSpriteTemplate, 40 + arg0->xPos * 8, 56 + arg0->yPos * 8, 1); - sCryVolumeMeter->unk0 = 32; - sCryVolumeMeter->unk1 = 32; - sCryVolumeMeter->unk2 = 0; + sCryMeterNeedle->spriteId = CreateSprite(&sCryMeterNeedleSpriteTemplate, 40 + window->xPos * 8, 56 + window->yPos * 8, 1); + sCryMeterNeedle->rotation = MIN_NEEDLE_POS; + sCryMeterNeedle->targetRotation = MIN_NEEDLE_POS; + sCryMeterNeedle->moveIncrement = 0; finished = TRUE; break; } @@ -438,92 +477,102 @@ bool8 LoadCryMeter(struct CryRelatedStruct *arg0, u8 windowId) void FreeCryScreen(void) { - FreeSpritePaletteByTag(GetSpritePaletteTagByPaletteNum(gSprites[sCryVolumeMeter->needleSpriteId].oam.paletteNum)); - DestroySprite(gSprites + sCryVolumeMeter->needleSpriteId); + FreeSpritePaletteByTag(GetSpritePaletteTagByPaletteNum(gSprites[sCryMeterNeedle->spriteId].oam.paletteNum)); + DestroySprite(gSprites + sCryMeterNeedle->spriteId); FREE_AND_SET_NULL(sDexCryScreen); - FREE_AND_SET_NULL(sCryVolumeMeter); + FREE_AND_SET_NULL(sCryMeterNeedle); } static void SpriteCB_CryMeterNeedle(struct Sprite *sprite) { u16 i; - s8 r3; + s8 peakAmplitude; s16 x; s16 y; struct ObjAffineSrcData affine; struct OamMatrix matrix; - u8 *var0; + u8 amplitude; - gSprites[sCryVolumeMeter->needleSpriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; - gSprites[sCryVolumeMeter->needleSpriteId].oam.affineParam = 0; - switch (sDexCryScreen->unk10) + gSprites[sCryMeterNeedle->spriteId].oam.affineMode = ST_OAM_AFFINE_NORMAL; + gSprites[sCryMeterNeedle->spriteId].oam.affineParam = 0; + + // While no cry is playing, cryState is 0 + // While cry is playing, cryState loops 1-8 + switch (sDexCryScreen->cryState) { case 0: - sCryVolumeMeter->unk1 = 32; - if (sCryVolumeMeter->unk0 > 0) + sCryMeterNeedle->targetRotation = MIN_NEEDLE_POS; + if (sCryMeterNeedle->rotation > 0) { - if (sCryVolumeMeter->unk2 != 1) - sCryVolumeMeter->unk2--; + if (sCryMeterNeedle->moveIncrement != 1) + sCryMeterNeedle->moveIncrement--; } else - sCryVolumeMeter->unk2 = 5; + { + sCryMeterNeedle->moveIncrement = NEEDLE_MOVE_INCREMENT; + } break; case 2: - r3 = 0; - for (i = 0; i < ARRAY_COUNT(sDexCryScreen->unk0); i++) + peakAmplitude = 0; + for (i = 0; i < ARRAY_COUNT(sDexCryScreen->cryWaveformBuffer); i++) { - if (r3 < sDexCryScreen->unk0[i]) - r3 = sDexCryScreen->unk0[i]; + if (peakAmplitude < sDexCryScreen->cryWaveformBuffer[i]) + peakAmplitude = sDexCryScreen->cryWaveformBuffer[i]; } - sub_8145B24(r3 * 0xd0 / 0x100); + SetCryMeterNeedleTarget(peakAmplitude * 208 / 256); break; case 6: - var0 = &sDexCryScreen->unk0[10]; - sub_8145B24(*var0 * 0xd0 / 0x100); + // To introduce some randomness, needle jumps to set pos in waveform rather than peak + amplitude = sDexCryScreen->cryWaveformBuffer[10]; + SetCryMeterNeedleTarget(amplitude * 208 / 256); break; } - if (sCryVolumeMeter->unk0 == sCryVolumeMeter->unk1) + if (sCryMeterNeedle->rotation == sCryMeterNeedle->targetRotation) { - // empty block + // Empty, needle has reached target } - else if (sCryVolumeMeter->unk0 < sCryVolumeMeter->unk1) + else if (sCryMeterNeedle->rotation < sCryMeterNeedle->targetRotation) { - sCryVolumeMeter->unk0 += sCryVolumeMeter->unk2; - if (sCryVolumeMeter->unk0 > sCryVolumeMeter->unk1) + // Rotate needle left + sCryMeterNeedle->rotation += sCryMeterNeedle->moveIncrement; + if (sCryMeterNeedle->rotation > sCryMeterNeedle->targetRotation) { - sCryVolumeMeter->unk0 = sCryVolumeMeter->unk1; - sCryVolumeMeter->unk1 = 0; + sCryMeterNeedle->rotation = sCryMeterNeedle->targetRotation; + sCryMeterNeedle->targetRotation = 0; } } else { - sCryVolumeMeter->unk0 -= sCryVolumeMeter->unk2; - if (sCryVolumeMeter->unk0 < sCryVolumeMeter->unk1) + // Rotate needle right + sCryMeterNeedle->rotation -= sCryMeterNeedle->moveIncrement; + if (sCryMeterNeedle->rotation < sCryMeterNeedle->targetRotation) { - sCryVolumeMeter->unk0 = sCryVolumeMeter->unk1; - sCryVolumeMeter->unk1 = 0; + sCryMeterNeedle->rotation = sCryMeterNeedle->targetRotation; + sCryMeterNeedle->targetRotation = 0; } } - affine.xScale = 0x100; - affine.yScale = 0x100; - affine.rotation = sCryVolumeMeter->unk0 * 256; + affine.xScale = 256; + affine.yScale = 256; + affine.rotation = sCryMeterNeedle->rotation * 256; ObjAffineSet(&affine, &matrix, 1, 2); SetOamMatrix(0, matrix.a, matrix.b, matrix.c, matrix.d); - x = gSineTable[((sCryVolumeMeter->unk0 + 0x7F) & 0xFF)]; - y = gSineTable[((sCryVolumeMeter->unk0 + 0x7F) & 0xFF) + 64]; + x = gSineTable[((sCryMeterNeedle->rotation + 0x7F) & 0xFF)]; + y = gSineTable[((sCryMeterNeedle->rotation + 0x7F) & 0xFF) + 64]; sprite->pos2.x = x * 24 / 256; sprite->pos2.y = y * 24 / 256; } -static void sub_8145B24(s8 a0) +static void SetCryMeterNeedleTarget(s8 offset) { - u16 r2 = (0x20 - a0) & 0xff; - if (r2 > 0x20 && r2 < 0xe0) - r2 = 0xe0; + u16 rotation = (MIN_NEEDLE_POS - offset) & 0xFF; - sCryVolumeMeter->unk1 = r2; - sCryVolumeMeter->unk2 = 5; + // Min is positive, max is negative. Make sure needle hasnt moved out of bounds + if (rotation > MIN_NEEDLE_POS && rotation < (u8)MAX_NEEDLE_POS) + rotation = (u8)MAX_NEEDLE_POS; + + sCryMeterNeedle->targetRotation = rotation; + sCryMeterNeedle->moveIncrement = NEEDLE_MOVE_INCREMENT; }