diff --git a/src/d_main.c b/src/d_main.c index 0a13c6d0b0108bc83acbfc1501e40c92305eaaa4..995704e762e619337c518c7f5a76e95a7c6f5f66 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1286,6 +1286,7 @@ void D_SRB2Main(void) I_StartupSound(); I_InitMusic(); S_InitSfxChannels(cv_soundvolume.value); + S_InitMusicDefs(); } CONS_Printf("ST_Init(): Init status bar.\n"); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 62c505ee0b726569f63ae6e3a0ec10a8c6b69aa8..7da0aa605ecb4f2100364d0fdcda18da6a0ff744 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3848,13 +3848,14 @@ static void Gravity_OnChange(void) static void SoundTest_OnChange(void) { + INT32 sfxfreeint = (INT32)sfxfree; if (cv_soundtest.value < 0) { - CV_SetValue(&cv_soundtest, NUMSFX-1); + CV_SetValue(&cv_soundtest, sfxfreeint-1); return; } - if (cv_soundtest.value >= NUMSFX) + if (cv_soundtest.value >= sfxfreeint) { CV_SetValue(&cv_soundtest, 0); return; diff --git a/src/dehacked.c b/src/dehacked.c index bf8bf62b524cd73167d858e89408c8285e9fc134..1ac04dc563582a54dbbaa460984e5af2708d4c5c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8656,6 +8656,8 @@ static const char *const MENUTYPES_LIST[] = { "SR_LEVELSELECT", "SR_UNLOCKCHECKLIST", "SR_EMBLEMHINT", + "SR_PLAYER", + "SR_SOUNDTEST", // Addons (Part of MISC, but let's make it our own) "AD_MAIN", diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 3b0620cc134c96c480aade16dce049e4d443e71c..e493dafacbb74406517bc3a4425de717ed11db6e 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -137,7 +137,7 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, const UINT8 *colormap) +void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) { FOutVector v[4]; FBITFIELD flags; @@ -182,6 +182,8 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, dupx = dupy = (dupx < dupy ? dupx : dupy); fscalew = fscaleh = FIXED_TO_FLOAT(pscale); + if (vscale != pscale) + fscaleh = FIXED_TO_FLOAT(vscale); // See my comments in v_video.c's V_DrawFixedPatch // -- Monster Iestyn 29/10/18 diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 3a0a58427fbb1d2d8bed6173cb04430b32c45541..fa230289fa9363bff35db7763f28cea63847fa90 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -42,7 +42,7 @@ void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum) void HWR_InitTextureMapping(void); void HWR_SetViewSize(void); void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); -void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, const UINT8 *colormap); +void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_CreatePlanePolygons(INT32 bspnum); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 865b61e8fcb6cd1206beb4b8d4485dea99cf59c4..62be6128300eac40493c55cfebbefe78cf40d731 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -551,6 +551,33 @@ static int libd_drawScaled(lua_State *L) return 0; } +static int libd_drawStretched(lua_State *L) +{ + fixed_t x, y, hscale, vscale; + INT32 flags; + patch_t *patch; + const UINT8 *colormap = NULL; + + HUDONLY + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + hscale = luaL_checkinteger(L, 3); + if (hscale < 0) + return luaL_error(L, "negative horizontal scale"); + vscale = luaL_checkinteger(L, 4); + if (vscale < 0) + return luaL_error(L, "negative vertical scale"); + patch = *((patch_t **)luaL_checkudata(L, 5, META_PATCH)); + flags = luaL_optinteger(L, 6, 0); + if (!lua_isnoneornil(L, 7)) + colormap = *((UINT8 **)luaL_checkudata(L, 7, META_COLORMAP)); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + + V_DrawStretchyFixedPatch(x, y, hscale, vscale, flags, patch, colormap); + return 0; +} + static int libd_drawNum(lua_State *L) { INT32 x, y, flags, num; @@ -902,6 +929,7 @@ static luaL_Reg lib_draw[] = { // drawing {"draw", libd_draw}, {"drawScaled", libd_drawScaled}, + {"drawStretched", libd_drawStretched}, {"drawNum", libd_drawNum}, {"drawPaddedNum", libd_drawPaddedNum}, {"drawFill", libd_drawFill}, diff --git a/src/m_menu.c b/src/m_menu.c index f3528d8e5cb33874a58203e0f832020c7696514f..6c066fe30ba72a0938b8cda873709e3f724122c3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -228,6 +228,7 @@ static void M_GetAllEmeralds(INT32 choice); static void M_DestroyRobots(INT32 choice); static void M_LevelSelectWarp(INT32 choice); static void M_Credits(INT32 choice); +static void M_SoundTest(INT32 choice); static void M_PandorasBox(INT32 choice); static void M_EmblemHints(INT32 choice); static void M_HandleChecklist(INT32 choice); @@ -336,8 +337,8 @@ static void M_DrawGenericMenu(void); static void M_DrawGenericScrollMenu(void); static void M_DrawCenteredMenu(void); static void M_DrawAddons(void); -static void M_DrawSkyRoom(void); static void M_DrawChecklist(void); +static void M_DrawSoundTest(void); static void M_DrawEmblemHints(void); static void M_DrawPauseMenu(void); static void M_DrawServerMenu(void); @@ -706,6 +707,11 @@ static menuitem_t SR_UnlockChecklistMenu[] = {IT_KEYHANDLER | IT_STRING, NULL, "", M_HandleChecklist, 0}, }; +static menuitem_t SR_SoundTestMenu[] = +{ + {IT_KEYHANDLER | IT_STRING, NULL, "", M_HandleSoundTest, 0}, +}; + static menuitem_t SR_EmblemHintMenu[] = { {IT_STRING|IT_CVAR, NULL, "Emblem Radar", &cv_itemfinder, 10}, @@ -1603,18 +1609,8 @@ menu_t SR_PandoraDef = 0, M_ExitPandorasBox }; -menu_t SR_MainDef = -{ - MN_SR_MAIN, - "M_SECRET", - sizeof (SR_MainMenu)/sizeof (menuitem_t), - &MainDef, - SR_MainMenu, - M_DrawSkyRoom, - 60, 40, - 0, - NULL -}; + +menu_t SR_MainDef = DEFAULTMENUSTYLE(MN_SR_MAIN, "M_SECRET", SR_MainMenu, &MainDef, 60, 40); menu_t SR_LevelSelectDef = MAPPLATTERMENUSTYLE( MN_SR_MAIN + (MN_SR_LEVELSELECT << 6), @@ -1632,6 +1628,20 @@ menu_t SR_UnlockChecklistDef = 0, NULL }; + +menu_t SR_SoundTestDef = +{ + MN_SR_MAIN + (MN_SR_SOUNDTEST << 6), + NULL, + sizeof (SR_SoundTestMenu)/sizeof (menuitem_t), + &SR_MainDef, + SR_SoundTestMenu, + M_DrawSoundTest, + 60, 150, + 0, + NULL +}; + menu_t SR_EmblemHintDef = { MN_SR_MAIN + (MN_SR_EMBLEMHINT << 6), @@ -2319,6 +2329,11 @@ void M_InitMenuPresTables(void) strncpy(menupres[i].musname, "_nitat", 7); else if (i == MN_SP_PLAYER || i == MN_SR_PLAYER) strncpy(menupres[i].musname, "_chsel", 7); + else if (i == MN_SR_SOUNDTEST) + { + *menupres[i].musname = '\0'; + menupres[i].musstop = true; + } } } @@ -6973,7 +6988,7 @@ static void M_DrawEmblemHints(void) M_DrawGenericMenu(); } -static void M_DrawSkyRoom(void) +/*static void M_DrawSkyRoom(void) { INT32 i, y = 0; @@ -7000,6 +7015,266 @@ static void M_DrawSkyRoom(void) } if (cv_soundtest.value) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + y + 8, V_YELLOWMAP, S_sfx[cv_soundtest.value].name); +}*/ + +static musicdef_t *curplaying = NULL; +static INT32 st_sel = 0, st_cc = 0; +static tic_t st_time = 0; +static patch_t* st_radio[9]; +static patch_t* st_launchpad[4]; + +static void M_SoundTest(INT32 choice) +{ + INT32 ul = skyRoomMenuTranslations[choice-1]; + UINT8 i; + char buf[8]; + + soundtestpage = (UINT8)(unlockables[ul].variable); + if (!soundtestpage) + soundtestpage = 1; + + if (!S_PrepareSoundTest()) + { + M_StartMessage(M_GetText("No selectable tracks found.\n"),NULL,MM_NOTHING); + return; + } + + STRBUFCPY(buf, "M_RADIOn"); + for (i = 0; i < 9; i++) + { + if (st_radio[i]) + W_UnlockCachedPatch(st_radio[i]); + buf[7] = (char)('0'+i); + st_radio[i] = W_CachePatchName(buf, PU_STATIC); + } + + STRBUFCPY(buf, "M_LPADn"); + for (i = 0; i < 4; i++) + { + if (st_launchpad[i]) + W_UnlockCachedPatch(st_launchpad[i]); + buf[6] = (char)('0'+i); + st_launchpad[i] = W_CachePatchName(buf, PU_STATIC); + } + + curplaying = NULL; + st_time = 0; + + st_sel = 0; + + st_cc = cv_closedcaptioning.value; // hack; + cv_closedcaptioning.value = 1; // hack + + M_SetupNextMenu(&SR_SoundTestDef); +} + +static void M_DrawSoundTest(void) +{ + INT32 x, y, i; + fixed_t hscale = FRACUNIT/2, vscale = FRACUNIT/2, bounce = 0; + UINT8 frame[4] = {0, 0, -1, SKINCOLOR_RUBY}; + + // let's handle the ticker first. ideally we'd tick this somewhere else, BUT... + if (curplaying) + { + if (curplaying == &soundtestsfx) + { + if (cv_soundtest.value) + { + frame[1] = (2-st_time); + frame[2] = ((cv_soundtest.value - 1) % 9); + frame[3] += (((cv_soundtest.value - 1) / 9) % (MAXSKINCOLORS - frame[3])); + if (st_time < 2) + st_time++; + } + } + else + { + if (curplaying->stoppingtics && st_time >= curplaying->stoppingtics) + { + curplaying = NULL; + st_time = 0; + } + else + { + fixed_t work, bpm = curplaying->bpm; + angle_t ang; + //bpm = FixedDiv((60*TICRATE)<<FRACBITS, bpm); -- bake this in on load + + work = st_time<<FRACBITS; + work %= bpm; + + if (st_time >= (FRACUNIT>>1)) // prevent overflow jump - takes about 15 minutes of loop on the same song to reach + st_time = (work>>FRACBITS); + + work = FixedDiv(work*180, bpm); + frame[0] = 8-(work/(20<<FRACBITS)); + ang = (FixedAngle(work)>>ANGLETOFINESHIFT) & FINEMASK; + bounce = (FINESINE(ang) - FRACUNIT/2); + hscale -= bounce/16; + vscale += bounce/16; + + st_time++; + } + } + } + + x = 90<<FRACBITS; + y = (BASEVIDHEIGHT-32)<<FRACBITS; + + V_DrawStretchyFixedPatch(x, y, + hscale, vscale, + 0, st_radio[frame[0]], NULL); + + V_DrawFixedPatch(x, y, FRACUNIT/2, 0, st_launchpad[0], NULL); + + for (i = 0; i < 9; i++) + { + if (i == frame[2]) + { + UINT8 *colmap = R_GetTranslationColormap(TC_RAINBOW, frame[3], GTC_CACHE); + V_DrawFixedPatch(x, y + (frame[1]<<FRACBITS), FRACUNIT/2, 0, st_launchpad[frame[1]+1], colmap); + } + else + V_DrawFixedPatch(x, y, FRACUNIT/2, 0, st_launchpad[1], NULL); + + if ((i % 3) == 2) + { + x -= ((2*28) + 25)<<(FRACBITS-1); + y -= ((2*7) - 11)<<(FRACBITS-1); + } + else + { + x += 28<<(FRACBITS-1); + y += 7<<(FRACBITS-1); + } + } + + y = (BASEVIDWIDTH-(vid.width/vid.dupx))/2; + + V_DrawFill(y, 20, vid.width/vid.dupx, 24, 159); + { + static fixed_t st_scroll = -1; + const char* titl; + x = 16; + V_DrawString(x, 10, 0, "NOW PLAYING:"); + if (curplaying) + { + if (curplaying->alttitle[0]) + titl = va("%s - %s - ", curplaying->title, curplaying->alttitle); + else + titl = va("%s - ", curplaying->title); + } + else + titl = "NONE - "; + + i = V_LevelNameWidth(titl); + + if (++st_scroll >= i) + st_scroll %= i; + + x -= st_scroll; + + while (x < BASEVIDWIDTH-y) + x += i; + while (x > y) + { + x -= i; + V_DrawLevelTitle(x, 24, 0, titl); + } + + if (curplaying) + V_DrawRightAlignedString(BASEVIDWIDTH-16, 46, V_ALLOWLOWERCASE, curplaying->authors); + } + + V_DrawFill(165, 60, 140, 112, 159); + + { + INT32 t, b, q, m = 112; + + if (numsoundtestdefs <= 7) + { + t = 0; + b = numsoundtestdefs - 1; + i = 0; + } + else + { + q = m; + m = (5*m)/numsoundtestdefs; + if (st_sel < 3) + { + t = 0; + b = 6; + i = 0; + } + else if (st_sel >= numsoundtestdefs-4) + { + t = numsoundtestdefs - 7; + b = numsoundtestdefs - 1; + i = q-m; + } + else + { + t = st_sel - 3; + b = st_sel + 3; + i = (t * (q-m))/(numsoundtestdefs - 7); + } + } + + V_DrawFill(165+140-1, 60 + i, 1, m, 0); + + if (t != 0) + V_DrawString(165+140+4, 60+4 - (skullAnimCounter/5), V_YELLOWMAP, "\x1A"); + + if (b != numsoundtestdefs - 1) + V_DrawString(165+140+4, 60+112-12 + (skullAnimCounter/5), V_YELLOWMAP, "\x1B"); + + x = 169; + y = 64; + + while (t <= b) + { + if (t == st_sel) + V_DrawFill(165, y-4, 140-1, 16, 155); + if (!soundtestdefs[t]->allowed) + { + V_DrawString(x, y, (t == st_sel ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE, "???"); + } + else if (soundtestdefs[t] == &soundtestsfx) + { + const char *sfxstr = va("SFX %s", cv_soundtest.string); + V_DrawString(x, y, (t == st_sel ? V_YELLOWMAP : 0), sfxstr); + if (t == st_sel) + { + V_DrawCharacter(x - 10 - (skullAnimCounter/5), y, + '\x1C' | V_YELLOWMAP, false); + V_DrawCharacter(x + 2 + V_StringWidth(sfxstr, 0) + (skullAnimCounter/5), y, + '\x1D' | V_YELLOWMAP, false); + } + + if (curplaying == soundtestdefs[t]) + { + sfxstr = (cv_soundtest.value) ? S_sfx[cv_soundtest.value].name : "N/A"; + i = V_StringWidth(sfxstr, 0); + V_DrawFill(165+140-9-i, y-4, i+8, 16, 150); + V_DrawRightAlignedString(165+140-5, y, V_YELLOWMAP, sfxstr); + } + } + else + { + V_DrawString(x, y, (t == st_sel ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE, soundtestdefs[t]->title); + if (curplaying == soundtestdefs[t]) + { + V_DrawFill(165+140-9, y-4, 8, 16, 150); + //V_DrawCharacter(165+140-8, y, '\x19' | V_YELLOWMAP, false); + V_DrawFixedPatch((165+140-9)<<FRACBITS, (y<<FRACBITS)-(bounce*4), FRACUNIT, 0, hu_font['\x19'-HU_FONTSTART], V_GetStringColormap(V_YELLOWMAP)); + } + } + t++; + y += 16; + } + } } static void M_HandleSoundTest(INT32 choice) @@ -7009,27 +7284,102 @@ static void M_HandleSoundTest(INT32 choice) switch (choice) { case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL, sfx_menu1); + if (st_sel++ >= numsoundtestdefs-1) + st_sel = 0; + { + cv_closedcaptioning.value = st_cc; // hack + S_StartSound(NULL, sfx_menu1); + cv_closedcaptioning.value = 1; // hack + } break; case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); + if (!st_sel--) + st_sel = numsoundtestdefs-1; + { + cv_closedcaptioning.value = st_cc; // hack + S_StartSound(NULL, sfx_menu1); + cv_closedcaptioning.value = 1; // hack + } + break; + case KEY_PGDN: + if (st_sel < numsoundtestdefs-1) + { + st_sel += 3; + if (st_sel >= numsoundtestdefs-1) + st_sel = numsoundtestdefs-1; + cv_closedcaptioning.value = st_cc; // hack + S_StartSound(NULL, sfx_menu1); + cv_closedcaptioning.value = 1; // hack + } + break; + case KEY_PGUP: + if (st_sel) + { + st_sel -= 3; + if (st_sel < 0) + st_sel = 0; + cv_closedcaptioning.value = st_cc; // hack + S_StartSound(NULL, sfx_menu1); + cv_closedcaptioning.value = 1; // hack + } break; case KEY_BACKSPACE: + if (curplaying) + { + S_StopSounds(); + S_StopMusic(); + curplaying = NULL; + st_time = 0; + cv_closedcaptioning.value = st_cc; // hack + S_StartSound(NULL, sfx_skid); + cv_closedcaptioning.value = 1; // hack + } + break; case KEY_ESCAPE: exitmenu = true; break; case KEY_RIGHTARROW: - CV_AddValue(&cv_soundtest, 1); + if (soundtestdefs[st_sel] == &soundtestsfx && soundtestdefs[st_sel]->allowed) + { + S_StopSounds(); + S_StopMusic(); + curplaying = soundtestdefs[st_sel]; + st_time = 0; + CV_AddValue(&cv_soundtest, 1); + } break; case KEY_LEFTARROW: - CV_AddValue(&cv_soundtest, -1); + if (soundtestdefs[st_sel] == &soundtestsfx && soundtestdefs[st_sel]->allowed) + { + S_StopSounds(); + S_StopMusic(); + curplaying = soundtestdefs[st_sel]; + st_time = 0; + CV_AddValue(&cv_soundtest, -1); + } break; case KEY_ENTER: S_StopSounds(); - S_StartSound(NULL, cv_soundtest.value); + S_StopMusic(); + st_time = 0; + if (soundtestdefs[st_sel]->allowed) + { + curplaying = soundtestdefs[st_sel]; + if (curplaying == &soundtestsfx) + { + // S_StopMusic() -- is this necessary? + if (cv_soundtest.value) + S_StartSound(NULL, cv_soundtest.value); + } + else + S_ChangeMusicInternal(curplaying->name, !curplaying->stoppingtics); + } + else + { + curplaying = NULL; + S_StartSound(NULL, sfx_lose); + } break; default: @@ -7037,6 +7387,11 @@ static void M_HandleSoundTest(INT32 choice) } if (exitmenu) { + Z_Free(soundtestdefs); + soundtestdefs = NULL; + + cv_closedcaptioning.value = st_cc; // undo hack + if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); else @@ -7111,8 +7466,8 @@ static void M_SecretsMenu(INT32 choice) SR_MainMenu[i].itemaction = M_Credits; break; case SECRET_SOUNDTEST: - SR_MainMenu[i].status = IT_STRING|IT_KEYHANDLER; - SR_MainMenu[i].itemaction = M_HandleSoundTest; + SR_MainMenu[i].status = IT_STRING|IT_CALL; + SR_MainMenu[i].itemaction = M_SoundTest; default: break; } diff --git a/src/m_menu.h b/src/m_menu.h index 51c734a43c8a6199c37857a622c69c2a567113f7..ec7915cc29ee070689fe800787658cfc097c1ecd 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -106,6 +106,7 @@ typedef enum MN_SR_UNLOCKCHECKLIST, MN_SR_EMBLEMHINT, MN_SR_PLAYER, + MN_SR_SOUNDTEST, // Addons (Part of MISC, but let's make it our own) MN_AD_MAIN, diff --git a/src/p_setup.c b/src/p_setup.c index d844a29e6b0b29247a30315b9f3ad037da7d5fcd..79391c3e427298bdd977696c09069e6da5ac56fe 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3477,6 +3477,11 @@ boolean P_AddWadFile(const char *wadfilename) R_PatchSkins(wadnum); // toast: PATCH PATCH ST_ReloadSkinFaceGraphics(); + // + // edit music defs + // + S_LoadMusicDefs(wadnum); + // // search for maps // diff --git a/src/s_sound.c b/src/s_sound.c index 8b87bd08328b9d00e0de2a0f0d4bbbc5b4f9d2e8..ab4bde6171ce53fb80590e0f8d511c44dc1030c5 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -38,6 +38,7 @@ extern INT32 msg_id; #include "p_local.h" // camera info #include "fastcmp.h" #include "m_misc.h" // for tunes command +#include "m_cond.h" // for conditionsets #if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) #include "lua_hook.h" // MusicChange hook @@ -1425,6 +1426,274 @@ static UINT32 queue_fadeinms; static tic_t pause_starttic; +/// ------------------------ +/// Music Definitions +/// ------------------------ + +musicdef_t soundtestsfx = { + "_STSFX", // prevents exactly one valid track name from being used on the sound test + "Sound Effects", + "", + "SEGA, Sonic Team Jr, other sources", + 1, // show on soundtest page 1 + 0, // with no conditions + 0, + 0, + false, + NULL +}; + +musicdef_t *musicdefstart = &soundtestsfx; + +// +// search for music definition in wad +// +static UINT16 W_CheckForMusicDefInPwad(UINT16 wadid) +{ + UINT16 i; + lumpinfo_t *lump_p; + + lump_p = wadfiles[wadid]->lumpinfo; + for (i = 0; i < wadfiles[wadid]->numlumps; i++, lump_p++) + if (memcmp(lump_p->name, "MUSICDEF", 8) == 0) + return i; + + return INT16_MAX; // not found +} + +void S_LoadMusicDefs(UINT16 wadnum) +{ + UINT16 lump; + char *buf; + char *buf2; + char *stoken; + char *value; + size_t size; + INT32 i; + musicdef_t *def = NULL; + UINT16 line = 1; // for better error msgs + + lump = W_CheckForMusicDefInPwad(wadnum); + if (lump == INT16_MAX) + return; + + buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lump); + + // for strtok + buf2 = malloc(size+1); + if (!buf2) + I_Error("S_LoadMusicDefs: No more free memory\n"); + M_Memcpy(buf2,buf,size); + buf2[size] = '\0'; + + stoken = strtok (buf2, "\r\n "); + // Find music def + while (stoken) + { + /*if ((stoken[0] == '/' && stoken[1] == '/') + || (stoken[0] == '#')) // skip comments + { + stoken = strtok(NULL, "\r\n"); // skip end of line + if (def) + stoken = strtok(NULL, "\r\n= "); + else + stoken = strtok(NULL, "\r\n "); + line++; + } + else*/ if (!stricmp(stoken, "lump")) + { + value = strtok(NULL, "\r\n "); + + if (!value) + { + CONS_Alert(CONS_WARNING, "MUSICDEF: Lump '%s' is missing name. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); + stoken = strtok(NULL, "\r\n"); // skip end of line + goto skip_lump; + } + + // No existing musicdefs + /*if (!musicdefstart) + { + musicdefstart = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL); + STRBUFCPY(musicdefstart->name, value); + strlwr(musicdefstart->name); + def = musicdefstart; + //CONS_Printf("S_LoadMusicDefs: Initialized musicdef w/ song '%s'\n", def->name); + } + else*/ + { + musicdef_t *prev = NULL; + def = musicdefstart; + + // Search if this is a replacement + //CONS_Printf("S_LoadMusicDefs: Searching for song replacement...\n"); + while (def) + { + if (!stricmp(def->name, value)) + { + //CONS_Printf("S_LoadMusicDefs: Found song replacement '%s'\n", def->name); + break; + } + + prev = def; + def = def->next; + } + + // Nothing found, add to the end. + if (!def) + { + def = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL); + STRBUFCPY(def->name, value); + strlwr(def->name); + def->bpm = TICRATE<<(FRACBITS-1); // FixedDiv((60*TICRATE)<<FRACBITS, 120<<FRACBITS) + if (prev != NULL) + prev->next = def; + //CONS_Printf("S_LoadMusicDefs: Added song '%s'\n", def->name); + } + } + +skip_lump: + stoken = strtok(NULL, "\r\n "); + line++; + } + else + { + value = strtok(NULL, "\r\n= "); + + if (!value) + { + CONS_Alert(CONS_WARNING, "MUSICDEF: Field '%s' is missing value. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); + stoken = strtok(NULL, "\r\n"); // skip end of line + goto skip_field; + } + + if (!def) + { + CONS_Alert(CONS_ERROR, "MUSICDEF: No music definition before field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); + free(buf2); + return; + } + + i = atoi(value); + + if (!stricmp(stoken, "usage")) { +#if 0 // Ignore for now + STRBUFCPY(def->usage, value); + for (value = def->usage; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + //CONS_Printf("S_LoadMusicDefs: Set usage to '%s'\n", def->usage); +#endif + } else if (!stricmp(stoken, "source")) { +#if 0 // Ignore for now + STRBUFCPY(def->source, value); + for (value = def->source; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->usage); +#endif + } else if (!stricmp(stoken, "title")) { + STRBUFCPY(def->title, value); + for (value = def->title; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + //CONS_Printf("S_LoadMusicDefs: Set title to '%s'\n", def->source); + } else if (!stricmp(stoken, "alttitle")) { + STRBUFCPY(def->alttitle, value); + for (value = def->alttitle; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + //CONS_Printf("S_LoadMusicDefs: Set alttitle to '%s'\n", def->source); + } else if (!stricmp(stoken, "authors")) { + STRBUFCPY(def->authors, value); + for (value = def->authors; *value; value++) + if (*value == '_') *value = ' '; // turn _ into spaces. + //CONS_Printf("S_LoadMusicDefs: Set authors to '%s'\n", def->source); + } else if (!stricmp(stoken, "soundtestpage")) { + def->soundtestpage = (UINT8)i; + } else if (!stricmp(stoken, "soundtestcond")) { + // Convert to map number + if (value[0] >= 'A' && value[0] <= 'Z' && value[2] == '\0') + i = M_MapNumber(value[0], value[1]); + def->soundtestcond = (INT16)i; + } else if (!stricmp(stoken, "stoppingtime")) { + double stoppingtime = atof(value)*TICRATE; + def->stoppingtics = (tic_t)stoppingtime; + } else if (!stricmp(stoken, "bpm")) { + double bpm = atof(value); + fixed_t bpmf = FLOAT_TO_FIXED(bpm); + if (bpmf > 0) + def->bpm = FixedDiv((60*TICRATE)<<FRACBITS, bpmf); + } else { + CONS_Alert(CONS_WARNING, "MUSICDEF: Invalid field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); + } + +skip_field: + stoken = strtok(NULL, "\r\n= "); + line++; + } + } + + free(buf2); + return; +} + +// +// S_InitMusicDefs +// +// Simply load music defs in all wads. +// +void S_InitMusicDefs(void) +{ + UINT16 i; + for (i = 0; i < numwadfiles; i++) + S_LoadMusicDefs(i); +} + +musicdef_t **soundtestdefs = NULL; +INT32 numsoundtestdefs = 0; +UINT8 soundtestpage = 1; + +// +// S_PrepareSoundTest +// +// Prepare sound test. What am I, your butler? +// +boolean S_PrepareSoundTest(void) +{ + musicdef_t *def; + INT32 pos = numsoundtestdefs = 0; + + for (def = musicdefstart; def; def = def->next) + { + if (!(def->soundtestpage & soundtestpage)) + continue; + def->allowed = false; + numsoundtestdefs++; + } + + if (!numsoundtestdefs) + return false; + + if (soundtestdefs) + Z_Free(soundtestdefs); + + if (!(soundtestdefs = Z_Malloc(numsoundtestdefs*sizeof(musicdef_t *), PU_STATIC, NULL))) + I_Error("S_PrepareSoundTest(): could not allocate soundtestdefs."); + + for (def = musicdefstart; def /*&& i < numsoundtestdefs*/; def = def->next) + { + if (!(def->soundtestpage & soundtestpage)) + continue; + soundtestdefs[pos++] = def; + if (def->soundtestcond > 0 && !(mapvisited[def->soundtestcond-1] & MV_BEATEN)) + continue; + if (def->soundtestcond < 0 && !M_Achieved(1-def->soundtestcond)) + continue; + def->allowed = true; + } + + return true; +} + + /// ------------------------ /// Music Status /// ------------------------ diff --git a/src/s_sound.h b/src/s_sound.h index c46c9fa089b40b02965c9dd142469543cf1f8fe2..d1551df0bdcad2210517dd3ae894fa7848169da2 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -188,6 +188,39 @@ boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi); // Set Speed of Music boolean S_SpeedMusic(float speed); +// Music definitions +typedef struct musicdef_s +{ + char name[7]; + char title[32]; + char alttitle[64]; + char authors[256]; + //char usage[256]; -- probably never going to be relevant to vanilla + /* + the trouble here is that kart combines what we call "title" + and "authors" into one string. we need to split it for sound + test reasons. they might split it later like we did, but... + */ + //char source[256]; + UINT8 soundtestpage; + INT16 soundtestcond; // +ve for map, -ve for conditionset, 0 for already here + tic_t stoppingtics; + fixed_t bpm; + boolean allowed; // question marks or listenable on sound test? + struct musicdef_s *next; +} musicdef_t; + +extern musicdef_t soundtestsfx; +extern musicdef_t *musicdefstart; +extern musicdef_t **soundtestdefs; +extern INT32 numsoundtestdefs; +extern UINT8 soundtestpage; + +void S_LoadMusicDefs(UINT16 wadnum); +void S_InitMusicDefs(void); + +boolean S_PrepareSoundTest(void); + // // Music Seeking // diff --git a/src/sounds.c b/src/sounds.c index 791a7571e432b23343fcb39b63ca5a6d9c86bd7f..197bfc0660a303dc213d139ca6c7137439f303b4 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -857,35 +857,45 @@ void S_InitRuntimeSounds (void) } } +sfxenum_t sfxfree = sfx_freeslot0; + // Add a new sound fx into a free sfx slot. // sfxenum_t S_AddSoundFx(const char *name, boolean singular, INT32 flags, boolean skinsound) { - sfxenum_t i, slot; + sfxenum_t i; if (skinsound) - slot = sfx_skinsoundslot0; - else - slot = sfx_freeslot0; - - for (i = slot; i < NUMSFX; i++) { - if (!S_sfx[i].priority) + for (i = sfx_skinsoundslot0; i < NUMSFX; i++) { - strncpy(freeslotnames[i-sfx_freeslot0], name, 6); - S_sfx[i].singularity = singular; - S_sfx[i].priority = 60; - S_sfx[i].pitch = flags; - S_sfx[i].volume = -1; - S_sfx[i].lumpnum = LUMPERROR; - S_sfx[i].skinsound = -1; - S_sfx[i].usefulness = -1; - - /// \todo if precached load it here - S_sfx[i].data = NULL; - return i; + if (S_sfx[i].priority) + continue; + break; } } + else + i = sfxfree; + + if (i < NUMSFX) + { + strncpy(freeslotnames[i-sfx_freeslot0], name, 6); + S_sfx[i].singularity = singular; + S_sfx[i].priority = 60; + S_sfx[i].pitch = flags; + S_sfx[i].volume = -1; + S_sfx[i].lumpnum = LUMPERROR; + S_sfx[i].skinsound = -1; + S_sfx[i].usefulness = -1; + + /// \todo if precached load it here + S_sfx[i].data = NULL; + + if (!skinsound) + sfxfree++; + + return i; + } CONS_Alert(CONS_WARNING, M_GetText("No more free sound slots\n")); return 0; } diff --git a/src/sounds.h b/src/sounds.h index 9f6e0bab640128b2e8c4a36182479bc2b28f7cbe..d48deb5404d8e2a279e1794ba85e0ff114bdecc8 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -879,6 +879,7 @@ typedef enum void S_InitRuntimeSounds(void); sfxenum_t S_AddSoundFx(const char *name, boolean singular, INT32 flags, boolean skinsound); +extern sfxenum_t sfxfree; // sound test and slotting void S_RemoveSoundFx(sfxenum_t id); #endif diff --git a/src/v_video.c b/src/v_video.c index 7f99cfd326c8089b878e4624a90c9f0e295edf87..d7dc0e50ff4c9d19789018e2211e120bb87d9864 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -541,12 +541,12 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix } // Draws a patch scaled to arbitrary size. -void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, const UINT8 *colormap) +void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap) { UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); UINT32 alphalevel = 0; - fixed_t col, ofs, colfrac, rowfrac, fdup; + fixed_t col, ofs, colfrac, rowfrac, fdup, vdup; INT32 dupx, dupy; const column_t *column; UINT8 *desttop, *dest, *deststart, *destend; @@ -563,7 +563,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t //if (rendermode != render_soft && !con_startup) // Why? if (rendermode != render_soft) { - HWR_DrawFixedPatch((GLPatch_t *)patch, x, y, pscale, scrn, colormap); + HWR_DrawStretchyFixedPatch((GLPatch_t *)patch, x, y, pscale, vscale, scrn, colormap); return; } #endif @@ -618,9 +618,11 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t // only use one dup, to avoid stretching (har har) dupx = dupy = (dupx < dupy ? dupx : dupy); - fdup = FixedMul(dupx<<FRACBITS, pscale); + fdup = vdup = FixedMul(dupx<<FRACBITS, pscale); + if (vscale != pscale) + vdup = FixedMul(dupx<<FRACBITS, vscale); colfrac = FixedDiv(FRACUNIT, fdup); - rowfrac = FixedDiv(FRACUNIT, fdup); + rowfrac = FixedDiv(FRACUNIT, vdup); // So it turns out offsets aren't scaled in V_NOSCALESTART unless V_OFFSET is applied ...poo, that's terrible // For now let's just at least give V_OFFSET the ability to support V_FLIP @@ -637,7 +639,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t // top offset // TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!? - offsety = FixedMul(SHORT(patch->topoffset)<<FRACBITS, pscale); + offsety = FixedMul(SHORT(patch->topoffset)<<FRACBITS, vscale); if ((scrn & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs { @@ -653,13 +655,14 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t if (splitscreen && (scrn & V_PERPLAYER)) { fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1); - fdup >>= 1; + vdup >>= 1; rowfrac <<= 1; y >>= 1; #ifdef QUADS if (splitscreen > 1) // 3 or 4 players { fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1)); + fdup >>= 1; colfrac <<= 1; x >>= 1; if (stplyr == &players[displayplayer]) @@ -825,7 +828,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t dest = desttop; if (scrn & V_FLIP) dest = deststart + (destend - desttop); - dest += FixedInt(FixedMul(topdelta<<FRACBITS,fdup))*vid.width; + dest += FixedInt(FixedMul(topdelta<<FRACBITS,vdup))*vid.width; for (ofs = 0; dest < deststop && (ofs>>FRACBITS) < column->length; ofs += rowfrac) { diff --git a/src/v_video.h b/src/v_video.h index 01d50cd57957479dfe74700aba40212caa215996..cd32ac5f89ed5879f01a0e44adfae872e1f2c908 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -140,7 +140,8 @@ extern RGBA_t *pMasterPalette; #define V_DrawSmallTranslucentPatch(x,y,s,p) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/2, s, p, NULL) #define V_DrawTinyTranslucentPatch(x,y,s,p) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/4, s, p, NULL) #define V_DrawSciencePatch(x,y,s,p,sc) V_DrawFixedPatch(x,y,sc,s,p,NULL) -void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, const UINT8 *colormap); +#define V_DrawFixedPatch(x,y,sc,s,p,c) V_DrawStretchyFixedPatch(x,y,sc,sc,s,p,c) +void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap); void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor); diff --git a/src/w_wad.c b/src/w_wad.c index ea9310580a08dd2e6d97302023d06d96866e4f6c..b4ee772d96f2ea877ebfc06c2440e478d1266b53 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1891,6 +1891,7 @@ int W_VerifyNMUSlumps(const char *filename) {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"YB_", 3}, // Intermission graphics, goes with the above {"M_", 2}, // As does menu stuff + {"MUSICDEF", 8}, // Song definitions (thanks kart) {NULL, 0}, };