diff --git a/debian-template/rules b/debian-template/rules old mode 100755 new mode 100644 diff --git a/src/d_main.c b/src/d_main.c index 2a5993c1..29a91686 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1350,6 +1350,7 @@ void D_SRB2Main(void) I_StartupSound(); I_InitMusic(); S_InitSfxChannels(cv_soundvolume.value); + S_InitMusicDefs(); CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 71c299e2..e15ed9aa 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -791,6 +791,7 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_consolechat); CV_RegisterVar(&cv_chatnotifications); CV_RegisterVar(&cv_chatbacktint); + CV_RegisterVar(&cv_songcredits); //CV_RegisterVar(&cv_crosshair); //CV_RegisterVar(&cv_crosshair2); //CV_RegisterVar(&cv_crosshair3); diff --git a/src/g_game.c b/src/g_game.c index 23f41564..1e0c7e46 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -435,6 +435,9 @@ consvar_t cv_chatbacktint = {"chatbacktint", "On", CV_SAVE, CV_OnOff, NULL, 0, N static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {2, "Window (Hidden)"}, {0, NULL}}; consvar_t cv_consolechat = {"chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +// Display song credits +consvar_t cv_songcredits = {"songcredits", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + /*consvar_t cv_crosshair = {"crosshair", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_crosshair2 = {"crosshair2", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_crosshair3 = {"crosshair3", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -2359,6 +2362,7 @@ void G_PlayerReborn(INT32 player) INT32 bumper; INT32 comebackpoints; INT32 wanted; + boolean songcredit = false; score = players[player].score; marescore = players[player].marescore; @@ -2537,10 +2541,13 @@ void G_PlayerReborn(INT32 player) strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); mapmusname[6] = 0; mapmusflags = mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK; + songcredit = true; } } P_RestoreMusic(p); + if (songcredit) + S_ShowMusicCredit(); if (leveltime > (starttime + (TICRATE/2)) && !p->spectator) p->kartstuff[k_respawn] = 48; // Respawn effect diff --git a/src/g_game.h b/src/g_game.h index 720d561f..14dc12d0 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -55,6 +55,7 @@ extern INT16 rw_maximums[NUM_WEAPONS]; // used in game menu extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection/*, cv_compactscoreboard*/; +extern consvar_t cv_songcredits; //extern consvar_t cv_crosshair, cv_crosshair2, cv_crosshair3, cv_crosshair4; extern consvar_t cv_invertmouse/*, cv_alwaysfreelook, cv_chasefreelook, cv_mousemove*/; extern consvar_t cv_invertmouse2/*, cv_alwaysfreelook2, cv_chasefreelook2, cv_mousemove2*/; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index f66aa07b..a38e91a7 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -51,6 +51,7 @@ #include "lua_hook.h" #endif +#include "s_sound.h" // song credits #include "k_kart.h" // coords are scaled @@ -103,6 +104,8 @@ static patch_t *tokenicon; // crosshair 0 = off, 1 = cross, 2 = angle, 3 = point, see m_menu.c static patch_t *crosshair[HU_CROSSHAIRS]; // 3 precached crosshair graphics +// song credits +static patch_t *songcreditbg; // ------- // protos. @@ -290,6 +293,8 @@ void HU_LoadGraphics(void) tinyemeraldpics[4] = W_CachePatchName("TEMER5", PU_HUDGFX); tinyemeraldpics[5] = W_CachePatchName("TEMER6", PU_HUDGFX); tinyemeraldpics[6] = W_CachePatchName("TEMER7", PU_HUDGFX); + + songcreditbg = W_CachePatchName("K_SONGCR", PU_HUDGFX); } // Initialise Heads up @@ -2119,6 +2124,51 @@ static void HU_DrawDemoInfo(void) } } + +// +// Song credits +// +static void HU_DrawSongCredits(void) +{ + char *str; + INT32 len, destx; + INT32 y = (splitscreen ? (BASEVIDHEIGHT/2)-4 : 32); + INT32 bgt; + + if (!cursongcredit.def) // No def + return; + + str = va("\x1F"" %s", cursongcredit.def->source); + len = V_ThinStringWidth(str, V_ALLOWLOWERCASE|V_6WIDTHSPACE); + destx = (len+7); + + if (cursongcredit.anim) + { + if (cursongcredit.trans > 0) + cursongcredit.trans--; + if (cursongcredit.x < destx) + cursongcredit.x += (destx - cursongcredit.x) / 2; + if (cursongcredit.x > destx) + cursongcredit.x = destx; + cursongcredit.anim--; + } + else + { + if (cursongcredit.trans < NUMTRANSMAPS) + cursongcredit.trans++; + if (cursongcredit.x > 0) + cursongcredit.x /= 2; + if (cursongcredit.x < 0) + cursongcredit.x = 0; + } + + bgt = (NUMTRANSMAPS/2)+(cursongcredit.trans/2); + if (bgt < NUMTRANSMAPS) + V_DrawScaledPatch(cursongcredit.x, y-2, V_SNAPTOLEFT|(bgt<flags & ML_EFFECT4)); + if (!(line->flags & ML_EFFECT3)) + S_ShowMusicCredit(); // Except, you can use the ML_BLOCKMONSTERS flag to change this behavior. // if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn. diff --git a/src/s_sound.c b/src/s_sound.c index 34163fd3..856aa045 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -101,7 +101,7 @@ consvar_t cv_numChannels = {"snd_channels", "64", CV_SAVE|CV_CALL, CV_Unsigned, #endif consvar_t surround = {"surround", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE|CV_NOSHOWHELP, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; +//consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE|CV_NOSHOWHELP, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; // Sound system toggles, saved into the config consvar_t cv_gamedigimusic = {"digimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameDigiMusic_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -263,7 +263,7 @@ void S_RegisterSoundStuff(void) #endif CV_RegisterVar(&surround); CV_RegisterVar(&cv_samplerate); - CV_RegisterVar(&cv_resetmusic); + //CV_RegisterVar(&cv_resetmusic); CV_RegisterVar(&cv_gamesounds); CV_RegisterVar(&cv_gamedigimusic); #ifndef NO_MIDI @@ -1541,6 +1541,210 @@ static void *music_data; static UINT16 music_flags; static boolean music_looping; +/// ------------------------ +/// Music Definitions +/// ------------------------ + +musicdef_t *musicdefstart = NULL; // First music definition +struct cursongcredit cursongcredit; // Currently displayed song credit info + +// +// 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; + musicdef_t *def, *prev; + 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'; + + def = prev = NULL; + + 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 + { + 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); + 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; + } + + 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")) { + 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->source); + } 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); +} + +// +// S_ShowMusicCredit +// +// Display current song's credit on screen +// +void S_ShowMusicCredit(void) +{ + musicdef_t *def = musicdefstart; + + if (!cv_songcredits.value) + return; + + if (!def) // No definitions + return; + + while (def) + { + if (!stricmp(def->name, music_name)) + { + cursongcredit.def = def; + cursongcredit.anim = 5*TICRATE; + cursongcredit.x = 0; + cursongcredit.trans = NUMTRANSMAPS; + return; + } + else + def = def->next; + } +} + /// ------------------------ /// Music Status /// ------------------------ @@ -1839,9 +2043,13 @@ void S_Start(void) mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); } - if (cv_resetmusic.value) + //if (cv_resetmusic.value) // Starting ambience should always be restarted S_StopMusic(); - S_ChangeMusic(mapmusname, mapmusflags, true); + + if (leveltime < (starttime + (TICRATE/2))) // SRB2Kart + S_ChangeMusic((encoremode ? "estart" : "kstart"), 0, false); + else + S_ChangeMusic(mapmusname, mapmusflags, true); } static void Command_Tunes_f(void) @@ -1974,7 +2182,7 @@ void GameDigiMusic_OnChange(void) if (Playing()) P_RestoreMusic(&players[consoleplayer]); else - S_ChangeMusicInternal("lclear", false); + S_ChangeMusicInternal("titles", looptitle); } else { @@ -2016,7 +2224,7 @@ void GameMIDIMusic_OnChange(void) if (Playing()) P_RestoreMusic(&players[consoleplayer]); else - S_ChangeMusicInternal("lclear", false); + S_ChangeMusicInternal("titles", looptitle); } else { diff --git a/src/s_sound.h b/src/s_sound.h index c83188cf..1ad519c2 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -27,7 +27,7 @@ extern consvar_t stereoreverse; extern consvar_t cv_soundvolume, cv_digmusicvolume;//, cv_midimusicvolume; extern consvar_t cv_numChannels; extern consvar_t surround; -extern consvar_t cv_resetmusic; +//extern consvar_t cv_resetmusic; extern consvar_t cv_gamedigimusic; #ifndef NO_MIDI extern consvar_t cv_gamemidimusic; @@ -128,6 +128,29 @@ boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi); // Set Speed of Music boolean S_SpeedMusic(float speed); +// Music credits +typedef struct musicdef_s +{ + char name[7]; + //char usage[256]; + char source[256]; + struct musicdef_s *next; +} musicdef_t; + +extern struct cursongcredit +{ + musicdef_t *def; + UINT16 anim; + INT32 x; + UINT8 trans; +} cursongcredit; + +extern musicdef_t *musicdefstart; + +void S_LoadMusicDefs(UINT16 wadnum); +void S_InitMusicDefs(void); +void S_ShowMusicCredit(void); + // // Music Routines // diff --git a/src/v_video.c b/src/v_video.c index eeb2593a..dd95efe3 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2267,6 +2267,7 @@ INT32 V_ThinStringWidth(const char *string, INT32 option) { INT32 c, w = 0; INT32 spacewidth = 2, charwidth = 0; + boolean lowercase = (option & V_ALLOWLOWERCASE); size_t i; switch (option & V_SPACINGMASK) @@ -2290,14 +2291,21 @@ INT32 V_ThinStringWidth(const char *string, INT32 option) if ((UINT8)c >= 0x80 && (UINT8)c <= 0x8F) //color parsing! -Inuyasha 2.16.09 continue; - c = toupper(c) - HU_FONTSTART; + if (!lowercase || !tny_font[c-HU_FONTSTART]) + c = toupper(c); + c -= HU_FONTSTART; + if (c < 0 || c >= HU_FONTSIZE || !tny_font[c]) w += spacewidth; else + { w += (charwidth ? charwidth - : (option & V_6WIDTHSPACE ? max(1, SHORT(tny_font[c]->width)-1) : SHORT(tny_font[c]->width))); // Reuse this flag for the alternate bunched-up spacing + : ((option & V_6WIDTHSPACE && i < strlen(string)-1) ? max(1, SHORT(tny_font[c]->width)-1) // Reuse this flag for the alternate bunched-up spacing + : SHORT(tny_font[c]->width))); + } } + return w; } diff --git a/src/w_wad.c b/src/w_wad.c index 69b4cb2e..63bee97d 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1738,6 +1738,7 @@ int W_VerifyNMUSlumps(const char *filename) {"MKFNT", 5}, // Kart font changes {"K_", 2}, // Kart graphic changes + {"MUSICDEF", 8}, // Kart song definitions {NULL, 0}, };