diff --git a/Source/d_main.c b/Source/d_main.c index 745e1b9c..a618749a 100644 --- a/Source/d_main.c +++ b/Source/d_main.c @@ -121,6 +121,8 @@ boolean singletics = false; // debug flag to cancel adaptiveness boolean nosfxparm; boolean nomusicparm; +boolean umapinfo_loaded = false; + //jff 4/18/98 extern boolean inhelpscreens; @@ -1639,7 +1641,10 @@ static void D_ProcessUMInWad(int i) D_ProcessUMInWad(lumpinfo[i].next); if (!strncasecmp(lumpinfo[i].name, "umapinfo", 8) && lumpinfo[i].namespace == ns_global) - U_ParseMapInfo((const char *)W_CacheLumpNum(i, PU_CACHE), W_LumpLength(i)); + { + U_ParseMapInfo((const char *)W_CacheLumpNum(i, PU_CACHE), W_LumpLength(i)); + umapinfo_loaded = true; + } } } diff --git a/Source/d_main.h b/Source/d_main.h index a542d92f..87bae111 100644 --- a/Source/d_main.h +++ b/Source/d_main.h @@ -53,6 +53,8 @@ extern boolean pistolstart; extern boolean nosfxparm; extern boolean nomusicparm; +extern boolean umapinfo_loaded; + // Called by IO functions when input is detected. void D_PostEvent(event_t* ev); diff --git a/Source/g_game.c b/Source/g_game.c index 9ef4c03a..0ba8aafc 100644 --- a/Source/g_game.c +++ b/Source/g_game.c @@ -1253,12 +1253,78 @@ static void G_DoPlayDemo(void) return; } + // ano - jun2019 + // so the format is + // demover byte == 255 + // "PR+UM" signature (w/ ending null terminator) + // extension_version byte. for now this should always be "1" + // 2 bytes for num_extensions (little-endian) + // num_extensions * + // 1 byte string length + // and length chars (up to 65535 obviously) + // note that the format has each length by each string + // as opposed to a table of lengths + // an example extensions string is "UMAPINFO". + // then finally the "real" demover byte is present here + demover = *demo_p++; + + if (demover == 255) + { + boolean using_umapinfo = false; + int extension_version = -1; + int num_extensions; + + // we check for the PR+UM signature as mentioned. + // Eternity Engine also uses 255 demover, with other signatures. + if (strncmp((const char *)demo_p, "PR+UM", 5) != 0) + { + I_Error("G_DoPlayDemo: Extended demo format 255 found, but \"PR+UM\" string not found."); + } + + demo_p += 6; + extension_version = *demo_p++; + + if (extension_version != 1) + { + I_Error("G_DoPlayDemo: Extended demo format version %d unrecognized.", extension_version); + } + + num_extensions = *demo_p++; + num_extensions |= ((unsigned int)(*demo_p++)) << 8; + + for (i = 0; i < num_extensions; i++) + { + int r_len = *demo_p++; + + // ano - jun2019 - when more potential extension strings get added, + // this section can become more complex + if (r_len == 8 && strncmp((const char *)demo_p, "UMAPINFO", 8) == 0) + { + using_umapinfo = true; + } + else + { + I_Error("G_DoPlayDemo: Extended demo format extension unrecognized."); + } + + demo_p += r_len; + } + + // skip map name + if (using_umapinfo) + { + demo_p += 8; + } + // ano - jun2019 - this is to support other demovers effectively? + // while still having the extended features + demover = *demo_p++; + } + // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly. // Old demos turn on demo_compatibility => compatibility; new demos load // compatibility flag, and other flags as well, as a part of the demo. - demo_version = // killough 7/19/98: use the version id stored in demo - demover = *demo_p++; + demo_version = demover; // killough 7/19/98: use the version id stored in demo // [FG] PrBoom's own demo format starts with demo version 210 if (demover >= 210 && demover != MBF21VERSION) @@ -3025,6 +3091,68 @@ void G_BeginRecording(void) demo_p = demobuffer; + if (umapinfo_loaded) + { + int num_extensions = 1; + char mapname[9] = {0}; + + // demover + *demo_p++ = 0xFF; + // signature + *demo_p++ = 'P'; + *demo_p++ = 'R'; + *demo_p++ = '+'; + *demo_p++ = 'U'; + *demo_p++ = 'M'; + *demo_p++ = '\0'; + // extension version + *demo_p++ = 1; + // + *demo_p++ = num_extensions & 0xff; + *demo_p++ = (num_extensions >> 8) & 0xff; + + // ano - note that the format has each length by each string + // as opposed to a table of lengths + *demo_p++ = 0x08; + *demo_p++ = 'U'; + *demo_p++ = 'M'; + *demo_p++ = 'A'; + *demo_p++ = 'P'; + *demo_p++ = 'I'; + *demo_p++ = 'N'; + *demo_p++ = 'F'; + *demo_p++ = 'O'; + // ano - to properly extend this to support other extension strings + // we wouldn't just plop this here, but right now we only support the 1 + // in the future, we should assume that chunks in the header should + // follow the order of their appearance in the extensions table. + + // [XA] get the map name from gamemapinfo if the + // starting map has a UMAPINFO definition. if not, + // fall back to the usual MAPxx/ExMy default. + if (gamemapinfo) + { + strncpy(mapname, gamemapinfo->mapname, 8); + } + else if(gamemode == commercial) + { + snprintf(mapname, 9, "MAP%02d", gamemap); + } + else + { + snprintf(mapname, 9, "E%dM%d", gameepisode, gamemap); + } + + for (i = 0; i < 8; i++) + { + // FIXME - the toupper is a hacky workaround for the case insensitivity + // in the current UMAPINFO reader. lump names should probably not be + // lowercase ever (?) + *demo_p++ = toupper(mapname[i]); + } + } + // ano - done with the extension format! + if (complevel == MBFVERSION || complevel == MBF21VERSION) { if (complevel == MBF21VERSION) @@ -3051,8 +3179,6 @@ void G_BeginRecording(void) *demo_p++ = compatibility; // killough 2/22/98 } - demo_version = complevel; - *demo_p++ = gameskill; *demo_p++ = gameepisode; *demo_p++ = gamemap;