Front end: post-mission results screen (kills/deaths scoreboard)
Completes the marshal chain: menu -> mission -> timed stop -> results -> relaunch. BT had no mission-end score flow; this builds one from the data the Comm MFD pilotList already tracks. - btl4console: at the timed stop (game thread, state still live) snapshot each roster pilot's kills/deaths via the BTResolveRosterPilot / BTPilotKills / BTPilotDeaths bridges; expose BTLocalConsole_ResultCount / GetResult. - btl4fe: BTFrontEnd_ShowResults -- a GDI green-on-black 'MISSION COMPLETE' scoreboard (PILOT / KILLS / DEATHS, slot 0 named from the menu), any key or ~12s to dismiss; store the last pilot name. - btl4main: show the scoreboard after a marshaled mission, before the relaunch. Verified: MISSION COMPLETE screen renders with the pilot row and the snapshotted score (0/0 on a no-combat test run; the data path is the same one the live Comm MFD reads). Phase 5 (front end) COMPLETE: menu + egg builder + marshal + timed stop + results + single-binary (relaunch) loop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,8 @@
|
||||
#include "l4app.hpp" // L4Application::SetEggNotationFileName
|
||||
|
||||
// Mission length (seconds) chosen on the last LAUNCH; WinMain arms the marshal.
|
||||
static int gLastMissionSeconds = 300;
|
||||
static int gLastMissionSeconds = 300;
|
||||
static char gLastPilotName[24] = "Pilot";
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
// Catalogs -- the BattleTech content the console's RPConfig.xml named.
|
||||
@@ -633,6 +634,7 @@ int BTFrontEnd_Run()
|
||||
strcpy(mission.weather, kMenuWeather[selWx].key);
|
||||
mission.lengthSeconds = kMenuLengths[selLen].seconds;
|
||||
strcpy(mission.pilots[0].name, pilotName);
|
||||
strncpy(gLastPilotName, pilotName, sizeof(gLastPilotName) - 1);
|
||||
strcpy(mission.pilots[0].vehicle, kMenuMechs[selMech].key);
|
||||
strcpy(mission.pilots[0].color, kMenuColors[selColor].key);
|
||||
|
||||
@@ -648,3 +650,103 @@ int BTFrontEnd_LastMissionSeconds()
|
||||
{
|
||||
return gLastMissionSeconds;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// THE RESULTS SCREEN -- shown after a marshaled mission, before the relaunch.
|
||||
// A GDI green-on-black scoreboard reading the marshal's snapshotted scores
|
||||
// (kills/deaths per roster slot; slot 0 = the local pilot, named from the
|
||||
// menu). Dismissed by any key/click or after a timeout.
|
||||
//===========================================================================//
|
||||
namespace { HWND gResultsWin = NULL; int gResultsDone = 0; }
|
||||
|
||||
extern int BTLocalConsole_ResultCount();
|
||||
extern int BTLocalConsole_GetResult(int index, int *kills, int *deaths);
|
||||
|
||||
namespace {
|
||||
LRESULT CALLBACK ResultsWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
|
||||
switch (msg) {
|
||||
case WM_PAINT: {
|
||||
PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps);
|
||||
RECT cl; GetClientRect(hwnd, &cl);
|
||||
HDC mem = CreateCompatibleDC(hdc);
|
||||
HBITMAP surf = CreateCompatibleBitmap(hdc, cl.right, cl.bottom);
|
||||
HBITMAP old = (HBITMAP) SelectObject(mem, surf);
|
||||
FillRect(mem, &cl, (HBRUSH) GetStockObject(BLACK_BRUSH));
|
||||
SetBkMode(mem, TRANSPARENT);
|
||||
int th = cl.bottom / 22; if (th < 16) th = 16; if (th > 28) th = 28;
|
||||
HFONT big = CreateFontA(-(th*2),0,0,0,FW_BOLD,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
|
||||
CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH|FF_MODERN,"Consolas");
|
||||
HFONT reg = CreateFontA(-th,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
|
||||
CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH|FF_MODERN,"Consolas");
|
||||
const COLORREF gB = RGB(64,255,64), gD = RGB(24,140,24);
|
||||
SelectObject(mem, big); SetTextColor(mem, gB);
|
||||
RECT t = cl; t.top = cl.bottom/12; t.bottom = t.top + th*3;
|
||||
DrawTextA(mem, "M I S S I O N C O M P L E T E", -1, &t, DT_CENTER|DT_TOP|DT_SINGLELINE);
|
||||
SelectObject(mem, reg);
|
||||
int y = cl.bottom/4; int cxN = cl.right/6, cxK = cl.right/2, cxD = (cl.right*2)/3;
|
||||
SetTextColor(mem, gB);
|
||||
RECT h; h.top=y; h.bottom=y+th*2;
|
||||
h.left=cxN; h.right=cxK; DrawTextA(mem,"PILOT",-1,&h,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
|
||||
h.left=cxK; h.right=cxD; DrawTextA(mem,"KILLS",-1,&h,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
|
||||
h.left=cxD; h.right=cl.right; DrawTextA(mem,"DEATHS",-1,&h,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
|
||||
y += th*2;
|
||||
int n = BTLocalConsole_ResultCount();
|
||||
if (n <= 0) n = 1; // always show the local pilot line
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int k = 0, d = 0; BTLocalConsole_GetResult(i, &k, &d);
|
||||
char name[24]; if (i == 0) strncpy(name, gLastPilotName, sizeof(name)-1), name[sizeof(name)-1]=0;
|
||||
else sprintf(name, "Pilot %d", i + 1);
|
||||
char kb[8], db[8]; sprintf(kb, "%d", k); sprintf(db, "%d", d);
|
||||
SetTextColor(mem, i == 0 ? gB : gD);
|
||||
RECT r; r.top=y; r.bottom=y+th*2;
|
||||
r.left=cxN; r.right=cxK; DrawTextA(mem,name,-1,&r,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
|
||||
r.left=cxK; r.right=cxD; DrawTextA(mem,kb,-1,&r,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
|
||||
r.left=cxD; r.right=cl.right; DrawTextA(mem,db,-1,&r,DT_LEFT|DT_VCENTER|DT_SINGLELINE);
|
||||
y += th*2;
|
||||
}
|
||||
SetTextColor(mem, gD);
|
||||
RECT f = cl; f.top = cl.bottom - th*3; f.bottom = cl.bottom - th;
|
||||
DrawTextA(mem, "press any key", -1, &f, DT_CENTER|DT_TOP|DT_SINGLELINE);
|
||||
BitBlt(hdc, 0,0, cl.right, cl.bottom, mem, 0,0, SRCCOPY);
|
||||
SelectObject(mem, old); DeleteObject(surf); DeleteDC(mem);
|
||||
DeleteObject(big); DeleteObject(reg);
|
||||
EndPaint(hwnd, &ps); return 0; }
|
||||
case WM_KEYDOWN: case WM_LBUTTONDOWN: gResultsDone = 1; return 0;
|
||||
case WM_CLOSE: gResultsDone = 1; return 0;
|
||||
}
|
||||
return DefWindowProcA(hwnd, msg, wp, lp);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Show the scoreboard until dismissed (or ~12s timeout). Returns always.
|
||||
void BTFrontEnd_ShowResults()
|
||||
{
|
||||
HINSTANCE instance = GetModuleHandleA(NULL);
|
||||
static int reg = 0;
|
||||
if (!reg) { reg = 1;
|
||||
WNDCLASSA wc; memset(&wc,0,sizeof(wc));
|
||||
wc.lpfnWndProc = ResultsWndProc; wc.hInstance = instance;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
|
||||
wc.lpszClassName = "BTResults";
|
||||
RegisterClassA(&wc);
|
||||
}
|
||||
int W = 800, H = 560;
|
||||
int sx = (GetSystemMetrics(SM_CXSCREEN) - W) / 2;
|
||||
int sy = (GetSystemMetrics(SM_CYSCREEN) - H) / 2;
|
||||
gResultsDone = 0;
|
||||
gResultsWin = CreateWindowExA(0, "BTResults", "BattleTech",
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE, sx<0?0:sx, sy<0?0:sy, W, H, NULL, NULL, instance, NULL);
|
||||
if (gResultsWin == NULL) return;
|
||||
SetForegroundWindow(gResultsWin);
|
||||
DWORD deadline = GetTickCount() + 12000;
|
||||
MSG msg;
|
||||
while (!gResultsDone && GetTickCount() < deadline) {
|
||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
if (msg.message == WM_KEYDOWN || msg.message == WM_QUIT) gResultsDone = 1;
|
||||
TranslateMessage(&msg); DispatchMessageA(&msg);
|
||||
}
|
||||
Sleep(15);
|
||||
}
|
||||
DestroyWindow(gResultsWin); gResultsWin = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user