diff --git a/RP_L4/RPL4LOBBY.cpp b/RP_L4/RPL4LOBBY.cpp index b79e916..f8ece7b 100644 --- a/RP_L4/RPL4LOBBY.cpp +++ b/RP_L4/RPL4LOBBY.cpp @@ -36,7 +36,10 @@ void RPL4Lobby_PullRaceResults() { } namespace { - enum { kMaxLobbyMembers = 4 }; + // A full grid is eight pods, as the pod hall ran it. The egg builder + // carries the owner plus maxExtraPilots (8), so eight members fit + // with room to spare. + enum { kMaxLobbyMembers = 8 }; const char kLobbyTagKey[] = "rp412"; const char kGoKey[] = "go"; @@ -379,7 +382,6 @@ namespace -1, &title, DT_CENTER | DT_TOP | DT_SINGLELINE); SelectObject(mem, room->textFont); - int row_h = client.bottom / 16; // wider than the old middle-half: the right column now carries // full catalog names, and in football three of them int left = client.right / 6; @@ -387,23 +389,9 @@ namespace char text[128]; //--------------------------------------------------------------- - // The host's setup, under the title: the track on its own line, - // then the conditions. Everyone flies the owner's picks, so this - // is the one thing in the room nobody can see for themselves. - // - // Drawn full width rather than the roster's middle half, because - // track names run long ("Berserker's Bahnzai"), and the roster - // then starts below whatever this took - two extra lines above a - // fixed roster top would have run into the first player. - //--------------------------------------------------------------- - int top = client.bottom / 4; - - //--------------------------------------------------------------- - // The buttons are laid out upward from the bottom edge, so the - // setup lines are only affordable if the roster and its hint - // still clear the topmost one. Work out the room first and take - // as many lines as fit - the map alone is worth more than the - // conditions, so it goes first and drops last. + // The buttons are laid out upward from the bottom edge while the + // roster runs down from the top, so everything between the title + // and the topmost button has to share one band. //--------------------------------------------------------------- int ceiling = client.bottom; if (FootballLobby() && room->teamRect.top > 0) @@ -419,16 +407,67 @@ namespace ceiling = room->leaveRect.top; } - int setup_top = title.bottom + row_h / 4; - // the fixed block below: four roster slots, a gap, and the hint, - // plus the half row this block leaves above the roster - int block = kMaxLobbyMembers * row_h + row_h / 2 + row_h; - int setup_lines = - (ceiling - block - setup_top - row_h / 2) / row_h; - if (setup_lines > 2) + //--------------------------------------------------------------- + // Size the rows to that band rather than to a fixed fraction of + // the window: a full lobby is eight players, and eight rows at a + // sixteenth each would run off the bottom of every window we + // support. Counted in half rows, the band holds + // + // setup lines + gap + kMaxLobbyMembers rows + gap + hint + // + // so the row height falls out of the space actually available. + // It never grows past the old sixteenth (a two-player lobby + // should not have circus-sized rows) and never shrinks below the + // font, which is what would actually break - overlapping text. + //--------------------------------------------------------------- + // tmHeight already includes the font's own leading, so a row that + // tall cannot clip or collide - asking for more than that just + // costs setup lines the room would rather keep. + TEXTMETRICA metrics; + GetTextMetricsA(mem, &metrics); + int min_row = metrics.tmHeight + 2; + int max_row = client.bottom / 16; + + int setup_top = title.bottom + client.bottom / 64; + int band = ceiling - setup_top; + + int setup_lines = 2; + int row_h = 0; + for (;;) { - setup_lines = 2; + // halves: setup, half gap, roster, half gap, hint + int halves = 2 * setup_lines + 1 + 2 * kMaxLobbyMembers + 1 + 2; + row_h = (2 * band) / halves; + if (row_h >= min_row || setup_lines == 0) + { + break; + } + --setup_lines; // buy room back from the setup lines } + if (row_h > max_row) row_h = max_row; + if (row_h < 12) row_h = 12; + + //--------------------------------------------------------------- + // On a window too short to give eight rows the room the standard + // font wants, draw this block smaller rather than letting the + // rows overlap each other or run under the buttons. Nobody plays + // at that size, but a squeezed roster still has to be readable. + //--------------------------------------------------------------- + HFONT squeezed = NULL; + HFONT previous = NULL; + if (row_h < min_row) + { + squeezed = CreateFontA(-(row_h * 2 / 3), 0, 0, 0, FW_NORMAL, + FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, + CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, + FIXED_PITCH | FF_MODERN, "Consolas"); + if (squeezed != NULL) + { + previous = (HFONT) SelectObject(mem, squeezed); + } + } + + int top = setup_top; const char *map_name = LobbyText(kMapKey); if (map_name[0] != '\0' && setup_lines > 0) @@ -534,6 +573,13 @@ namespace : "Waiting for the host to launch...", -1, &hint, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + // back to the room font for the buttons, which have their own room + if (squeezed != NULL) + { + SelectObject(mem, previous); + DeleteObject(squeezed); + } + HBRUSH frame = CreateSolidBrush(kGreenBright); //