diff --git a/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp b/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp
index a01dabf1..6cadd82e 100644
--- a/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp
+++ b/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp
@@ -669,16 +669,82 @@ static void DispLogDesktopOrder()
// This is the same answer: open every device, put its number on the glass, and let
// the operator read the mapping off the pod instead of deducing it.
//
-// Deliberately uses DDSCL_NORMAL and paints the desktop through GDI. Taking
-// exclusive fullscreen on several devices at once is the very thing that fails on
-// modern Windows, and a diagnostic that trips over the fault it is diagnosing is
-// worthless. Nothing here changes a display mode.
+// Paints through ordinary GDI windows, one per monitor, positioned from the
+// rectangle the device's HMONITOR reports. The first version opened each
+// DirectDraw device with DDSCL_NORMAL and drew on its primary surface; that does
+// not work. Under DDSCL_NORMAL a secondary device's "primary surface" is not that
+// monitor's framebuffer - it either fails to create or resolves to the desktop
+// primary - so on a four-monitor pod every device painted the main screen, each
+// over the last, and only the final colour survived. Nothing here takes exclusive
+// mode or changes a display mode, which was the point of the original design and
+// still holds.
//
+// [tident] Per-window paint data, indexed by the device that owns the window.
+static struct
+{
+ COLORREF cr;
+ char szBig[64];
+ char szLine1[160];
+ char szLine2[192];
+} g_aIdentPaint[8];
+
+static LRESULT CALLBACK IdentWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ PAINTSTRUCT ps;
+ HDC hdc;
+ RECT rc;
+ HBRUSH hBrush;
+ HFONT hFontBig;
+ HFONT hFontSmall;
+ HFONT hOld;
+ int idx;
+ int nHeight;
+
+ if( uMsg!=WM_PAINT )
+ return DefWindowProcA( hWnd, uMsg, wParam, lParam );
+
+ idx=(int)GetWindowLongA( hWnd, GWL_USERDATA );
+ if( idx<0 || idx>7 )
+ idx=0;
+
+ hdc=BeginPaint( hWnd, &ps );
+ GetClientRect( hWnd, &rc );
+ nHeight=rc.bottom-rc.top;
+
+ hBrush=CreateSolidBrush( g_aIdentPaint[idx].cr );
+ FillRect( hdc, &rc, hBrush );
+ DeleteObject( hBrush );
+
+ SetBkMode( hdc, TRANSPARENT );
+ SetTextColor( hdc, RGB(255,255,255) );
+
+ // The number the operator types; everything else is confirmation.
+ hFontBig=CreateFontA( nHeight/2, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY, FF_DONTCARE, "Arial" );
+ hOld=(HFONT)SelectObject( hdc, hFontBig );
+ rc.top=nHeight/8;
+ DrawTextA( hdc, g_aIdentPaint[idx].szBig, -1, &rc, DT_CENTER|DT_TOP|DT_SINGLELINE );
+ SelectObject( hdc, hOld );
+ DeleteObject( hFontBig );
+
+ hFontSmall=CreateFontA( nHeight/16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY, FF_DONTCARE, "Arial" );
+ hOld=(HFONT)SelectObject( hdc, hFontSmall );
+ rc.top=nHeight*3/4;
+ DrawTextA( hdc, g_aIdentPaint[idx].szLine1, -1, &rc, DT_CENTER|DT_TOP|DT_SINGLELINE );
+ rc.top=nHeight*3/4 + nHeight/14;
+ DrawTextA( hdc, g_aIdentPaint[idx].szLine2, -1, &rc, DT_CENTER|DT_TOP|DT_SINGLELINE );
+ SelectObject( hdc, hOld );
+ DeleteObject( hFontSmall );
+
+ EndPaint( hWnd, &ps );
+ return 0;
+}
+
static void IdentifyDisplays()
{
- IDirectDraw7* apDD[8];
- IDirectDrawSurface7* apSurf[8];
- DWORD iDev;
// Distinct fill per device so the panels remain tellable apart from across the
// room, and readable if the font fails to create for any reason.
static const COLORREF acrFill[8] =
@@ -687,7 +753,18 @@ static void IdentifyDisplays()
RGB(120,0,140), RGB(0,120,140), RGB(90,90,90), RGB(180,60,0)
};
static const char* apszRole[6] = { "main", "radar", "span", "span2", "mfd1", "mfd2" };
- int anRoleDev[6];
+ static const char* pszIdentClass = "MW4TIdentWindow";
+ int anRoleDev[6];
+ const char* apszDevRole[8];
+ RECT arcMon[8];
+ int anGroup[8];
+ HWND ahWnd[8];
+ WNDCLASSA wc;
+ DWORD iDev;
+ DWORD dwStart;
+ int iRole;
+ int j;
+ int nWindows=0;
anRoleDev[0]=Environment.FullScreenDevice;
anRoleDev[1]=g_nNonDualHead;
@@ -700,139 +777,161 @@ static void IdentifyDisplays()
DispLog( "Painting each display with its -tmon number. No display mode is changed and\r\n"
"no device takes exclusive mode. The game exits when the display period ends.\r\n\r\n" );
- for( iDev=0; iDev %s\r\n", (int)iDev,
DispLogMonitorName( g_ahDevMonitor[iDev], szMon ) );
-
- hr=wDirectDrawCreateEx( &DeviceArray[iDev].DeviceGUID, (VOID**)&apDD[iDev], IID_IDirectDraw7, NULL );
- if( FAILED(hr) || !apDD[iDev] )
- {
- DispLog( " *** DirectDrawCreateEx failed (0x%08lX) - cannot identify this one ***\r\n",
- (unsigned long)hr );
- apDD[iDev]=0;
- continue;
- }
-
- hr=apDD[iDev]->SetCooperativeLevel( hCoop, DDSCL_NORMAL );
- if( FAILED(hr) )
- {
- DispLog( " *** SetCooperativeLevel(NORMAL) failed (0x%08lX) ***\r\n", (unsigned long)hr );
- continue;
- }
-
- memset( &ddsd, 0, sizeof(ddsd) );
- ddsd.dwSize=sizeof(ddsd);
- ddsd.dwFlags=DDSD_CAPS;
- ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;
- hr=apDD[iDev]->CreateSurface( &ddsd, &apSurf[iDev], NULL );
- if( FAILED(hr) || !apSurf[iDev] )
- {
- DispLog( " *** CreateSurface(primary) failed (0x%08lX) ***\r\n", (unsigned long)hr );
- apSurf[iDev]=0;
- continue;
- }
-
- {
- HDC hdc=NULL;
- const char* pszRole="unused";
- int iRole;
-
- for( iRole=0; iRole<6; iRole++ )
- if( anRoleDev[iRole]==(int)iDev )
- {
- pszRole=apszRole[iRole];
- break;
- }
-
- hr=apSurf[iDev]->GetDC( &hdc );
- if( FAILED(hr) || !hdc )
- {
- DispLog( " *** GetDC failed (0x%08lX) ***\r\n", (unsigned long)hr );
- continue;
- }
-
- {
- RECT rc;
- HBRUSH hBrush;
- HFONT hFontBig;
- HFONT hFontSmall;
- HFONT hOld;
- char szBig[16];
- char szLine[256];
- int nWidth;
- int nHeight;
-
- nWidth =GetDeviceCaps( hdc, HORZRES );
- nHeight=GetDeviceCaps( hdc, VERTRES );
-
- rc.left=0; rc.top=0; rc.right=nWidth; rc.bottom=nHeight;
- hBrush=CreateSolidBrush( acrFill[iDev] );
- FillRect( hdc, &rc, hBrush );
- DeleteObject( hBrush );
-
- SetBkMode( hdc, TRANSPARENT );
- SetTextColor( hdc, RGB(255,255,255) );
-
- // The number the operator types; everything else is confirmation.
- sprintf( szBig, "%d", (int)iDev+1 );
- hFontBig=CreateFontA( nHeight/2, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
- DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
- ANTIALIASED_QUALITY, FF_DONTCARE, "Arial" );
- hOld=(HFONT)SelectObject( hdc, hFontBig );
- rc.top=nHeight/8;
- DrawTextA( hdc, szBig, -1, &rc, DT_CENTER|DT_TOP|DT_SINGLELINE );
- SelectObject( hdc, hOld );
- DeleteObject( hFontBig );
-
- hFontSmall=CreateFontA( nHeight/16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
- DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
- ANTIALIASED_QUALITY, FF_DONTCARE, "Arial" );
- hOld=(HFONT)SelectObject( hdc, hFontSmall );
-
- rc.top=nHeight*3/4;
- sprintf( szLine, "use %d in -tmon", (int)iDev+1 );
- DrawTextA( hdc, szLine, -1, &rc, DT_CENTER|DT_TOP|DT_SINGLELINE );
-
- rc.top=nHeight*3/4 + nHeight/14;
- sprintf( szLine, "device %d currently: %s", (int)iDev, pszRole );
- DrawTextA( hdc, szLine, -1, &rc, DT_CENTER|DT_TOP|DT_SINGLELINE );
-
- SelectObject( hdc, hOld );
- DeleteObject( hFontSmall );
- }
-
- apSurf[iDev]->ReleaseDC( hdc );
- DispLog( " painted: -tmon value %d, currently assigned to %s\r\n",
- (int)iDev+1, pszRole );
- }
}
- DispLog( "\r\n Write down the number on each monitor, then set -tmon in the order\r\n"
- " main,radar,mfd1,mfd2 using those numbers.\r\n" );
- DispLog( " Holding the display for %d seconds...\r\n", g_nIdentSeconds );
-
- Sleep( (DWORD)g_nIdentSeconds * 1000 );
+ // Two devices resolving to the same rectangle are one physical monitor - the
+ // usual cause is a driver exposing a primary alias. One window each would just
+ // overpaint, so they share a window and the label names both numbers.
+ for( iDev=0; iDevRelease();
- if( apDD[iDev] )
- apDD[iDev]->Release();
+ char szNums[64];
+ char szRoles[192];
+ char szTmp[64];
+ int nMembers=0;
+
+ if( anGroup[iDev]!=(int)iDev )
+ continue;
+
+ szNums[0]='\0';
+ szRoles[0]='\0';
+ for( j=0; j<(int)NumDevices && j<8; j++ )
+ {
+ if( anGroup[j]!=(int)iDev )
+ continue;
+ if( nMembers )
+ {
+ strcat( szNums, " & " );
+ strcat( szRoles, " " );
+ }
+ sprintf( szTmp, "%d", j+1 );
+ strcat( szNums, szTmp );
+ sprintf( szTmp, "device %d: %s", j, apszDevRole[j] );
+ strcat( szRoles, szTmp );
+ nMembers++;
+ }
+
+ g_aIdentPaint[iDev].cr=acrFill[iDev];
+ strcpy( g_aIdentPaint[iDev].szBig, szNums );
+ if( nMembers>1 )
+ sprintf( g_aIdentPaint[iDev].szLine1,
+ "one monitor, %d device numbers - either works in -tmon", nMembers );
+ else
+ sprintf( g_aIdentPaint[iDev].szLine1, "use %s in -tmon", szNums );
+ strcpy( g_aIdentPaint[iDev].szLine2, szRoles );
}
+ memset( &wc, 0, sizeof(wc) );
+ wc.lpfnWndProc =IdentWndProc;
+ wc.hInstance =GetModuleHandleA( NULL );
+ wc.hCursor =LoadCursorA( NULL, IDC_ARROW );
+ wc.hbrBackground=NULL;
+ wc.lpszClassName=pszIdentClass;
+ RegisterClassA( &wc );
+
+ for( iDev=0; iDevEverything in this list is a fix -- none of it needs configuring. The console lobby now reads
V5.1.0b3; use that to confirm a pod actually received the new build.
+-tident now actually works. In RC2 it painted a single coloured
+ rectangle on the main screen and nothing on the other monitors, so it could not be used for what
+ it was added for. See section 4.
- Damage paper dolls corrected on 22 'Mechs. The external MFD and Radar damage
displays were showing mirrored or misaligned zones. See section 5.
- Targeting a Zeus showed an Annihilator. Fixed, along with two other 'Mechs whose
@@ -557,9 +560,10 @@ screen (section 4).
- Sound output is two-speaker stereo. Surround and quad speaker rigs are downmixed.
This is how the game has always behaved; making use of more speakers is being investigated for a
later release.
--tident is only meaningful on a machine with more than one monitor. On a
- single-screen test PC it may briefly paint one number over another, because Windows can present a
- single monitor to the game as two devices. Harmless, and it cannot happen on a real pod.
+- If two device numbers land on one monitor,
-tident now says so rather
+ than painting one number over the other. The monitor shows both numbers, e.g. 1 & 2,
+ and either may be used in -tmon. This happens when a driver presents one monitor to the
+ game as two devices, which is common on single-screen test PCs and does not occur on a pod.
11. Upgrade checklist
diff --git a/RELEASE-NOTES-5.1.0b_RC3.md b/RELEASE-NOTES-5.1.0b_RC3.md
index 6618905d..3d962c7f 100644
--- a/RELEASE-NOTES-5.1.0b_RC3.md
+++ b/RELEASE-NOTES-5.1.0b_RC3.md
@@ -15,6 +15,9 @@ match printer.
Everything in this list is a fix -- none of it needs configuring. The console lobby now reads
**`V5.1.0b3`**; use that to confirm a pod actually received the new build.
+- **`-tident` now actually works.** In RC2 it painted a single coloured rectangle on the main
+ screen and nothing on the other monitors, so it could not be used for what it was added for.
+ See section 4.
- **Damage paper dolls corrected on 22 'Mechs.** The external MFD and Radar damage displays
were showing mirrored or misaligned zones. See section 5.
- **Targeting a Zeus showed an Annihilator.** Fixed, along with two other 'Mechs whose target
@@ -605,9 +608,10 @@ screen (section 4).
- **Sound output is two-speaker stereo.** Surround and quad speaker rigs are downmixed. This is
how the game has always behaved; making use of more speakers is being investigated for a
later release.
-- **`-tident` is only meaningful on a machine with more than one monitor.** On a single-screen
- test PC it may briefly paint one number over another, because Windows can present a single
- monitor to the game as two devices. Harmless, and it cannot happen on a real pod.
+- **If two device numbers land on one monitor, `-tident` now says so** rather than painting one
+ number over the other. The monitor shows both numbers, e.g. `1 & 2`, and either may be used in
+ `-tmon`. This happens when a driver presents one monitor to the game as two devices, which is
+ common on single-screen test PCs and does not occur on a pod.
---
diff --git a/testing-checklist-5.1.0b_RC3.txt b/testing-checklist-5.1.0b_RC3.txt
index 76e4329c..c727b05b 100644
--- a/testing-checklist-5.1.0b_RC3.txt
+++ b/testing-checklist-5.1.0b_RC3.txt
@@ -138,13 +138,23 @@ Added 2026-07-23 (commit 5813aeb6)
Added for RC2 (2026-07-25 through 2026-08-07)
------------------------------------------------
-12. -tident DISPLAY IDENTIFY MODE (new switch)
+12. -tident DISPLAY IDENTIFY MODE
MW4.exe -tident [3..120, default 20] paints every display with a colour,
its -tmon number, its DirectDraw device index and its current role, then
- exits. Uses DDSCL_NORMAL + GDI: no exclusive mode, no display mode change.
+ exits. No exclusive mode, no display mode change.
- [ ] MW4.exe -tident on a 4-monitor pod: every monitor shows a distinct
- colour and a large number; no monitor is left on the desktop
+ REWRITTEN FOR RC3 -- in RC2 this did not work. It opened each DirectDraw
+ device with DDSCL_NORMAL and drew on the device's primary surface, but a
+ secondary device's primary surface under DDSCL_NORMAL is not that monitor's
+ framebuffer, so on a 4-monitor pod every device painted the MAIN screen in
+ turn and only the last survived. Observed symptom: one green rectangle on
+ the main monitor, nothing anywhere else. It now creates one borderless
+ topmost GDI window per monitor, positioned from that device's monitor
+ rectangle, and runs a real message pump so the windows actually paint.
+
+ [ ] MW4.exe -tident on a 4-monitor pod: ALL FOUR monitors are covered, each
+ a different colour with a large number. This is the RC2 regression --
+ check it first
[ ] The role shown on each monitor (main / radar / mfd1 / mfd2) matches
what that monitor actually displays during a mission
[ ] The game exits on its own when the timer expires, and does NOT start
@@ -153,8 +163,15 @@ Added for RC2 (2026-07-25 through 2026-08-07)
and monitor arrangement as before (nothing to restore by hand)
[ ] Works on a pod where the MFD modes are currently failing (that is the
case it exists for)
- [ ] Everything painted on screen also appears in gos-displays.txt
+ [ ] Everything painted on screen also appears in gos-displays.txt, including
+ the new "N window(s) shown across M device(s)" line
+ [ ] gos-displays.txt reports a painted line per monitor with its pixel size
+ and desktop position, and those match the physical layout
[ ] Typing those numbers into -tmon puts each panel on the intended monitor
+ [ ] On a SINGLE-monitor test PC (not a pod): if the driver presents one
+ monitor as two devices, one window appears showing both numbers, e.g.
+ "1 & 2", rather than two windows overpainting. gos-displays.txt says
+ "shares a monitor with device N"
13. gos-displays.txt FULL START-UP TRACE
Startup-only logging; no frame-loop cost. File is truncated each launch.