pkgsrc-WIP-changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

doomlegacy-devel: Full UMAPINFO support



Module Name:	pkgsrc-wip
Committed By:	Michael Baeuerle <micha%NetBSD.org@localhost>
Pushed By:	micha
Date:		Fri Mar 24 12:08:29 2023 +0100
Changeset:	0b28f792144f2c9d4241b70f0ab6e2da9281c68d

Modified Files:
	doomlegacy-devel/TODO
	doomlegacy-devel/distinfo
	doomlegacy-devel/files/umapinfo.c
	doomlegacy-devel/files/umapinfo.h
	doomlegacy-devel/patches/patch-src_f__finale.c
	doomlegacy-devel/patches/patch-src_g__game.c
	doomlegacy-devel/patches/patch-src_p__info.c
	doomlegacy-devel/patches/patch-src_w__wad.c
	doomlegacy-devel/patches/patch-src_wi__stuff.c
Added Files:
	doomlegacy-devel/patches/patch-src_d__main.c
	doomlegacy-devel/patches/patch-src_m__menu.c
	doomlegacy-devel/patches/patch-src_p__enemy.c

Log Message:
doomlegacy-devel: Full UMAPINFO support

To see a diff of this commit:
https://wip.pkgsrc.org/cgi-bin/gitweb.cgi?p=pkgsrc-wip.git;a=commitdiff;h=0b28f792144f2c9d4241b70f0ab6e2da9281c68d

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

diffstat:
 doomlegacy-devel/TODO                          |   4 +-
 doomlegacy-devel/distinfo                      |  13 +-
 doomlegacy-devel/files/umapinfo.c              | 274 +++++++++++++++----------
 doomlegacy-devel/files/umapinfo.h              |  29 +--
 doomlegacy-devel/patches/patch-src_d__main.c   |  15 ++
 doomlegacy-devel/patches/patch-src_f__finale.c |  39 +++-
 doomlegacy-devel/patches/patch-src_g__game.c   |  33 ++-
 doomlegacy-devel/patches/patch-src_m__menu.c   | 100 +++++++++
 doomlegacy-devel/patches/patch-src_p__enemy.c  | 200 ++++++++++++++++++
 doomlegacy-devel/patches/patch-src_p__info.c   | 106 +++++++---
 doomlegacy-devel/patches/patch-src_w__wad.c    |  28 ++-
 doomlegacy-devel/patches/patch-src_wi__stuff.c | 267 +++++++++++++++++++++++-
 12 files changed, 910 insertions(+), 198 deletions(-)

diffs:
diff --git a/doomlegacy-devel/TODO b/doomlegacy-devel/TODO
index 7e4633113e..6cda9c720c 100644
--- a/doomlegacy-devel/TODO
+++ b/doomlegacy-devel/TODO
@@ -10,8 +10,8 @@ Part 25: Add UMAPINFO support
 =============================
 [X] Based on libdoom-umapinfo-1.0.0
     => Module to parse and import data added
-[ ] Hook keys into game engine
-    => All keys except 'enterpic', "emenu' and 'bossactions' should work now
+[X] Hook keys into game engine
+    => All keys should work now, up to the limits of the engine
 
 
 EOF
diff --git a/doomlegacy-devel/distinfo b/doomlegacy-devel/distinfo
index 714741f84c..8fe4448f02 100644
--- a/doomlegacy-devel/distinfo
+++ b/doomlegacy-devel/distinfo
@@ -6,14 +6,17 @@ Size (doomlegacy_1.48.12_common.zip) = 1055689 bytes
 SHA1 (patch-make__options__nix) = 666e4242f07d4d3e42da3b395cf95f07ed3b4c70
 SHA1 (patch-src_Makefile) = 7921393b6c4941fd02d9644836991c30b0fb3188
 SHA1 (patch-src_am__map.c) = 14b3c8b70c63778ad043827ab2f0b6f4fe07bcde
+SHA1 (patch-src_d__main.c) = b182f7c74899f63cc85dffca03d4e9450389fb21
 SHA1 (patch-src_d__player.h) = 5975ea8a714aeb10dcecc7fd42fffcb8f9a2e51b
 SHA1 (patch-src_doomstat.h) = baa7387b6271d3064c12e24aaadf40cdb383e395
-SHA1 (patch-src_f__finale.c) = 6de35c080709d6c0fc9e72b46f7c558cc5605de5
+SHA1 (patch-src_f__finale.c) = 675772336bd091ecdcfd32244821b7ae6fc951f6
 SHA1 (patch-src_f__finale.h) = 5ba7ae568be4dd97d06e4724dc7e1907f3a09cd8
-SHA1 (patch-src_g__game.c) = c5168003940fff0bfcf2db1937e217f65a911a4d
-SHA1 (patch-src_p__info.c) = 6f13050349238ccabe02b7c1bb1996c5c971fa31
+SHA1 (patch-src_g__game.c) = 1307a1dc8518646aaca9b136819ddd3e13d2b947
+SHA1 (patch-src_m__menu.c) = 7e8b564800c9b3b75f96dae3d9216f8cd6dc195f
+SHA1 (patch-src_p__enemy.c) = 66627e696d01381e8fd772f4d52e5332bcd2399b
+SHA1 (patch-src_p__info.c) = 9a8061b1d183374f1ea3678c6a0ad762ff12f8bd
 SHA1 (patch-src_p__info.h) = e24772efb6b42ad5b834b1c12477f2a2feb508aa
 SHA1 (patch-src_p__setup.c) = 77ef2316b3d5ac72274ccfcf6bff3229a9245997
-SHA1 (patch-src_w__wad.c) = 237489b5d19e89e36dbf6720467d910cd7b72aa9
+SHA1 (patch-src_w__wad.c) = e410639b34e0b4ac763a41bb5aebaf6993e04d19
 SHA1 (patch-src_w__wad.h) = 683283a32222e96a6472f103d3dc51e7229e4753
-SHA1 (patch-src_wi__stuff.c) = 380fdfc31975cad0624460561142ffa22e1233c4
+SHA1 (patch-src_wi__stuff.c) = f708ff6160762862a00fca9d52219ec649c59dfc
diff --git a/doomlegacy-devel/files/umapinfo.c b/doomlegacy-devel/files/umapinfo.c
index 5d43ff1f95..4296533af6 100644
--- a/doomlegacy-devel/files/umapinfo.c
+++ b/doomlegacy-devel/files/umapinfo.c
@@ -1,4 +1,4 @@
-//----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
 //
 // Copyright(C) 2023 by DooM Legacy Team
 //
@@ -15,7 +15,7 @@
 // DESCRIPTION:
 //      Support for additional map information in UMAPINFO format.
 //
-//----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
 
 // [MB] 2023-01-21: Support for Rev 2.2 added
 //      Description of UMAPINFO lump format:
@@ -42,10 +42,13 @@
 #include "z_zone.h"
 
 
-// UMAPINFO data in local format
-umapinfo_t umapinfo = { NULL };
+// Internal representation of UMAPINFO data (merged from PWADs)
+umapinfo_t umapinfo = { NULL, NULL, false };
 
 
+// -----------------------------------------------------------------------------
+// Memory management
+
 static void *UMI_Malloc(size_t memsize)
 {
     return Z_Malloc(memsize, PU_STATIC, 0);
@@ -59,49 +62,8 @@ static void UMI_Free(void *ptr)
 }
 
 
-static void UMI_InitMapEntry(mapentry_t *entry,
-                             unsigned int episode, unsigned int map)
-{
-    entry->next              = NULL;
-
-    entry->author            = NULL;
-    entry->label             = NULL;
-    entry->levelname         = NULL;
-    entry->intertext         = NULL;
-    entry->intertextsecret   = NULL;
-    entry->interbackdrop     = NULL;
-    entry->intermusic        = NULL;
-    entry->nextmap           = NULL;
-    entry->nextsecret        = NULL;
-    entry->music             = NULL;
-    entry->skytexture        = NULL;
-    entry->levelpic          = NULL;
-    entry->exitpic           = NULL;
-    entry->enterpic          = NULL;
-    entry->endpic            = NULL;
-    entry->emenu             = NULL;
-    entry->bossactions       = NULL;
-    entry->endgame           = unchanged;
-    entry->episode           = episode;
-    entry->map               = map;
-    entry->partime           = 0;
-    entry->emenu_clear       = false;
-    entry->bossactions_clear = false;
-    entry->nointermission    = false;
-    entry->endbunny          = false;
-    entry->endcast           = false;
-}
-
-
-static void UMI_InitBossActionEntry(bossaction_t *entry)
-{
-    entry->next    = NULL;
-
-    entry->thing   = 0;
-    entry->special = 0;
-    entry->tag     = 0;
-}
-
+// -----------------------------------------------------------------------------
+// Constructors and destructors
 
 static void UMI_InitEpisodeMenuEntry(emenu_t *entry)
 {
@@ -128,6 +90,16 @@ static void UMI_DestroyEpisodeMenu(emenu_t *entry)
 }
 
 
+static void UMI_InitBossActionEntry(bossaction_t *entry)
+{
+    entry->next    = NULL;
+
+    entry->thing   = 0;
+    entry->special = 0;
+    entry->tag     = 0;
+}
+
+
 static void UMI_DestroyBossActions(bossaction_t *entry)
 {
     while (NULL != entry)
@@ -140,6 +112,38 @@ static void UMI_DestroyBossActions(bossaction_t *entry)
 }
 
 
+static void UMI_InitMapEntry(mapentry_t *entry,
+                             unsigned int episode, unsigned int map)
+{
+    entry->next              = NULL;
+
+    entry->author            = NULL;
+    entry->label             = NULL;
+    entry->levelname         = NULL;
+    entry->intertext         = NULL;
+    entry->intertextsecret   = NULL;
+    entry->interbackdrop     = NULL;
+    entry->intermusic        = NULL;
+    entry->nextmap           = NULL;
+    entry->nextsecret        = NULL;
+    entry->music             = NULL;
+    entry->skytexture        = NULL;
+    entry->levelpic          = NULL;
+    entry->exitpic           = NULL;
+    entry->enterpic          = NULL;
+    entry->endpic            = NULL;
+    entry->bossactions       = NULL;
+    entry->endgame           = unchanged;
+    entry->episode           = episode;
+    entry->map               = map;
+    entry->partime           = 0;
+    entry->bossactions_clear = false;
+    entry->nointermission    = false;
+    entry->endbunny          = false;
+    entry->endcast           = false;
+}
+
+
 static void UMI_DestroyMaps(mapentry_t *entry)
 {
     while (NULL != entry)
@@ -161,7 +165,6 @@ static void UMI_DestroyMaps(mapentry_t *entry)
         UMI_Free((void*) entry->exitpic);
         UMI_Free((void*) entry->enterpic);
         UMI_Free((void*) entry->endpic);
-        UMI_DestroyEpisodeMenu(entry->emenu);
         UMI_DestroyBossActions(entry->bossactions);
         UMI_Free(entry);
         entry = tmp;
@@ -169,6 +172,9 @@ static void UMI_DestroyMaps(mapentry_t *entry)
 }
 
 
+// -----------------------------------------------------------------------------
+// Access functions for key values
+
 // On error, 0 is returned
 static unsigned int UMI_GetNumber(doom_umi1_ts_state state)
 {
@@ -381,6 +387,9 @@ static void UMI_ReplaceMultiStringClear(doom_umi1_ts_state state,
 }
 
 
+// -----------------------------------------------------------------------------
+// Episode menu
+
 // Returns true on success
 static boolean UMI_PopulateEpisodeMenuEntry(doom_umi1_ts_state state,
                                             emenu_t *entry)
@@ -453,6 +462,7 @@ static boolean UMI_AppendEpisodeMenuEntry(doom_umi1_ts_state state,
             }
             else
             {
+                // Append episode menu entry to list
                 if (NULL == *em)
                     *em = entry;
                 else
@@ -471,6 +481,9 @@ static boolean UMI_AppendEpisodeMenuEntry(doom_umi1_ts_state state,
 }
 
 
+// -----------------------------------------------------------------------------
+// Boss actions
+
 // Returns true on success
 static boolean UMI_PopulateBossActionEntry(doom_umi1_ts_state state,
                                            bossaction_t *entry)
@@ -498,6 +511,7 @@ static boolean UMI_PopulateBossActionEntry(doom_umi1_ts_state state,
 }
 
 
+// Returns true if identifier 'clear' was detected
 static boolean UMI_MergeBossAction(doom_umi1_ts_state state,
                                    bossaction_t** ba, size_t valcount)
 {
@@ -544,11 +558,49 @@ static boolean UMI_MergeBossAction(doom_umi1_ts_state state,
 }
 
 
+// -----------------------------------------------------------------------------
+// Import data
+
+// Check whether map entry object for episode/map already exists
+// If not, create an empty map entry object
+static mapentry_t *UMI_GetMapEntry(unsigned int episode, unsigned int map)
+{
+    mapentry_t *entry      = umapinfo.entry_first;
+    mapentry_t *entry_last = NULL;
+
+    while (NULL != entry)
+    {
+        entry_last = entry;
+        if (episode == entry->episode && map == entry->map)
+            break;
+
+        entry = entry->next;
+    }
+
+    if (NULL == entry)
+    {
+        // Not found, create new entry
+        entry = UMI_Malloc(sizeof(mapentry_t));
+        if (NULL != entry)
+        {
+            UMI_InitMapEntry(entry, episode, map);
+            if (NULL == umapinfo.entry_first)
+                umapinfo.entry_first = entry;
+            else
+                entry_last->next = entry;
+        }
+    }
+
+    return entry;
+}
+
+
 static void UMI_StoreKeyData(doom_umi1_ts_state state, mapentry_t *entry)
 {
-    size_t key      = 0;
-    int    retval   = doom_umi1_ts_key_read(state, NULL, &key);
-    size_t valcount = 0;
+    size_t  key      = 0;
+    int     retval   = doom_umi1_ts_key_read(state, NULL, &key);
+    size_t  valcount = 0;
+    boolean emc      = false;  // Episode menu clear request
 
     if (0 > retval)
     {
@@ -612,12 +664,12 @@ static void UMI_StoreKeyData(doom_umi1_ts_state state, mapentry_t *entry)
             UMI_ReplaceStringMax8(state, &entry->endpic);
             break;
         case DOOM_UMI1_KEY_EPISODE:
-            entry->emenu_clear =
-                UMI_AppendEpisodeMenuEntry(state, &entry->emenu, valcount);
+            // Associated with global episode list (not the map entry object)
+            emc = UMI_AppendEpisodeMenuEntry(state, &umapinfo.emenu, valcount);
             break;
         case DOOM_UMI1_KEY_BOSSACTION:
-            entry->bossactions_clear =
-                UMI_MergeBossAction(state, &entry->bossactions, valcount);
+            if (UMI_MergeBossAction(state, &entry->bossactions, valcount))
+                entry->bossactions_clear = true;
             break;
         case DOOM_UMI1_KEY_ENDGAME:
             entry->endgame = UMI_GetNumber(state) ? enabled : disabled;
@@ -638,38 +690,10 @@ static void UMI_StoreKeyData(doom_umi1_ts_state state, mapentry_t *entry)
             GenPrintf(EMSG_warn, "UMAPINFO: Unknown key ignored\n");
             break;
     }
-}
-
-
-static mapentry_t *UMI_GetMapEntry(unsigned int episode, unsigned int map)
-{
-    mapentry_t *entry      = umapinfo.entry_first;
-    mapentry_t *entry_last = NULL;
-
-    while (NULL != entry)
-    {
-        entry_last = entry;
-        if (episode == entry->episode && map == entry->map)
-            break;
-
-        entry = entry->next;
-    }
-
-    if (NULL == entry)
-    {
-        // Not found, create new entry
-        entry = UMI_Malloc(sizeof(mapentry_t));
-        if (NULL != entry)
-        {
-            UMI_InitMapEntry(entry, episode, map);
-            if (NULL == umapinfo.entry_first)
-                umapinfo.entry_first = entry;
-            else
-                entry_last->next = entry;
-        }
-    }
 
-    return entry;
+    // Store flag that default episode menu must be cleared
+    if (emc)
+       umapinfo.emenu_clear = true;
 }
 
 
@@ -728,6 +752,11 @@ static void UMI_ImportUMapInfo(umapinfo_t *umi, doom_umi1_handle data)
 }
 
 
+// -----------------------------------------------------------------------------
+// API
+
+// Import and merge UMAPINFO lump into current data
+// If parts of the new data are already present, they overwrite the current data
 void UMI_LoadUMapInfoLump(lumpnum_t lumpnum)
 {
     doom_umi1_handle  data = NULL; // libdoom-umapinfo UMAPINFO object handle
@@ -762,11 +791,18 @@ void UMI_LoadUMapInfoLump(lumpnum_t lumpnum)
 
 void UMI_DestroyUMapInfo(void)
 {
+    UMI_DestroyEpisodeMenu(umapinfo.emenu);
+    umapinfo.emenu       = NULL;
+    umapinfo.emenu_clear = false;
+
     UMI_DestroyMaps(umapinfo.entry_first);
     umapinfo.entry_first = NULL;
 }
 
 
+// Extract episode and map numbers from map name
+// For Doom 2 map names zero is returned for episode
+// Returns true on success (numbers are valid)
 boolean UMI_ParseMapName(const char *name, byte *episode, byte *map)
 {
     boolean      result = false;
@@ -795,6 +831,8 @@ boolean UMI_ParseMapName(const char *name, byte *episode, byte *map)
 }
 
 
+// Search for UMAPINFO map entry that matches episode and map parameters
+// NULL is returned if nothing was found
 mapentry_t *UMI_LookupUMapInfo(byte episode, byte map)
 {
     mapentry_t   *entry = umapinfo.entry_first;
@@ -821,60 +859,52 @@ mapentry_t *UMI_LookupUMapInfo(byte episode, byte map)
 }
 
 
-// The function S_AddMusic() will add a "d_" prefix
-const char* UMI_GetMusicLumpName(const char* name)
-{
-    if (('d' == name[0] || 'D' == name[0]) && '_' == name[1])
-        return &name[2];
-    else
-        return name;
-}
-
-
-// Called from: P_SetupLevel()
+// Load UMAPINFO data for current gameepisode/gamemap
 void UMI_Load_LevelInfo(void)
 {
     gamemapinfo = UMI_LookupUMapInfo(gameepisode, gamemap);
 
     // SMMU level info is replaced with UMAPINFO data, where possible
-    if (NULL != gamemapinfo)
+    if (gamemapinfo)
     {
-        // For now only used by COM_MapInfo_f() for the command "mapinfo"
+        // Key author is handled by WI_Draw_LF() and WI_Draw_EL()
+        // Also mapped to info_creator for COM_MapInfo_f()
         if (gamemapinfo->author)
             info_creator = gamemapinfo->author;
 
-        // label and levelname are handled by P_LevelName()
+        // Keys label and levelname are handled by P_LevelName()
 
-        // intertext and intertextsecret are handled by F_StartFinale()
+        // Keys intertext and intertextsecret are handled by F_StartFinale()
 
-        // interbackdrop is handled by F_StartFinale()
+        // Key interbackdrop is handled by F_StartFinale()
 
-        // intermusic is handled by WI_Ticker()
+        // Key intermusic is handled by WI_Ticker()
 
-        // nextmap and nextsecret are handled by G_DoUMapInfo()
+        // Keys nextmap and nextsecret are handled by G_DoUMapInfo()
 
+        // Key music is mapped to info_music
         if (gamemapinfo->music)
             info_music = UMI_GetMusicLumpName(gamemapinfo->music);
 
+        // Key skytexture is mapped to info_skyname
         if (gamemapinfo->skytexture)
             info_skyname = gamemapinfo->skytexture;
 
-        if (gamemapinfo->levelpic)
-            info_levelpic = gamemapinfo->levelpic;
+        // Key levelpic is handled by WI_Draw_LF() and WI_Draw_EL()
 
+        // Key exitpic is mapped to info_interpic
         if (gamemapinfo->exitpic)
             info_interpic = gamemapinfo->exitpic;
 
-        // FIXME: enterpic is not handled yet
-
-        // endpic is handled by F_Drawer()
+        // Key enterpic is handled by WI_Draw_ShowNextLoc()
 
-        // XXX emenu is not handled yet
+        // Key endpic is handled by F_Drawer()
 
-        // XXX bossactions is not handled yet
+        // Key bossactions is handled by A_Bosstype_Death()
 
-        // endgame is handled by G_NextLevel()
+        // Key endgame is handled by G_NextLevel()
 
+        // Key partime is mapped to info_partime
         if (gamemapinfo->partime)
         {
             if ((unsigned int) INT_MAX < gamemapinfo->partime)
@@ -887,12 +917,27 @@ void UMI_Load_LevelInfo(void)
 }
 
 
+// Strip "d_" prefix from lump name, if present
+//�(because the�function�S_AddMusic()�adds�a�"d_"�prefix)
+// Returns a pointer into name
+const char* UMI_GetMusicLumpName(const char* name)
+{
+    if (('d' == name[0] || 'D' == name[0]) && '_' == name[1])
+        return &name[2];
+    else
+        return name;
+}
+
+
 #else  // HAVE_LIBDOOM_UMAPINFO
 
 
 #include "doomincl.h"
 
 
+// -----------------------------------------------------------------------------
+// API stubs (if libdoom-umapinfo is not available)
+
 void UMI_LoadUMapInfoLump(lumpnum_t lumpnum)
 {
     GenPrintf(EMSG_warn, "UMAPINFO: Ignored (libdoom-umapinfo is required)\n");
@@ -923,4 +968,9 @@ void UMI_Load_LevelInfo(void)
 }
 
 
+const�char*�UMI_GetMusicLumpName(const�char*�name)
+{
+    return name;
+}
+
 #endif  // HAVE_LIBDOOM_UMAPINFO
diff --git a/doomlegacy-devel/files/umapinfo.h b/doomlegacy-devel/files/umapinfo.h
index c45a3fb773..7f0ed9f535 100644
--- a/doomlegacy-devel/files/umapinfo.h
+++ b/doomlegacy-devel/files/umapinfo.h
@@ -1,4 +1,4 @@
-//----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
 //
 // Copyright(C) 2023 by DooM Legacy Team
 //
@@ -15,7 +15,7 @@
 // DESCRIPTION:
 //      Support for additional map information in UMAPINFO format.
 //
-//----------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
 
 #ifndef UMAPINFO_H
 #define UMAPINFO_H
@@ -76,13 +76,11 @@ struct mapentry_t
     const char   *exitpic;
     const char   *enterpic;
     const char   *endpic;
-    emenu_t      *emenu;              // Linked list
     bossaction_t *bossactions;        // Linked list
     tristate_t    endgame;            // Can be undefined, false or true
     unsigned int  episode;
     unsigned int  map;
     unsigned int  partime;
-    boolean       emenu_clear;        // Clear all default episode menu entries
     boolean       bossactions_clear;  // Clear all default boss actions
     boolean       nointermission;     // Skip the 'level finished' screen
     boolean       endbunny;           // End game after level, show bunny
@@ -90,42 +88,35 @@ struct mapentry_t
 };
 
 
-typedef struct
+typedef struct umapinfo_t umapinfo_t;
+struct umapinfo_t
 {
     mapentry_t *entry_first;  // Linked list
-} umapinfo_t;
+
+    emenu_t    *emenu;        // Linked list
+    boolean     emenu_clear;  // Clear all default episode menu entries
+};
 
 
-// Current data (merged from PWADs)
 extern umapinfo_t umapinfo;
 
 
-// Import and merge UMAPINFO lump into current data
-// If parts of the new data are already present, they overwrite the current data
 void UMI_LoadUMapInfoLump(lumpnum_t lumpnum);
 
 
-// Destory current data
 void UMI_DestroyUMapInfo(void);
 
 
-// Extract episode and map numbers from map name
-// For Doom 2 map names zero is returned for episode
-// Returns true on success (numbers are valid)
 boolean UMI_ParseMapName(const char *mapname, byte *episode, byte * map);
 
 
-// Search for UMAPINFO map entry that matches episode and map parameters
-// NULL is returned if nothing was found
 mapentry_t *UMI_LookupUMapInfo(byte episode, byte map);
 
 
-// Returns the position after "D_" prefix (if present) or the start of name
-const char* UMI_GetMusicLumpName(const char* name);
+void UMI_Load_LevelInfo(void);
 
 
-// Load UMAPINFO data for current gameepisode/gamemap
-void UMI_Load_LevelInfo(void);
+const char* UMI_GetMusicLumpName(const char* name);
 
 
 #endif  // UMAPINFO_H
diff --git a/doomlegacy-devel/patches/patch-src_d__main.c b/doomlegacy-devel/patches/patch-src_d__main.c
new file mode 100644
index 0000000000..f5d15f72d8
--- /dev/null
+++ b/doomlegacy-devel/patches/patch-src_d__main.c
@@ -0,0 +1,15 @@
+$NetBSD$
+
+--- src/d_main.c.orig	2023-03-19 11:31:58.068883902 +0000
++++ src/d_main.c
+@@ -3570,6 +3570,10 @@ void D_Quit_Save ( quit_severity_e sever
+ void I_Quit (void)
+ {
+     D_Quit_Save( QUIT_normal );
++
++    // [MB] 2023-03-19: Support for UMAPINFO added
++    UMI_DestroyUMapInfo();
++
+     I_Quit_System();  // No Return
+ }
+ 
diff --git a/doomlegacy-devel/patches/patch-src_f__finale.c b/doomlegacy-devel/patches/patch-src_f__finale.c
index a33a3d0f95..a67b322a4d 100644
--- a/doomlegacy-devel/patches/patch-src_f__finale.c
+++ b/doomlegacy-devel/patches/patch-src_f__finale.c
@@ -2,7 +2,7 @@ $NetBSD$
 
 Add support for UMAPINFO.
 
---- src/f_finale.c.orig	2023-01-10 10:38:38.000000000 +0000
+--- src/f_finale.c.orig	2023-02-26 17:42:28.000000000 +0000
 +++ src/f_finale.c
 @@ -75,8 +75,8 @@ int             finalecount;
  #define TEXTSPEED       3
@@ -85,15 +85,44 @@ Add support for UMAPINFO.
  {
     patch_t*  pic = W_CachePatchName( name, PU_CACHE );  // endian fix
     // Intercept some doom pictures that chex.wad left in (a young kids game).
-@@ -874,7 +899,10 @@ void F_Drawer (void)
+@@ -858,14 +883,14 @@ void F_Drawer (void)
+     // Draw to screen0, scaled
+     V_SetupDraw( 0 | V_SCALESTART | V_SCALEPATCH | V_CENTERHORZ );
+ 
+-    if (finalestage == 2)
++    if( finalestage == 2 )
+     {
+-        F_CastDrawer ();
++        F_CastDrawer();
+         return;
+     }
+ 
+-    if (!finalestage)
+-        F_TextWrite ();
++    if( !finalestage )
++        F_TextWrite();
+     else
+     {
+         if( gamemode == heretic )
+@@ -874,10 +899,13 @@ void F_Drawer (void)
          }
          else
          {
 -           switch (gameepisode)
 +           // [MB] 2023-02-05: Support for UMAPINFO added
-+           if (gamemapinfo && gamemapinfo->endpic)
++           if( gamemapinfo && gamemapinfo->endpic )
 +              F_Draw_interpic_Name( gamemapinfo->endpic );
-+           else switch (gameepisode)
++           else switch( gameepisode )
             {
              case 1:
-               if ( gamemode == ultdoom_retail || gamemode == chexquest1 )
+-              if ( gamemode == ultdoom_retail || gamemode == chexquest1 )
++              if( gamemode == ultdoom_retail || gamemode == chexquest1 )
+                 F_Draw_interpic_Name( text[CREDIT_NUM] );
+               else
+                 F_Draw_interpic_Name( text[HELP2_NUM] );
+@@ -894,5 +922,4 @@ void F_Drawer (void)
+            }
+         }
+     }
+-
+ }
diff --git a/doomlegacy-devel/patches/patch-src_g__game.c b/doomlegacy-devel/patches/patch-src_g__game.c
index dac79bcaa4..e2f19356a3 100644
--- a/doomlegacy-devel/patches/patch-src_g__game.c
+++ b/doomlegacy-devel/patches/patch-src_g__game.c
@@ -2,7 +2,7 @@ $NetBSD$
 
 Add support for UMAPINFO.
 
---- src/g_game.c.orig	2023-01-10 10:38:23.000000000 +0000
+--- src/g_game.c.orig	2023-02-26 17:42:09.000000000 +0000
 +++ src/g_game.c
 @@ -225,6 +225,7 @@ uint16_t        demoversion_rev;  // dem
  skill_e         gameskill;
@@ -12,7 +12,7 @@ Add support for UMAPINFO.
  char            game_map_filename[MAX_WADPATH];      // an external wad filename
  
  
-@@ -2384,10 +2385,74 @@ void G_DoCompleted (void)
+@@ -2384,10 +2385,80 @@ void G_DoCompleted (void)
      automapactive = false;
  }
  
@@ -24,6 +24,7 @@ Add support for UMAPINFO.
 +    boolean result = false;
 +
 +    wminfo.epsd_next   = wminfo.epsd;
++    wminfo.lev_next    = wminfo.lev_prev + 1;
 +    wminfo.lastmapinfo = gamemapinfo;
 +    wminfo.nextmapinfo = NULL;
 +
@@ -32,7 +33,7 @@ Add support for UMAPINFO.
 +        const char *mapname = NULL;
 +        int         i = 0;
 +
-+        // 'nextmap' or 'nextsecret' key overrides default behaviour
++        // Keys nextmap and nextsecret overrides default setup
 +        if (secretexit && gamemapinfo->nextsecret)
 +        {
 +            mapname = gamemapinfo->nextsecret;
@@ -44,7 +45,7 @@ Add support for UMAPINFO.
 +
 +        if (mapname)
 +        {
-+            result = true;
++            result = true;  // UMAPINFO overrides default setup
 +
 +            {
 +                byte e = 0;
@@ -76,6 +77,11 @@ Add support for UMAPINFO.
  {
      int  i;
  
++    // [MB] 2023-01-22: Moved to beginning for G_DoUMapInfo()
++    // 0 based
++    wminfo.epsd     = gameepisode - 1;
++    wminfo.lev_prev = gamemap - 1;
++
 +    // [MB] 2023-01-22: Support for UMAPINFO added
 +    {
 +        boolean skip = G_DoUMapInfo();
@@ -87,7 +93,7 @@ Add support for UMAPINFO.
      if (gamemode != doom2_commercial)
      {
          switch(gamemap)
-@@ -2401,7 +2466,7 @@ void G_Start_Intermission( void )
+@@ -2401,7 +2472,7 @@ void G_Start_Intermission( void )
                  // also for heretic
                  // disconnect from network
                  CL_Reset();
@@ -96,7 +102,7 @@ Add support for UMAPINFO.
                  return;
              }
              break; // [WDJ] 4/11/2012  map 8 is not secret level, and prboom and boom do not fall thru here.
-@@ -2421,7 +2486,7 @@ void G_Start_Intermission( void )
+@@ -2421,7 +2492,7 @@ void G_Start_Intermission( void )
              else
              {
                  CL_Reset();
@@ -105,7 +111,14 @@ Add support for UMAPINFO.
                  return;
              }
          }
-@@ -2436,7 +2501,7 @@ void G_Start_Intermission( void )
+@@ -2429,14 +2500,11 @@ void G_Start_Intermission( void )
+ 
+     if(!dedicated)
+         wminfo.didsecret = consoleplayer_ptr->didsecret;
+-    // 0 based
+-    wminfo.epsd = gameepisode -1;
+-    wminfo.lev_prev = gamemap -1;
+ 
      // go to next level
      // wminfo.lev_next is 0 biased, unlike gamemap
      wminfo.lev_next = gamemap;
@@ -114,7 +127,7 @@ Add support for UMAPINFO.
      // overwrite next level in some cases
      if (gamemode == doom2_commercial)
      {
-@@ -2490,6 +2555,21 @@ void G_Start_Intermission( void )
+@@ -2490,6 +2558,21 @@ void G_Start_Intermission( void )
                  wminfo.lev_next = 0; // wrap around in deathmatch
          }
      }
@@ -136,7 +149,7 @@ Add support for UMAPINFO.
  
      wminfo.maxkills = totalkills;
      wminfo.maxitems = totalitems;
-@@ -2542,6 +2622,16 @@ void G_NextLevel (void)
+@@ -2542,6 +2625,16 @@ void G_NextLevel (void)
              if( gamemap == 30 )
                  wminfo.lev_next = 0; // wrap around in deathmatch
          }
@@ -153,7 +166,7 @@ Add support for UMAPINFO.
          else
          {
              switch (gamemap)
-@@ -2557,7 +2647,7 @@ void G_NextLevel (void)
+@@ -2557,7 +2650,7 @@ void G_NextLevel (void)
                  if( gamemap == 30 )
                      CL_Reset(); // end of game disconnect from server
                  gameaction = ga_nothing;
diff --git a/doomlegacy-devel/patches/patch-src_m__menu.c b/doomlegacy-devel/patches/patch-src_m__menu.c
new file mode 100644
index 0000000000..c93a0065f6
--- /dev/null
+++ b/doomlegacy-devel/patches/patch-src_m__menu.c
@@ -0,0 +1,100 @@
+$NetBSD$
+
+Add support for UMAPINFO.
+
+--- src/m_menu.c.orig	2023-02-26 17:42:09.000000000 +0000
++++ src/m_menu.c
+@@ -6300,6 +6300,83 @@ void M_Init (void)
+     CV_RegisterVar(&cv_oof_2s);
+ }
+ 
++
++// [MB] 2023-03-23: Modify episode menu with data from UMAPINFO
++// If clear is false, the new entries are appended to the existing menu
++static void M_EpisodeMenuFromUMAPINFO (void)
++{
++    boolean   modified = false;
++    emenu_t * episode  = umapinfo.emenu;
++
++    // Accept clear only for the first UMAPINFO map entry
++    if( umapinfo.emenu_clear )
++    {
++        modified        = true;
++        EpiDef.numitems = 0;
++        GenPrintf(EMSG_debug, "UMAPINFO: Default episode menu cleared\n");
++    }
++
++    while( episode )
++    {
++        // UMAPINFO allows 8 episodes, currently only 5 are supported
++        if( EpiDef.numitems < 5 )
++        {
++            // EpisodeMenu[EpiDef.numitems].status is below
++            // FIXME: Cast to char* is ugly
++            // Is it possible to declared elements const in menuitem_t?
++            EpisodeMenu[EpiDef.numitems].patch = (char*)episode->patch;
++            EpisodeMenu[EpiDef.numitems].text  = (char*)episode->name;
++            // EpisodeMenu[EpiDef.numitems].itemaction is not changed
++            if( episode->key[0] )
++            {
++                // UMAPINFO value is defined as quoted string
++                // The first character is used, if string is not empty
++                byte k = (byte)episode->key[0];
++
++                EpisodeMenu[EpiDef.numitems].alphaKey = k;
++            }
++            EpiDef.numitems++;
++            GenPrintf(EMSG_debug, "UMAPINFO: Episode entry added\n");
++        }
++        modified = true;
++        episode  = episode->next;
++    }
++
++    // Use patches only if all episodes have a valid patch
++    if( modified )
++    {
++        boolean  use_patches = true;
++        uint16_t i;
++
++        // FIXME: This should check if the patches are valid too
++        for( i = 0; i < EpiDef.numitems; i++ )
++            if( EpisodeMenu[i].patch == NULL )
++                use_patches = false;
++
++        GenPrintf(EMSG_debug, "UMAPINFO: Modified episode menu ");
++        if( use_patches )
++            GenPrintf(EMSG_debug, "(using patches):\n");
++        else
++            GenPrintf(EMSG_debug, "(using strings):\n");
++
++        for( i = 0; i < EpiDef.numitems; i++ )
++        {
++            GenPrintf(EMSG_debug, "    Episode %u: ", (unsigned int) i + 1u);
++            if( use_patches )
++                GenPrintf(EMSG_debug, "%s\n", EpisodeMenu[i].patch);
++            else
++                GenPrintf(EMSG_debug, "%s\n", EpisodeMenu[i].text);
++
++            EpisodeMenu[i].status = IT_CALL;
++            if( use_patches )
++                EpisodeMenu[i].status |= IT_PATCH;
++            else
++                EpisodeMenu[i].status |= IT_STRING2;
++        }
++    }
++}
++
++
+ // Called once after gamemode has been determined, game dependent
+ void M_Configure (void)
+ {
+@@ -6382,6 +6459,9 @@ void M_Configure (void)
+           cv_nextmap.defaultvalue = "11";
+           // We need to remove the fifth episode.
+           EpiDef.numitems--;
++
++          // [MB] 2023-03-23: Support for UMAPINFO added
++          M_EpisodeMenuFromUMAPINFO();
+           break;
+       case heretic:
+           cv_nextmap.PossibleValue = exmy_cons_t;
diff --git a/doomlegacy-devel/patches/patch-src_p__enemy.c b/doomlegacy-devel/patches/patch-src_p__enemy.c
new file mode 100644
index 0000000000..2c6c4473a4
--- /dev/null
+++ b/doomlegacy-devel/patches/patch-src_p__enemy.c
@@ -0,0 +1,200 @@
+$NetBSD$
+
+--- src/p_enemy.c.orig	2023-02-26 17:42:27.000000000 +0000
++++ src/p_enemy.c
+@@ -3401,6 +3401,66 @@ static state_t *P_FinalState(statenum_t
+     return &states[state];
+ }
+ 
++// [MB] 2023-03-19: Support for UMAPINFO added
++// Helper function for A_Bosstype_Death(), code is now used more than once
++// Returns false if no player is alive
++static boolean A_Player_Alive(void)
++{
++    boolean alive = true;
++    int     i;
++
++    for( i = 0 ; i < MAXPLAYERS ; i++ )
++        if( playeringame[i] && players[i].health > 0 )
++            break;
++
++    if (i == MAXPLAYERS)
++        alive = false;
++
++    return alive;
++}
++
++// [MB] 2023-03-19: Support for UMAPINFO added
++// Helper function for A_Bosstype_Death(), code is now used more than once
++// Parameters are forwarded from A_Bosstype_Death().
++// Returns true if all other bosses (of same type as in parameter mo) are dead
++static boolean A_All_Bosses_Dead(mobj_t* mo, int boss_type)
++{
++    boolean     dead = true;
++    thinker_t*  th;
++    mobj_t*     mo2;
++
++    for( th = thinkercap.next ; th != &thinkercap ; th = th->next )
++    {
++        if( th->function.acp1 != (actionf_p1)P_MobjThinker )
++            continue;
++
++        // Fixes MAP07 bug where if last arachnotron is killed while first
++        // still in death sequence, then both would trigger this code
++        // and the floor would be raised twice (bad).
++        mo2 = (mobj_t *)th;
++        // Check all boss of the same type
++        if ( mo2 != mo
++             && mo2->type == boss_type )
++        {
++            // Check if really dead and finished the death sequence.
++            // [WDJ] Corpse has health < 0.
++            // If two monsters are killed at the same time, this test may occur
++            // while first is corpse and second is not.  But the simple health
++            // test may trigger twice because second monster already has
++            // health < 0 during the first death test.
++            if( mo2->health > 0  // the old test (doom original 1.9)
++                || !(mo2->flags & MF_CORPSE)
++                || mo2->state != P_FinalState(mo2->info->deathstate) )
++            {
++                // other boss not dead
++                dead = false;
++            }
++        }
++    }
++
++    return dead;
++}
++
+ //
+ // A_BossDeath
+ // Possibly trigger special effects
+@@ -3412,13 +3472,73 @@ static state_t *P_FinalState(statenum_t
+ // [WDJ]  Keen death does not have tests for mo->type and thus allows
+ // Dehacked monsters to trigger Keen death and BossDeath effects.
+ // Should duplicate that ability in Doom maps.
+-void A_Bosstype_Death (mobj_t* mo, int boss_type)
++static void A_Bosstype_Death (mobj_t* mo, int boss_type)
+ {
+-    thinker_t*  th;
+-    mobj_t*     mo2;
+-    line_t      lineop;  // operation performed when all bosses are dead.
+-    int         i;
+-   
++    line_t lineop;  // operation performed when all bosses are dead.
++
++    // [MB] 2023-03-19: Support for UMAPINFO added
++    if( gamemapinfo && gamemapinfo->bossactions )
++    {
++        struct bossaction_t*  umi_ba = gamemapinfo->bossactions;
++        boolean               found  = false;
++
++        do
++        {
++            if( boss_type == umi_ba->thing)
++            {
++                found = true;
++                break;
++            }
++            umi_ba = umi_ba->next;
++        }
++        while( umi_ba );
++
++        if( !found )
++            return;
++
++        // DEHEXTRA is not supported
++        if( boss_type > ENDDOOM_MT )
++        {
++            GenPrintf(EMSG_debug,
++                      "UMAPINFO: Thing for bossaction not supported\n");
++            return;
++        }
++
++        if( ! A_All_Bosses_Dead(mo, boss_type) )
++            return;
++
++        // Execute (potentially multiple) actions defined by UMAPINFO
++        umi_ba = gamemapinfo->bossactions;
++        do
++        {
++            if( boss_type == umi_ba->thing)
++            {
++                // FIXME: Is this allowed for the xxxSoecialLine() functions?
++                memset(&lineop, 0, sizeof(line_t));
++                if (umi_ba->special > (unsigned int)SHRT_MAX)
++                    continue;
++                lineop.special = (short)umi_ba->special;
++                if (umi_ba->tag > (unsigned int)UINT16_MAX)
++                    continue;
++                lineop.tag = (uint16_t)umi_ba->tag;
++
++                // Try to use the line first, cross it if not successful
++                if( ! P_UseSpecialLine(mo, &lineop, 0) )
++                    P_CrossSpecialLine(&lineop, 0, mo);
++            }
++            umi_ba = umi_ba->next;
++        }
++        while( umi_ba );
++        return;
++    }
++
++    if( gamemapinfo && gamemapinfo->bossactions_clear )
++    {
++        // Default handling explicitly cleared by UMAPINFO
++        return;
++    }
++
++    // [MB] Default handling starts here
+     if ( gamemode == doom2_commercial)
+     {
+         // Doom2 MAP07: When last Mancubus is dead,
+@@ -3515,45 +3635,14 @@ void A_Bosstype_Death (mobj_t* mo, int b
+ 
+     }
+ 
+-
+     // make sure there is a player alive for victory
+-    for (i=0 ; i<MAXPLAYERS ; i++)
+-        if (playeringame[i] && players[i].health > 0)
+-            break;
+-
+-    if (i==MAXPLAYERS)
++    if( ! A_Player_Alive() )
+         return; // no one left alive, so do not end game
+ 
+     // scan the remaining thinkers to see
+     // if all bosses are dead
+-    for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+-    {
+-        if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+-            continue;
+-
+-        // Fixes MAP07 bug where if last arachnotron is killed while first
+-        // still in death sequence, then both would trigger this code
+-        // and the floor would be raised twice (bad).
+-        mo2 = (mobj_t *)th;
+-        // Check all boss of the same type
+-        if ( mo2 != mo
+-            && mo2->type == boss_type )
+-        {
+-            // Check if really dead and finished the death sequence.
+-            // [WDJ] Corpse has health < 0.
+-            // If two monsters are killed at the same time, this test may occur
+-            // while first is corpse and second is not.  But the simple health
+-            // test may trigger twice because second monster already has
+-            // health < 0 during the first death test.
+-            if( mo2->health > 0  // the old test (doom original 1.9)
+-                || !(mo2->flags & MF_CORPSE)
+-                || mo2->state != P_FinalState(mo2->info->deathstate) )
+-            {
+-                // other boss not dead
+-                goto no_action;
+-            }
+-        }
+-    }
++    if( ! A_All_Bosses_Dead(mo, boss_type) )
++        goto no_action;
+ 
+     // victory!
+     if ( gamemode == doom2_commercial)
diff --git a/doomlegacy-devel/patches/patch-src_p__info.c b/doomlegacy-devel/patches/patch-src_p__info.c
index 71f1d217f0..cf78581a3d 100644
--- a/doomlegacy-devel/patches/patch-src_p__info.c
+++ b/doomlegacy-devel/patches/patch-src_p__info.c
@@ -2,9 +2,19 @@ $NetBSD$
 
 Add support for UMAPINFO.
 
---- src/p_info.c.orig	2023-01-10 10:38:38.000000000 +0000
+--- src/p_info.c.orig	2023-02-26 17:42:27.000000000 +0000
 +++ src/p_info.c
-@@ -150,13 +150,15 @@ static void P_RemoveEqualses(char *line)
+@@ -79,6 +79,9 @@
+ #include "z_zone.h"
+ #include "p_local.h"
+ 
++// [MB] 2023-03-12: Size of static buffers used for names of levels, etc.
++#define NAME_BUFSIZE  50
++
+ //----------------------------------------------------------------------------
+ //
+ // Helper functions
+@@ -150,13 +153,15 @@ static void P_RemoveEqualses(char *line)
  //  '=' sign is optional: all equals signs are internally turned to spaces
  //
  
@@ -25,7 +35,7 @@ Add support for UMAPINFO.
  char *info_nextlevel;
  char *info_nextsecret;
  char *info_intertext = NULL;
-@@ -295,7 +297,10 @@ not_map:
+@@ -295,7 +300,10 @@ not_map:
  
  void P_Clear_LevelVars(void)
  {
@@ -37,7 +47,7 @@ Add support for UMAPINFO.
    info_music = "";
    info_creator = "unknown";
    info_partime = -1;
-@@ -673,7 +678,8 @@ void P_Load_LevelInfo( void )
+@@ -673,7 +681,8 @@ void P_Load_LevelInfo( void )
  
  void COM_MapInfo_f(void)
  {
@@ -47,47 +57,79 @@ Add support for UMAPINFO.
    CONS_Printf("Author: %s\n", info_creator);
  }
  
-@@ -684,12 +690,48 @@ void P_Register_Info_Commands(void)
+@@ -684,12 +693,81 @@ void P_Register_Info_Commands(void)
  }
  
  
--
- char * P_LevelName(void)
- {
--  return levelname;
-+    // [MB] 2023-01-22: Support for UMAPINFO added
-+    if (gamemapinfo && gamemapinfo->levelname)
++// [MB] 2023-03-12: Get label (prefix) for UMAPINFO levelname
++// Helper function for P_LevelName()
++//
++// Returns the length of the label, even if larger than buffer size
++// (but does not write beyond end of buffer).
++static size_t P_LevelName_GetLabel(char * buffer, size_t size)
++{
++    size_t len_label = 0;
++
++    if (size > 0)
 +    {
-+        static char newlevelstr[50];
-+        size_t      remaining = 50 - 1;  // -1 for NUL-termination
++        int len = -1;
 +
-+        newlevelstr[0] = 0;
-+        if (gamemapinfo && gamemapinfo->label)
++        if(gamemapinfo && gamemapinfo->label)
 +        {
-+            // The key 'label' contains a prefix for key 'levelname'
-+            size_t len_label = strlen(gamemapinfo->label);
-+            size_t len_level = strlen(gamemapinfo->levelname);
-+
-+            if (remaining < len_label)
-+                len_label = remaining;
-+            remaining -= len_label;
-+            if (remaining < len_level)
-+                len_level = remaining;
++            // Empty string, if "clear" was specified in UMAPINFO
++            const char * label = gamemapinfo->label;
 +
-+            memcpy(newlevelstr, gamemapinfo->label, len_label);
-+            memcpy(&newlevelstr[len_label], gamemapinfo->levelname, len_level);
-+            newlevelstr[len_label + len_level] = 0;
++            len = snprintf(buffer, size, "%s", label);
 +        }
 +        else
 +        {
-+            size_t len_level = strlen(gamemapinfo->levelname);
++            // Quoted from UMAPINFO specification Rev 2.2 definition of map
++            // entry:
++            // The [episode and map] numbers [...] can exceed their original
++            // limits, though, so MAP50, E5M6 or even MAP100 or E1M10 are valid
++            // map names for their respective game.
++            //
++            // Quoted from UMAPINFO specification Rev 2.2 definition of label:
++            // If not specified the mapname will be used by default followed by
++            // a colon and a space character (e.g. "E1M1: ").
++            unsigned char e = gameepisode;
++            unsigned char m = gamemap;
 +
-+            if (remaining < len_level)
-+                len_level = remaining;
++            if(gamemode == doom2_commercial)
++                len = snprintf(buffer, size, "level %u: ", m);
++            else
++                len = snprintf(buffer, size, "E%uM%u: ", e, m);
 +
-+            memcpy(newlevelstr, gamemapinfo->levelname, len_level);
-+            newlevelstr[len_level] = 0;
 +        }
++
++        if(len > 0)
++           len_label = len;
++    }
++
++    return len_label;
++}
++
+ 
+ char * P_LevelName(void)
+ {
+-  return levelname;
++    // [MB] 2023-01-22: Support for UMAPINFO added
++    if(gamemapinfo && gamemapinfo->levelname)
++    {
++        static char  newlevelstr[NAME_BUFSIZE];
++        size_t       remaining = NAME_BUFSIZE - 1;  // -1 for NUL-termination
++
++        size_t len_label = P_LevelName_GetLabel(newlevelstr, NAME_BUFSIZE);
++        size_t len_level = strlen(gamemapinfo->levelname);
++
++        if(len_label > remaining)
++            len_label = remaining;
++        remaining -= len_label;
++        if(len_level > remaining)
++            len_level = remaining;
++
++        memcpy(&newlevelstr[len_label], gamemapinfo->levelname, len_level);
++        newlevelstr[len_label + len_level] = 0;
 +        return newlevelstr;
 +    }
 +    else
diff --git a/doomlegacy-devel/patches/patch-src_w__wad.c b/doomlegacy-devel/patches/patch-src_w__wad.c
index d82ff37aed..5cbc2788c3 100644
--- a/doomlegacy-devel/patches/patch-src_w__wad.c
+++ b/doomlegacy-devel/patches/patch-src_w__wad.c
@@ -2,26 +2,32 @@ $NetBSD$
 
 Add support for UMAPINFO.
 
---- src/w_wad.c.orig	2023-01-10 10:38:38.711741654 +0000
+--- src/w_wad.c.orig	2023-02-26 17:42:27.000000000 +0000
 +++ src/w_wad.c
-@@ -118,6 +118,7 @@
- #include "d_netfil.h"
- #include "dehacked.h"
-   // DEH_LoadDehackedLump
-+#include "umapinfo.h"
- #include "r_defs.h"
- #include "i_system.h"
+@@ -109,6 +109,9 @@
+ #include <unistd.h>
+   // close, read, lseek
  
-@@ -589,6 +590,8 @@ int W_Load_WadFile ( const char * filena
++// [MB] 2023-03-19: Support for UMAPINFO added
++#include "doomstat.h"
++
+ #include "doomincl.h"
+ #include "w_wad.h"
+ #include "z_zone.h"
+@@ -589,6 +592,12 @@ int W_Load_WadFile ( const char * filena
  
      GenPrintf(EMSG_info, "Added file %s (%i lumps)\n", filenamebuf, numlumps);
      W_Load_DehackedLumps( filenum );
 +    // [MB] 2023-01-10: Process UMAPINFO last for highest priority
-+    W_Load_UMapInfoLumps( filenum );
++    if ( EN_doom_etc )
++    {
++        // UMAPINFO is for Doom only (not seuitable for Heretic and Hexen)
++        W_Load_UMapInfoLumps( filenum );
++    }
  
      return filenum;
  
-@@ -1378,6 +1381,25 @@ void W_Load_DehackedLumps( int wadnum )
+@@ -1378,6 +1387,25 @@ void W_Load_DehackedLumps( int wadnum )
      }
  }
  
diff --git a/doomlegacy-devel/patches/patch-src_wi__stuff.c b/doomlegacy-devel/patches/patch-src_wi__stuff.c
index 16ada6ca43..f06abd204e 100644
--- a/doomlegacy-devel/patches/patch-src_wi__stuff.c
+++ b/doomlegacy-devel/patches/patch-src_wi__stuff.c
@@ -2,9 +2,250 @@ $NetBSD$
 
 Add support for UMAPINFO.
 
---- src/wi_stuff.c.orig	2023-01-29 19:24:45.535984651 +0000
+--- src/wi_stuff.c.orig	2023-02-26 17:42:27.000000000 +0000
 +++ src/wi_stuff.c
-@@ -1986,11 +1986,21 @@ void WI_Ticker(void)
+@@ -481,6 +481,28 @@ void detect_range_violation( int item, i
+ // CODE
+ //
+ 
++
++// [MB] 2023-03-19: Support for UMAPINFO added
++// Moved out of WI_Load_Data() into separate function because with UMAPINFO
++// the LF and EL screens can use different background pictures.
++static void WI_Prepare_Background(void)
++{
++    // Prepare new background from bgname for software renderer
++    if (rendermode == render_soft)
++    {
++        memset(screens[0], 0, vid.screen_size);
++
++        // clear backbuffer from status bar stuff and borders
++        memset(screens[1], 0, vid.screen_size);
++
++        // Draw background on screen1
++        V_SetupDraw(1 | V_SCALESTART | V_SCALEPATCH | V_CENTERHORZ); // screen 1
++        V_DrawScaledPatch(0, 0, W_CachePatchName(bgname, PU_CACHE));
++        V_SetupDraw(drawinfo.prev_screenflags);  // restore
++    }
++}
++
++
+ // slam background
+ // UNUSED static unsigned char *background=0;
+ 
+@@ -523,25 +545,79 @@ static void WI_Draw_LF(void)
+ {
+     // Hardware or software render.
+     patch_t * pp, * pf;
++    int x = 0;
+     int y = WI_TITLEY;
+ 
+-    // draw <LevelName>
+-    if( FontBBaseLump )
++    // [MB] 2023-03-12: Support for UMAPINFO added
++    //
++    // Quoted from UMAPINFO specification Rev 2.2 definition of levelpic:
++    // Specifies the patch that is used on the status screen for 'entering' and
++    // 'finished'. [...]
++    // If not given, the status screen will instead print the map's name with a
++    // suitable font (PrBoom uses STFxxx) to ensure that the proper name is
++    // used. If the author field is set, it will also be shown.
++    if (wbs->lastmapinfo && wbs->lastmapinfo->levelpic)
++    {
++        pp = W_CachePatchName(wbs->lastmapinfo->levelpic, PU_CACHE);
++        pf = V_patch(pp);  // access patch fields
++        x = (BASEVIDWIDTH - pf->width) / 2;
++        V_DrawScaledPatch(x, y, pp);
++
++        y += (5 * pf->height) / 4;
++
++        x = (BASEVIDWIDTH - (V_patch(finished)->width)) / 2;
++        V_DrawScaledPatch(x, y, finished);
++    }
++    else if (wbs->lastmapinfo && wbs->lastmapinfo->levelname)
+     {
+-        V_DrawTextB(P_LevelName(), (BASEVIDWIDTH - V_TextBWidth(P_LevelName()))/2, y);
+-        y += (5*V_TextBHeight(P_LevelName()))/4;
+-        V_DrawTextB("Finished", (BASEVIDWIDTH - V_TextBWidth("Finished"))/2, y);
++        const char * level_string = wbs->lastmapinfo->levelname;
++
++        x = (BASEVIDWIDTH - V_StringWidth(level_string)) / 2;
++        V_DrawString(x, y, V_WHITEMAP, level_string);
++
++        if (wbs->lastmapinfo && wbs->lastmapinfo->author)
++        {
++            const char * author_string = wbs->lastmapinfo->author;
++
++            y += (5 * V_FontInfo()->height) / 4;
++
++            x = (BASEVIDWIDTH - V_StringWidth(author_string)) / 2;
++            V_DrawString(x, y, V_WHITEMAP, author_string);
++        }
++
++        y += 2 * V_FontInfo()->height;
++
++        x = (BASEVIDWIDTH - (V_patch(finished)->width)) / 2;
++        V_DrawScaledPatch(x, y, finished);
+     }
++    // Normal behaviour without UMAPINFO
+     else
+     {
+-        //[segabor]: 'SHORT' BUG !  [WDJ] Patch read does endian conversion
+-        pp = lnames[wbs->lev_prev];
+-        pf = V_patch( pp );  // access patch fields
+-        V_DrawScaledPatch ((BASEVIDWIDTH - pf->width)/2, y, pp);
+-        y += (5 * pf->height)/4;
+-        // draw "Finished!"
+-        V_DrawScaledPatch ((BASEVIDWIDTH - (V_patch(finished)->width))/2,
+-                            y, finished);
++        // draw <LevelName>
++        if (FontBBaseLump)
++        {
++            x = (BASEVIDWIDTH - V_TextBWidth(P_LevelName())) / 2;
++            V_DrawTextB(P_LevelName(), x, y);
++
++            y += (5 * V_TextBHeight(P_LevelName())) / 4;
++
++            x = (BASEVIDWIDTH - V_TextBWidth("Finished")) / 2;
++            V_DrawTextB("Finished", x, y);
++        }
++        else
++        {
++            //[segabor]: 'SHORT' BUG !  [WDJ] Patch read does endian conversion
++            pp = lnames[wbs->lev_prev];
++            pf = V_patch( pp );  // access patch fields
++            x = (BASEVIDWIDTH - pf->width) / 2;
++            V_DrawScaledPatch(x, y, pp);
++
++            y += (5 * pf->height) / 4;
++
++            x = (BASEVIDWIDTH - (V_patch(finished)->width)) / 2;
++            // draw "Finished!"
++            V_DrawScaledPatch(x, y, finished);
++        }
+     }
+ }
+ 
+@@ -552,31 +628,81 @@ static void WI_Draw_EL(void)
+ {
+     // Hardware or software render.
+     patch_t * pp, * pf;
++    int x = 0;
+     int y = WI_TITLEY;
+ 
+-    // draw "Entering"
+-    if( FontBBaseLump )
++    // [MB] 2023-03-12: Support for UMAPINFO added
++    // See WI_Draw_LF() for additional notes.
++    if (wbs->nextmapinfo && wbs->nextmapinfo->levelpic)
+     {
+-        const char * levname = P_LevelNameByNum(wbs->epsd+1, wbs->lev_next+1);
+-        V_DrawTextB("Entering", (BASEVIDWIDTH - V_TextBWidth("Entering"))/2, y);
+-        y += (5*V_TextBHeight("Entering"))/4;
+-        V_DrawTextB( levname, (BASEVIDWIDTH - V_TextBWidth(levname))/2, y);
++        x = (BASEVIDWIDTH - (V_patch(entering)->width)) / 2;
++        V_DrawScaledPatch(x, y, entering);
++
++        y += (5 * V_patch(entering)->height) / 4;
++
++        pp = W_CachePatchName(wbs->nextmapinfo->levelpic, PU_CACHE);
++        pf = V_patch(pp);  // access patch fields
++        x = (BASEVIDWIDTH - pf->width) / 2;
++        V_DrawScaledPatch(x, y, pp);
+     }
+-    else
++    else if (wbs->nextmapinfo && wbs->nextmapinfo->levelname)
+     {
+-        //[segabor]: 'SHORT' BUG !    [WDJ] Patch read does endian conversion
+-        V_DrawScaledPatch((BASEVIDWIDTH - (V_patch(entering)->width))/2,
+-                          y, entering);
+-        // draw level
+-        pp = lnames[wbs->lev_next];
+-        pf = V_patch( pp );  // access patch fields
+-        y += (5 * pf->height)/4;
++        const char * level_string = wbs->nextmapinfo->levelname;
+ 
+-        V_DrawScaledPatch((BASEVIDWIDTH - pf->width)/2, y, pp);
++        x = (BASEVIDWIDTH - (V_patch(entering)->width)) / 2;
++        V_DrawScaledPatch(x, y, entering);
++
++        y += V_patch(entering)->height + V_FontInfo()->height;
++
++        x = (BASEVIDWIDTH - V_StringWidth(level_string)) / 2;
++        V_DrawString(x, y, V_WHITEMAP, level_string);
++
++        if (wbs->nextmapinfo && wbs->nextmapinfo->author)
++        {
++            const char * author_string = wbs->nextmapinfo->author;
++
++            y += (5 * V_FontInfo()->height) / 4;
++
++            x = (BASEVIDWIDTH - V_StringWidth(author_string)) / 2;
++            V_DrawString(x, y, V_WHITEMAP, author_string);
++        }
+     }
++    // Normal behaviour without UMAPINFO
++    else
++    {
++        // draw "Entering"
++        if (FontBBaseLump)
++        {
++            const char * level_string = P_LevelNameByNum(wbs->epsd + 1,
++                                                         wbs->lev_next + 1);
+ 
++            x = (BASEVIDWIDTH - V_TextBWidth("Entering")) / 2;
++            V_DrawTextB("Entering", x, y);
++
++            y += (5 * V_TextBHeight("Entering")) / 4;
++
++            x = (BASEVIDWIDTH - V_TextBWidth(level_string)) / 2;
++            V_DrawTextB(level_string, x, y);
++        }
++        else
++        {
++            //[segabor]: 'SHORT' BUG !  [WDJ] Patch read does endian conversion
++            x = (BASEVIDWIDTH - (V_patch(entering)->width)) / 2;
++            V_DrawScaledPatch(x, y, entering);
++
++            // draw level
++            pp = lnames[wbs->lev_next];
++            pf = V_patch(pp);  // access patch fields
++
++            y += (5 * pf->height) / 4;
++
++            x = (BASEVIDWIDTH - pf->width) / 2;
++            V_DrawScaledPatch(x, y, pp);
++        }
++    }
+ }
+ 
++
+ // [WDJ] Made more resistent to segfault.
+ // Doom YAH draw
+ //  n : YAH index
+@@ -958,6 +1084,13 @@ static void WI_Draw_ShowNextLoc(void)
+     if (cnt<=0)  // all removed no draw !!!
+         return;
+ 
++    // [MB] 2023-03-19: Support for UMAPINFO added
++    if (wbs->nextmapinfo && wbs->nextmapinfo->enterpic)
++    {
++        strcpy(bgname, wbs->nextmapinfo->enterpic);
++        WI_Prepare_Background();
++    }
++
+     WI_Slam_Background();
+ 
+     // draw animated background
+@@ -1977,7 +2110,6 @@ static void WI_checkForAccelerate(void)
+ }
+ 
+ 
+-
+ // Updates stuff each client tick.
+ void WI_Ticker(void)
+ {
+@@ -1986,11 +2118,21 @@ void WI_Ticker(void)
  
      if (bcnt == 1)
      {
@@ -30,3 +271,25 @@ Add support for UMAPINFO.
      }
  
      WI_checkForAccelerate();
+@@ -2097,20 +2239,8 @@ void WI_Load_Data(void)
+         if (wb_epsd == 3)
+             strcpy(bgname,"INTERPIC");
+     }
+-    
+-    
+-    if( rendermode == render_soft )
+-    {
+-        memset(screens[0], 0, vid.screen_size);
+ 
+-        // clear backbuffer from status bar stuff and borders
+-        memset(screens[1], 0, vid.screen_size);
+-  
+-        // Draw background on screen1
+-        V_SetupDraw( 1 | V_SCALESTART | V_SCALEPATCH | V_CENTERHORZ ); // screen 1
+-        V_DrawScaledPatch(0, 0, W_CachePatchName(bgname, PU_CACHE));
+-        V_SetupDraw( drawinfo.prev_screenflags );  // restore
+-    }
++    WI_Prepare_Background();
+ 
+     // UNUSED unsigned char *pic = screens[1];
+     // if (gamemode == doom2_commercial)


Home | Main Index | Thread Index | Old Index