After a console-marshaled race ends, the race loop now shows a RACE RESULTS screen (place / pilot / final score, sorted descending, with a CONTINUE button) before returning to the setup menu. Scores come from the local console's intake; single-player rows carry the pilot's own name, additional pods show their host number until the Steam roster maps IDs to personas. The setup menu also keeps the player's selections and pilot name across races now instead of resetting to defaults each cycle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1193 lines
33 KiB
C++
1193 lines
33 KiB
C++
#include "..\munga_l4\mungal4.h"
|
|
#pragma hdrstop
|
|
|
|
#include "rpl4fe.h"
|
|
#include "rpl4console.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string>
|
|
|
|
//########################################################################
|
|
// The Death Race catalog (from TeslaConsole's RedPlanet/RPConfig.xml;
|
|
// 'headmf' is excluded for the race scenario there).
|
|
//########################################################################
|
|
|
|
namespace
|
|
{
|
|
struct CatalogEntry
|
|
{
|
|
const char *key;
|
|
const char *name;
|
|
};
|
|
|
|
const CatalogEntry kMaps[] =
|
|
{
|
|
{ "wise", "Wiseguy's Wake" },
|
|
{ "lyzlane", "Lyz's Lane" },
|
|
{ "yip", "Yip's Yahoorama" },
|
|
{ "blade", "Blade's Edge" },
|
|
{ "otto", "Berserker's Bahnzai" },
|
|
{ "frstrm", "Firestorm's Fury" },
|
|
{ "burnt", "Burnt Cookies" },
|
|
{ "brewers", "Brewer's Bane" },
|
|
{ "pain", "Paingod's Passage" },
|
|
{ "headoff", "Freezemoon's Freeway" },
|
|
};
|
|
|
|
const CatalogEntry kVehicles[] =
|
|
{
|
|
{ "quark", "Quark" },
|
|
{ "lepton", "Lepton" },
|
|
{ "proton", "Proton" },
|
|
{ "bug", "Bug" },
|
|
{ "speck", "Speck" },
|
|
{ "blkspk", "Black Speck" },
|
|
{ "chigger", "Chigger" },
|
|
{ "flea", "Flea" },
|
|
{ "roach", "Roach" },
|
|
{ "skeeter", "Skeeter" },
|
|
{ "wasp", "Wasp" },
|
|
{ "barge", "Barge" },
|
|
{ "broccoli", "Screaming Broccoli" },
|
|
{ "burro", "Burro" },
|
|
{ "mule", "Mule" },
|
|
{ "bttlbrg", "Battle Barge" },
|
|
{ "gator", "Gator" },
|
|
{ "grunt", "Grunt" },
|
|
{ "vole", "Vole" },
|
|
{ "bull", "Bull" },
|
|
{ "tarntula", "Tarantula" },
|
|
{ "mantis", "Mantis" },
|
|
{ "ripper", "Ripper" },
|
|
{ "roadblk", "Road Block" },
|
|
{ "spitter", "Spitter" },
|
|
{ "puck", "Armadillo" },
|
|
{ "dragon", "Dragon" },
|
|
};
|
|
|
|
const CatalogEntry kColors[] =
|
|
{
|
|
{ "Red", "Red" }, { "Blue", "Blue" }, { "Green", "Green" },
|
|
{ "White", "White" }, { "Pink", "Pink" }, { "Aqua", "Aqua" },
|
|
{ "Yellow", "Yellow" }, { "Purple", "Purple" }, { "Black", "Black" },
|
|
};
|
|
|
|
const CatalogEntry kBadges[] =
|
|
{
|
|
{ "None", "None" }, { "Celtic", "Celtic" }, { "Desert", "Desert" },
|
|
{ "Flames", "Flames" }, { "Giraffe", "Giraffe" }, { "Hawaii", "Hawaii" },
|
|
{ "Korean", "Korean Camo" }, { "Lightning", "Lightning" },
|
|
{ "Razzle Dazzle", "Razzle Dazzle" }, { "Rising Sun", "Rising Sun" },
|
|
{ "Tiger Stripe", "Tiger Stripes" },
|
|
};
|
|
|
|
const CatalogEntry kTimes[] =
|
|
{
|
|
{ "day", "Day" }, { "night", "Night" },
|
|
};
|
|
|
|
const CatalogEntry kWeather[] =
|
|
{
|
|
{ "clear", "Clear" }, { "fog", "Light Fog" }, { "soup", "Heavy Fog" },
|
|
};
|
|
|
|
struct LengthEntry
|
|
{
|
|
int seconds; // 0 = endless (length line omitted)
|
|
const char *name;
|
|
};
|
|
|
|
const LengthEntry kLengths[] =
|
|
{
|
|
{ 0, "Endless" },
|
|
{ 180, "3:00" },
|
|
{ 300, "5:00" },
|
|
{ 480, "8:00" },
|
|
{ 600, "10:00" },
|
|
};
|
|
|
|
// Standalone pilot address, as used by TEST.EGG: single-user mode
|
|
// adopts the first pilot entry without resolving it.
|
|
const char kLocalPilotAddress[] = "200.0.0.255";
|
|
|
|
#define FE_COUNT(t) ((int)(sizeof(t)/sizeof((t)[0])))
|
|
|
|
//---------------------------------------------------------------
|
|
// Menu model
|
|
//---------------------------------------------------------------
|
|
enum FEGroup
|
|
{
|
|
GroupMap = 0,
|
|
GroupVehicle,
|
|
GroupColor,
|
|
GroupBadge,
|
|
GroupTime,
|
|
GroupWeather,
|
|
GroupLength,
|
|
GroupLaunch,
|
|
GroupCount
|
|
};
|
|
|
|
struct FEItem
|
|
{
|
|
int group;
|
|
int index;
|
|
RECT rect;
|
|
};
|
|
|
|
struct FEState
|
|
{
|
|
int selection[GroupCount];
|
|
char pilotName[24];
|
|
|
|
FEItem items[128];
|
|
int itemCount;
|
|
|
|
HWND menuWindow;
|
|
HWND nameEdit;
|
|
HFONT textFont;
|
|
HFONT titleFont;
|
|
HBRUSH editBrush;
|
|
Logical launched;
|
|
Logical closed;
|
|
};
|
|
|
|
FEState *gFE = NULL;
|
|
int gLastMissionSeconds = 0;
|
|
|
|
// carried across races so cycling back to the menu keeps the
|
|
// player's loadout (and names the results screen's score rows)
|
|
int gPersistSelection[GroupCount];
|
|
Logical gHavePersist = False;
|
|
char gLastPilotName[24] = "Pilot";
|
|
|
|
const COLORREF kGreenBright = RGB(64, 255, 64);
|
|
const COLORREF kGreenDim = RGB(24, 140, 24);
|
|
const COLORREF kBlack = RGB(0, 0, 0);
|
|
|
|
//---------------------------------------------------------------
|
|
// Layout: three columns of lists + the launch button
|
|
//---------------------------------------------------------------
|
|
void AddGroupItems(
|
|
FEState *fe, int group, int count,
|
|
int x, int *y, int row_h, int width)
|
|
{
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
FEItem *item = &fe->items[fe->itemCount++];
|
|
item->group = group;
|
|
item->index = i;
|
|
item->rect.left = x;
|
|
item->rect.top = *y;
|
|
item->rect.right = x + width;
|
|
item->rect.bottom = *y + row_h;
|
|
*y += row_h;
|
|
}
|
|
*y += row_h; // gap below the group
|
|
}
|
|
|
|
void LayoutMenu(FEState *fe, int client_w, int client_h)
|
|
{
|
|
fe->itemCount = 0;
|
|
|
|
int row_h = client_h / 36;
|
|
if (row_h < 18) row_h = 18;
|
|
if (row_h > 30) row_h = 30;
|
|
|
|
int col_w = client_w / 5;
|
|
int col1 = client_w / 14;
|
|
int col2 = col1 + col_w + client_w / 28;
|
|
int col3 = col2 + col_w + client_w / 28;
|
|
int top = client_h / 7;
|
|
|
|
int y = top;
|
|
AddGroupItems(fe, GroupMap, FE_COUNT(kMaps), col1, &y, row_h, col_w);
|
|
int y_after_maps = y;
|
|
AddGroupItems(fe, GroupTime, FE_COUNT(kTimes), col1, &y, row_h, col_w);
|
|
AddGroupItems(fe, GroupWeather, FE_COUNT(kWeather), col1, &y, row_h, col_w);
|
|
AddGroupItems(fe, GroupLength, FE_COUNT(kLengths), col1, &y, row_h, col_w);
|
|
|
|
y = top;
|
|
AddGroupItems(fe, GroupVehicle, FE_COUNT(kVehicles), col2, &y, row_h, col_w);
|
|
|
|
y = top + 2 * row_h; // leave room for the name edit + header
|
|
AddGroupItems(fe, GroupColor, FE_COUNT(kColors), col3, &y, row_h, col_w);
|
|
AddGroupItems(fe, GroupBadge, FE_COUNT(kBadges), col3, &y, row_h, col_w);
|
|
|
|
// launch button
|
|
FEItem *launch = &fe->items[fe->itemCount++];
|
|
launch->group = GroupLaunch;
|
|
launch->index = 0;
|
|
launch->rect.left = col3;
|
|
launch->rect.top = client_h - 3 * row_h;
|
|
launch->rect.right = col3 + col_w;
|
|
launch->rect.bottom = client_h - row_h;
|
|
|
|
// pilot name edit sits at the top of column 3
|
|
if (fe->nameEdit != NULL)
|
|
{
|
|
MoveWindow(fe->nameEdit,
|
|
col3, top - row_h / 4, col_w, row_h, TRUE);
|
|
}
|
|
}
|
|
|
|
const char *GroupTitle(int group)
|
|
{
|
|
switch (group)
|
|
{
|
|
case GroupMap: return "TRACK";
|
|
case GroupVehicle: return "VEHICLE";
|
|
case GroupColor: return "COLOR";
|
|
case GroupBadge: return "BADGE";
|
|
case GroupTime: return "TIME OF DAY";
|
|
case GroupWeather: return "WEATHER";
|
|
case GroupLength: return "RACE LENGTH";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
const char *ItemName(int group, int index)
|
|
{
|
|
switch (group)
|
|
{
|
|
case GroupMap: return kMaps[index].name;
|
|
case GroupVehicle: return kVehicles[index].name;
|
|
case GroupColor: return kColors[index].name;
|
|
case GroupBadge: return kBadges[index].name;
|
|
case GroupTime: return kTimes[index].name;
|
|
case GroupWeather: return kWeather[index].name;
|
|
case GroupLength: return kLengths[index].name;
|
|
case GroupLaunch: return "L A U N C H R A C E";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
// Painting (double buffered, pod green on black)
|
|
//---------------------------------------------------------------
|
|
void PaintMenu(FEState *fe)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc = BeginPaint(fe->menuWindow, &ps);
|
|
|
|
RECT client;
|
|
GetClientRect(fe->menuWindow, &client);
|
|
|
|
HDC mem = CreateCompatibleDC(hdc);
|
|
HBITMAP surface = CreateCompatibleBitmap(hdc, client.right, client.bottom);
|
|
HBITMAP old_surface = (HBITMAP) SelectObject(mem, surface);
|
|
|
|
FillRect(mem, &client, (HBRUSH) GetStockObject(BLACK_BRUSH));
|
|
SetBkMode(mem, TRANSPARENT);
|
|
|
|
// title
|
|
SelectObject(mem, fe->titleFont);
|
|
SetTextColor(mem, kGreenBright);
|
|
RECT title = client;
|
|
title.top = client.bottom / 28;
|
|
title.bottom = title.top + client.bottom / 10;
|
|
DrawTextA(mem, "RED PLANET - MARTIAN DEATH RACE", -1, &title,
|
|
DT_CENTER | DT_TOP | DT_SINGLELINE);
|
|
|
|
SelectObject(mem, fe->textFont);
|
|
|
|
// group headers (drawn above each group's first item)
|
|
int previous_group = -1;
|
|
for (int i = 0; i < fe->itemCount; ++i)
|
|
{
|
|
const FEItem *item = &fe->items[i];
|
|
if (item->group != previous_group && item->group != GroupLaunch)
|
|
{
|
|
previous_group = item->group;
|
|
RECT header = item->rect;
|
|
header.top -= (item->rect.bottom - item->rect.top);
|
|
header.bottom = item->rect.top;
|
|
SetTextColor(mem, kGreenBright);
|
|
DrawTextA(mem, GroupTitle(item->group), -1, &header,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
Logical selected =
|
|
(item->group == GroupLaunch) ||
|
|
(fe->selection[item->group] == item->index);
|
|
|
|
RECT row = item->rect;
|
|
if (item->group == GroupLaunch)
|
|
{
|
|
HBRUSH launch_brush = CreateSolidBrush(kGreenBright);
|
|
FrameRect(mem, &row, launch_brush);
|
|
DeleteObject(launch_brush);
|
|
SetTextColor(mem, kGreenBright);
|
|
DrawTextA(mem, ItemName(item->group, item->index), -1, &row,
|
|
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
continue;
|
|
}
|
|
|
|
if (selected)
|
|
{
|
|
HBRUSH sel_brush = CreateSolidBrush(kGreenDim);
|
|
RECT fill = row;
|
|
FillRect(mem, &fill, sel_brush);
|
|
DeleteObject(sel_brush);
|
|
SetTextColor(mem, kGreenBright);
|
|
}
|
|
else
|
|
{
|
|
SetTextColor(mem, kGreenDim);
|
|
}
|
|
RECT text = row;
|
|
text.left += 6;
|
|
DrawTextA(mem, ItemName(item->group, item->index), -1, &text,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
// pilot-name header
|
|
if (fe->nameEdit != NULL)
|
|
{
|
|
RECT edit_rect;
|
|
GetWindowRect(fe->nameEdit, &edit_rect);
|
|
POINT corner = { edit_rect.left, edit_rect.top };
|
|
ScreenToClient(fe->menuWindow, &corner);
|
|
RECT header;
|
|
header.left = corner.x;
|
|
header.right = corner.x + 300;
|
|
header.bottom = corner.y;
|
|
header.top = corner.y - 26;
|
|
SetTextColor(mem, kGreenBright);
|
|
DrawTextA(mem, "PILOT NAME", -1, &header,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
BitBlt(hdc, 0, 0, client.right, client.bottom, mem, 0, 0, SRCCOPY);
|
|
|
|
SelectObject(mem, old_surface);
|
|
DeleteObject(surface);
|
|
DeleteDC(mem);
|
|
EndPaint(fe->menuWindow, &ps);
|
|
}
|
|
|
|
void MenuClick(FEState *fe, int x, int y)
|
|
{
|
|
for (int i = 0; i < fe->itemCount; ++i)
|
|
{
|
|
const FEItem *item = &fe->items[i];
|
|
if (x >= item->rect.left && x < item->rect.right &&
|
|
y >= item->rect.top && y < item->rect.bottom)
|
|
{
|
|
if (item->group == GroupLaunch)
|
|
{
|
|
fe->launched = True;
|
|
// wake the modal loop (a click delivered via
|
|
// SendMessage never passes through the queue)
|
|
PostMessageA(fe->menuWindow, WM_NULL, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
fe->selection[item->group] = item->index;
|
|
InvalidateRect(fe->menuWindow, NULL, FALSE);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
FrontEndWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
FEState *fe = gFE;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_PAINT:
|
|
if (fe != NULL)
|
|
{
|
|
PaintMenu(fe);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
if (fe != NULL)
|
|
{
|
|
MenuClick(fe, (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam));
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_CTLCOLOREDIT:
|
|
if (fe != NULL)
|
|
{
|
|
SetTextColor((HDC) wParam, kGreenBright);
|
|
SetBkColor((HDC) wParam, kBlack);
|
|
return (LRESULT) fe->editBrush;
|
|
}
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
return 1;
|
|
}
|
|
return DefWindowProcA(hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
// Plasma name bitmaps: white text auto-fit into WxH, thresholded
|
|
// to 1bpp hex rows - the C++ twin of the console's PlasmaBitmaps.
|
|
//---------------------------------------------------------------
|
|
void AppendNameBitmap(std::string &egg, int width, int height, const char *name)
|
|
{
|
|
BITMAPINFO info;
|
|
memset(&info, 0, sizeof(info));
|
|
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
info.bmiHeader.biWidth = width;
|
|
info.bmiHeader.biHeight = -height; // top-down
|
|
info.bmiHeader.biPlanes = 1;
|
|
info.bmiHeader.biBitCount = 32;
|
|
info.bmiHeader.biCompression = BI_RGB;
|
|
|
|
void *bits = NULL;
|
|
HDC dc = CreateCompatibleDC(NULL);
|
|
HBITMAP bitmap = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, NULL, 0);
|
|
HBITMAP old_bitmap = (HBITMAP) SelectObject(dc, bitmap);
|
|
|
|
memset(bits, 0, width * height * 4);
|
|
SetBkMode(dc, TRANSPARENT);
|
|
SetTextColor(dc, RGB(255, 255, 255));
|
|
|
|
// shrink the font until the name fits (console: 24pt downward)
|
|
int point_size = 24;
|
|
for (;;)
|
|
{
|
|
HFONT font = CreateFontA(
|
|
-MulDiv(point_size, GetDeviceCaps(dc, LOGPIXELSY), 72),
|
|
0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
|
|
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
|
NONANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
|
|
"Microsoft Sans Serif");
|
|
HFONT old_font = (HFONT) SelectObject(dc, font);
|
|
|
|
SIZE extent;
|
|
GetTextExtentPoint32A(dc, name, (int) strlen(name), &extent);
|
|
if ((extent.cx <= width && extent.cy <= height) || point_size <= 1)
|
|
{
|
|
RECT rect = { 0, 0, width, height };
|
|
DrawTextA(dc, name, -1, &rect,
|
|
DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
|
|
SelectObject(dc, old_font);
|
|
DeleteObject(font);
|
|
break;
|
|
}
|
|
SelectObject(dc, old_font);
|
|
DeleteObject(font);
|
|
point_size = (point_size <= 2) ? (point_size / 2) : (point_size - 2);
|
|
}
|
|
|
|
GdiFlush();
|
|
const unsigned long *pixels = (const unsigned long *) bits;
|
|
char hex[8];
|
|
for (int row = 0; row < height; ++row)
|
|
{
|
|
egg += "bitmap=";
|
|
for (int byte_index = 0; byte_index < width / 8; ++byte_index)
|
|
{
|
|
unsigned char packed = 0;
|
|
for (int bit = 0; bit < 8; ++bit)
|
|
{
|
|
unsigned long pixel = pixels[row * width + byte_index * 8 + bit];
|
|
if ((pixel & 0xFF) >= 128) // white text on black
|
|
{
|
|
packed |= (unsigned char)(128 >> bit);
|
|
}
|
|
}
|
|
sprintf(hex, "%02X", packed);
|
|
egg += hex;
|
|
}
|
|
egg += "\n";
|
|
}
|
|
sprintf(hex, "%d", width);
|
|
egg += "x="; egg += hex; egg += "\n";
|
|
sprintf(hex, "%d", height);
|
|
egg += "y="; egg += hex; egg += "\n";
|
|
|
|
SelectObject(dc, old_bitmap);
|
|
DeleteObject(bitmap);
|
|
DeleteDC(dc);
|
|
}
|
|
|
|
// The 1st-4th place plasma graphics, verbatim from the console
|
|
// (RPMission.AppendOrdinals) / TEST.EGG.
|
|
extern const char *kOrdinalsBlock;
|
|
|
|
//---------------------------------------------------------------
|
|
// Egg assembly (console RPMission.ToEggString, race scenario,
|
|
// one local pilot)
|
|
//---------------------------------------------------------------
|
|
void BuildEggText(const FEState *fe, std::string &egg)
|
|
{
|
|
char line[256];
|
|
|
|
egg += "[mission]\n";
|
|
egg += "adventure=Red Planet\n";
|
|
sprintf(line, "map=%s\n", kMaps[fe->selection[GroupMap]].key);
|
|
egg += line;
|
|
egg += "scenario=race\n";
|
|
sprintf(line, "time=%s\n", kTimes[fe->selection[GroupTime]].key);
|
|
egg += line;
|
|
sprintf(line, "weather=%s\n", kWeather[fe->selection[GroupWeather]].key);
|
|
egg += line;
|
|
egg += "temperature=0\n";
|
|
egg += "compression=0\n";
|
|
int seconds = kLengths[fe->selection[GroupLength]].seconds;
|
|
if (seconds > 0)
|
|
{
|
|
sprintf(line, "length=%d\n", seconds);
|
|
egg += line;
|
|
}
|
|
|
|
egg += "[pilots]\n";
|
|
sprintf(line, "pilot=%s\n", kLocalPilotAddress);
|
|
egg += line;
|
|
|
|
sprintf(line, "[%s]\n", kLocalPilotAddress);
|
|
egg += line;
|
|
egg += "hostType=0\n";
|
|
egg += "dropzone=one\n";
|
|
sprintf(line, "name=%s\n", fe->pilotName);
|
|
egg += line;
|
|
egg += "bitmapindex=1\n";
|
|
egg += "loadzones=1\n";
|
|
sprintf(line, "vehicle=%s\n", kVehicles[fe->selection[GroupVehicle]].key);
|
|
egg += line;
|
|
sprintf(line, "color=%s\n", kColors[fe->selection[GroupColor]].key);
|
|
egg += line;
|
|
sprintf(line, "badge=%s\n", kBadges[fe->selection[GroupBadge]].key);
|
|
egg += line;
|
|
|
|
sprintf(line, "[largebitmap]\nbitmap=BitMap::Large::%s\n", fe->pilotName);
|
|
egg += line;
|
|
sprintf(line, "[smallbitmap]\nbitmap=BitMap::Small::%s\n", fe->pilotName);
|
|
egg += line;
|
|
|
|
sprintf(line, "[BitMap::Large::%s]\n", fe->pilotName);
|
|
egg += line;
|
|
AppendNameBitmap(egg, 128, 32, fe->pilotName);
|
|
egg += "width=8\n";
|
|
|
|
sprintf(line, "[BitMap::Small::%s]\n", fe->pilotName);
|
|
egg += line;
|
|
AppendNameBitmap(egg, 64, 16, fe->pilotName);
|
|
egg += "width=4\n";
|
|
|
|
egg += kOrdinalsBlock;
|
|
}
|
|
}
|
|
|
|
//########################################################################
|
|
//############################ RPL4FrontEnd_Run ##########################
|
|
//########################################################################
|
|
|
|
Logical
|
|
RPL4FrontEnd_Run(
|
|
HINSTANCE instance,
|
|
HWND main_window,
|
|
char *egg_path_out,
|
|
int egg_path_size
|
|
)
|
|
{
|
|
FEState fe;
|
|
memset(&fe, 0, sizeof(fe));
|
|
strcpy(fe.pilotName, gLastPilotName);
|
|
if (gHavePersist)
|
|
{
|
|
memcpy(fe.selection, gPersistSelection, sizeof(fe.selection));
|
|
}
|
|
else
|
|
{
|
|
fe.selection[GroupLength] = 2; // 5:00
|
|
}
|
|
gFE = &fe;
|
|
|
|
//---------------------------------------------------------------
|
|
// Window class + fonts
|
|
//---------------------------------------------------------------
|
|
static Logical class_registered = False;
|
|
if (!class_registered)
|
|
{
|
|
class_registered = True;
|
|
WNDCLASSA window_class;
|
|
memset(&window_class, 0, sizeof(window_class));
|
|
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
|
window_class.lpfnWndProc = FrontEndWndProc;
|
|
window_class.hInstance = instance;
|
|
window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
window_class.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
|
|
window_class.lpszClassName = "RPFrontEnd";
|
|
RegisterClassA(&window_class);
|
|
}
|
|
|
|
RECT client;
|
|
GetClientRect(main_window, &client);
|
|
|
|
fe.menuWindow = CreateWindowExA(
|
|
0, "RPFrontEnd", "",
|
|
WS_CHILD | WS_VISIBLE,
|
|
0, 0, client.right, client.bottom,
|
|
main_window, NULL, instance, NULL);
|
|
if (fe.menuWindow == NULL)
|
|
{
|
|
gFE = NULL;
|
|
return False;
|
|
}
|
|
|
|
int text_h = client.bottom / 40;
|
|
if (text_h < 16) text_h = 16;
|
|
if (text_h > 24) text_h = 24;
|
|
fe.textFont = CreateFontA(-text_h, 0, 0, 0, FW_NORMAL,
|
|
FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_MODERN,
|
|
"Consolas");
|
|
fe.titleFont = CreateFontA(-(text_h * 2), 0, 0, 0, FW_BOLD,
|
|
FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_MODERN,
|
|
"Consolas");
|
|
fe.editBrush = CreateSolidBrush(kBlack);
|
|
|
|
fe.nameEdit = CreateWindowExA(
|
|
0, "EDIT", fe.pilotName,
|
|
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
|
|
0, 0, 10, 10,
|
|
fe.menuWindow, NULL, instance, NULL);
|
|
SendMessageA(fe.nameEdit, WM_SETFONT, (WPARAM) fe.textFont, TRUE);
|
|
SendMessageA(fe.nameEdit, EM_SETLIMITTEXT, sizeof(fe.pilotName) - 2, 0);
|
|
|
|
LayoutMenu(&fe, client.right, client.bottom);
|
|
InvalidateRect(fe.menuWindow, NULL, TRUE);
|
|
|
|
//---------------------------------------------------------------
|
|
// Modal loop until the player launches or closes the window
|
|
//---------------------------------------------------------------
|
|
MSG msg;
|
|
while (!fe.launched && !fe.closed)
|
|
{
|
|
BOOL result = GetMessageA(&msg, NULL, 0, 0);
|
|
if (result <= 0)
|
|
{
|
|
fe.closed = True;
|
|
break;
|
|
}
|
|
if (msg.message == WM_QUIT ||
|
|
(msg.message == WM_SYSCOMMAND && msg.wParam == SC_CLOSE))
|
|
{
|
|
fe.closed = True;
|
|
}
|
|
// closing the main window ends the front end too
|
|
if (msg.message == WM_CLOSE && msg.hwnd == main_window)
|
|
{
|
|
fe.closed = True;
|
|
}
|
|
TranslateMessage(&msg);
|
|
DispatchMessageA(&msg);
|
|
if (!IsWindow(main_window))
|
|
{
|
|
fe.closed = True;
|
|
}
|
|
}
|
|
|
|
Logical launched = fe.launched;
|
|
if (launched)
|
|
{
|
|
gLastMissionSeconds = kLengths[fe.selection[GroupLength]].seconds;
|
|
|
|
GetWindowTextA(fe.nameEdit, fe.pilotName, sizeof(fe.pilotName) - 1);
|
|
if (fe.pilotName[0] == '\0')
|
|
{
|
|
strcpy(fe.pilotName, "Pilot");
|
|
}
|
|
strcpy(gLastPilotName, fe.pilotName);
|
|
memcpy(gPersistSelection, fe.selection, sizeof(gPersistSelection));
|
|
gHavePersist = True;
|
|
|
|
std::string egg;
|
|
egg.reserve(16384);
|
|
BuildEggText(&fe, egg);
|
|
|
|
strncpy(egg_path_out, "frontend.egg", egg_path_size - 1);
|
|
egg_path_out[egg_path_size - 1] = '\0';
|
|
|
|
FILE *file = fopen(egg_path_out, "wb");
|
|
if (file != NULL)
|
|
{
|
|
fwrite(egg.data(), 1, egg.size(), file);
|
|
fclose(file);
|
|
DEBUG_STREAM << "FrontEnd: wrote " << egg_path_out << " ("
|
|
<< (int) egg.size() << " bytes)\n" << std::flush;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_STREAM << "FrontEnd: could not write " << egg_path_out
|
|
<< "\n" << std::flush;
|
|
launched = False;
|
|
}
|
|
}
|
|
|
|
DestroyWindow(fe.menuWindow);
|
|
DeleteObject(fe.textFont);
|
|
DeleteObject(fe.titleFont);
|
|
DeleteObject(fe.editBrush);
|
|
gFE = NULL;
|
|
|
|
return launched;
|
|
}
|
|
|
|
int
|
|
RPL4FrontEnd_LastMissionSeconds()
|
|
{
|
|
return gLastMissionSeconds;
|
|
}
|
|
|
|
//########################################################################
|
|
//######################## RPL4FrontEnd_ShowResults ######################
|
|
//########################################################################
|
|
|
|
namespace
|
|
{
|
|
struct ResultRow
|
|
{
|
|
char name[32];
|
|
int score;
|
|
};
|
|
|
|
struct ResultsState
|
|
{
|
|
HWND window;
|
|
HFONT textFont;
|
|
HFONT titleFont;
|
|
ResultRow rows[16];
|
|
int rowCount;
|
|
RECT continueRect;
|
|
Logical dismissed;
|
|
Logical closed;
|
|
};
|
|
|
|
ResultsState *gRS = NULL;
|
|
|
|
const char *PlaceName(int place)
|
|
{
|
|
static const char *kPlaces[] = { "1ST", "2ND", "3RD", "4TH" };
|
|
static char other[8];
|
|
if (place < 4)
|
|
{
|
|
return kPlaces[place];
|
|
}
|
|
sprintf(other, "%dTH", place + 1);
|
|
return other;
|
|
}
|
|
|
|
void PaintResults(ResultsState *rs)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc = BeginPaint(rs->window, &ps);
|
|
|
|
RECT client;
|
|
GetClientRect(rs->window, &client);
|
|
|
|
HDC mem = CreateCompatibleDC(hdc);
|
|
HBITMAP surface = CreateCompatibleBitmap(hdc, client.right, client.bottom);
|
|
HBITMAP old_surface = (HBITMAP) SelectObject(mem, surface);
|
|
|
|
FillRect(mem, &client, (HBRUSH) GetStockObject(BLACK_BRUSH));
|
|
SetBkMode(mem, TRANSPARENT);
|
|
|
|
SelectObject(mem, rs->titleFont);
|
|
SetTextColor(mem, kGreenBright);
|
|
RECT title = client;
|
|
title.top = client.bottom / 28;
|
|
title.bottom = title.top + client.bottom / 10;
|
|
DrawTextA(mem, "RACE RESULTS", -1, &title,
|
|
DT_CENTER | DT_TOP | DT_SINGLELINE);
|
|
|
|
SelectObject(mem, rs->textFont);
|
|
int row_h = client.bottom / 16;
|
|
int top = client.bottom / 4;
|
|
int left = client.right / 3;
|
|
int right = 2 * client.right / 3;
|
|
char text[48];
|
|
for (int i = 0; i < rs->rowCount; ++i)
|
|
{
|
|
RECT row;
|
|
row.left = left;
|
|
row.right = right;
|
|
row.top = top + i * row_h;
|
|
row.bottom = row.top + row_h;
|
|
|
|
SetTextColor(mem, (i == 0) ? kGreenBright : kGreenDim);
|
|
DrawTextA(mem, PlaceName(i), -1, &row,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
RECT name = row;
|
|
name.left += (right - left) / 5;
|
|
DrawTextA(mem, rs->rows[i].name, -1, &name,
|
|
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
sprintf(text, "%d", rs->rows[i].score);
|
|
DrawTextA(mem, text, -1, &row,
|
|
DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
|
|
}
|
|
|
|
HBRUSH frame_brush = CreateSolidBrush(kGreenBright);
|
|
FrameRect(mem, &rs->continueRect, frame_brush);
|
|
DeleteObject(frame_brush);
|
|
SetTextColor(mem, kGreenBright);
|
|
DrawTextA(mem, "C O N T I N U E", -1, &rs->continueRect,
|
|
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
BitBlt(hdc, 0, 0, client.right, client.bottom, mem, 0, 0, SRCCOPY);
|
|
|
|
SelectObject(mem, old_surface);
|
|
DeleteObject(surface);
|
|
DeleteDC(mem);
|
|
EndPaint(rs->window, &ps);
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
ResultsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
ResultsState *rs = gRS;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_PAINT:
|
|
if (rs != NULL)
|
|
{
|
|
PaintResults(rs);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
if (rs != NULL)
|
|
{
|
|
POINT point = { (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam) };
|
|
if (PtInRect(&rs->continueRect, point))
|
|
{
|
|
rs->dismissed = True;
|
|
PostMessageA(rs->window, WM_NULL, 0, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
return 1;
|
|
}
|
|
return DefWindowProcA(hwnd, message, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
Logical
|
|
RPL4FrontEnd_ShowResults(
|
|
HINSTANCE instance,
|
|
HWND main_window
|
|
)
|
|
{
|
|
int result_count = RPL4LocalConsole_ResultCount();
|
|
if (result_count <= 0)
|
|
{
|
|
return True; // nothing to show (first boot)
|
|
}
|
|
if (!IsWindow(main_window))
|
|
{
|
|
return False;
|
|
}
|
|
|
|
ResultsState rs;
|
|
memset(&rs, 0, sizeof(rs));
|
|
|
|
//---------------------------------------------------------------
|
|
// Intake, then sort descending by score. Single-player results
|
|
// carry the pilot's own name; with more pods the roster will map
|
|
// host IDs to Steam personas (until then: pod number).
|
|
//---------------------------------------------------------------
|
|
for (int i = 0; i < result_count && rs.rowCount < 16; ++i)
|
|
{
|
|
int host_ID, score;
|
|
if (!RPL4LocalConsole_GetResult(i, &host_ID, &score))
|
|
{
|
|
continue;
|
|
}
|
|
ResultRow *row = &rs.rows[rs.rowCount++];
|
|
if (result_count == 1)
|
|
{
|
|
sprintf(row->name, "%s", gLastPilotName);
|
|
}
|
|
else
|
|
{
|
|
sprintf(row->name, "POD %d", host_ID);
|
|
}
|
|
row->score = score;
|
|
}
|
|
for (int i = 1; i < rs.rowCount; ++i)
|
|
{
|
|
ResultRow key = rs.rows[i];
|
|
int j = i - 1;
|
|
while (j >= 0 && rs.rows[j].score < key.score)
|
|
{
|
|
rs.rows[j + 1] = rs.rows[j];
|
|
--j;
|
|
}
|
|
rs.rows[j + 1] = key;
|
|
}
|
|
|
|
static Logical class_registered = False;
|
|
if (!class_registered)
|
|
{
|
|
class_registered = True;
|
|
WNDCLASSA window_class;
|
|
memset(&window_class, 0, sizeof(window_class));
|
|
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
|
window_class.lpfnWndProc = ResultsWndProc;
|
|
window_class.hInstance = instance;
|
|
window_class.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
window_class.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
|
|
window_class.lpszClassName = "RPResults";
|
|
RegisterClassA(&window_class);
|
|
}
|
|
|
|
RECT client;
|
|
GetClientRect(main_window, &client);
|
|
|
|
rs.window = CreateWindowExA(
|
|
0, "RPResults", "",
|
|
WS_CHILD | WS_VISIBLE,
|
|
0, 0, client.right, client.bottom,
|
|
main_window, NULL, instance, NULL);
|
|
if (rs.window == NULL)
|
|
{
|
|
return False;
|
|
}
|
|
|
|
int text_h = client.bottom / 40;
|
|
if (text_h < 16) text_h = 16;
|
|
if (text_h > 24) text_h = 24;
|
|
rs.textFont = CreateFontA(-(text_h * 3 / 2), 0, 0, 0, FW_NORMAL,
|
|
FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_MODERN,
|
|
"Consolas");
|
|
rs.titleFont = CreateFontA(-(text_h * 2), 0, 0, 0, FW_BOLD,
|
|
FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_MODERN,
|
|
"Consolas");
|
|
|
|
int row_h = client.bottom / 36;
|
|
if (row_h < 18) row_h = 18;
|
|
if (row_h > 30) row_h = 30;
|
|
int col_w = client.right / 5;
|
|
rs.continueRect.left = (client.right - col_w) / 2;
|
|
rs.continueRect.right = rs.continueRect.left + col_w;
|
|
rs.continueRect.top = client.bottom - 3 * row_h;
|
|
rs.continueRect.bottom = client.bottom - row_h;
|
|
|
|
gRS = &rs;
|
|
SetFocus(rs.window);
|
|
InvalidateRect(rs.window, NULL, TRUE);
|
|
|
|
//---------------------------------------------------------------
|
|
// Modal until CONTINUE (or any key) - same shape as the menu loop
|
|
//---------------------------------------------------------------
|
|
MSG msg;
|
|
while (!rs.dismissed && !rs.closed)
|
|
{
|
|
BOOL result = GetMessageA(&msg, NULL, 0, 0);
|
|
if (result <= 0)
|
|
{
|
|
rs.closed = True;
|
|
break;
|
|
}
|
|
if (msg.message == WM_QUIT ||
|
|
(msg.message == WM_SYSCOMMAND && msg.wParam == SC_CLOSE))
|
|
{
|
|
rs.closed = True;
|
|
}
|
|
if (msg.message == WM_CLOSE && msg.hwnd == main_window)
|
|
{
|
|
rs.closed = True;
|
|
}
|
|
if (msg.message == WM_KEYDOWN &&
|
|
(msg.wParam == VK_RETURN || msg.wParam == VK_SPACE ||
|
|
msg.wParam == VK_ESCAPE))
|
|
{
|
|
rs.dismissed = True;
|
|
}
|
|
TranslateMessage(&msg);
|
|
DispatchMessageA(&msg);
|
|
if (!IsWindow(main_window))
|
|
{
|
|
rs.closed = True;
|
|
}
|
|
}
|
|
|
|
DestroyWindow(rs.window);
|
|
DeleteObject(rs.textFont);
|
|
DeleteObject(rs.titleFont);
|
|
gRS = NULL;
|
|
|
|
return !rs.closed;
|
|
}
|
|
|
|
//########################################################################
|
|
// Ordinal plasma graphics (verbatim from the console / TEST.EGG)
|
|
//########################################################################
|
|
|
|
namespace
|
|
{
|
|
const char *kOrdinalsBlock =
|
|
"[ordinals]\n"
|
|
"bitmap=Ordinal::BitMap::1\n"
|
|
"bitmap=Ordinal::BitMap::2\n"
|
|
"bitmap=Ordinal::BitMap::3\n"
|
|
"bitmap=Ordinal::BitMap::4\n"
|
|
"[Ordinal::BitMap::1]\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=000038000003C000001FF00000000F00\n"
|
|
"bitmap=0000F8000003C000003FF80000000F00\n"
|
|
"bitmap=0001F8000003C00000707C0000000F00\n"
|
|
"bitmap=0001F8000003C00000603C0000000F00\n"
|
|
"bitmap=00007801FC0FF00000003C3DF807FF00\n"
|
|
"bitmap=00007803FE0FF00000003C3FFC0FFF00\n"
|
|
"bitmap=00007803C703C00000003C3E3C1F0F00\n"
|
|
"bitmap=000078078303C0000000783C1E1E0F00\n"
|
|
"bitmap=000078078003C0000000783C1E1E0F00\n"
|
|
"bitmap=00007807C003C0000000F03C1E1E0F00\n"
|
|
"bitmap=00007807F003C0000001E03C1E1E0F00\n"
|
|
"bitmap=00007803FC03C0000003C03C1E1E0F00\n"
|
|
"bitmap=00007801FE03C0000007803C1E1E0F00\n"
|
|
"bitmap=000078007F03C000000F003C1E1E0F00\n"
|
|
"bitmap=000078001F03C000001E003C1E1E0F00\n"
|
|
"bitmap=000078000F03C000003C003C1E1E0F00\n"
|
|
"bitmap=000078060F03C0000078003C1E1E0F00\n"
|
|
"bitmap=000078071E03E0000078003C1E1F1F00\n"
|
|
"bitmap=00007803FE01F000007FFC3C1E0FFF00\n"
|
|
"bitmap=00007801FC00F000007FFC3C1E07EF00\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"x=128\n"
|
|
"y=32\n"
|
|
"width=8\n"
|
|
"[Ordinal::BitMap::2]\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=001FFF0000003C0000003C03C0780000\n"
|
|
"bitmap=001FFF0000003C0000007C03C0780000\n"
|
|
"bitmap=00000E0000003C000000FC03C0780000\n"
|
|
"bitmap=00003C0000003C000001BC03C0780000\n"
|
|
"bitmap=0000700F3E1FFC000003BC0FF07BF000\n"
|
|
"bitmap=0001E00F7E3FFC0000073C0FF07FF800\n"
|
|
"bitmap=0003800FFE7C3C0000063C03C07C7800\n"
|
|
"bitmap=0007F80FFE783C00000C3C03C0783C00\n"
|
|
"bitmap=0007FE0F80783C0000183C03C0783C00\n"
|
|
"bitmap=00001E0F00783C0000383C03C0783C00\n"
|
|
"bitmap=00000F0F00783C0000703C03C0783C00\n"
|
|
"bitmap=00000F0F00783C00007FFF03C0783C00\n"
|
|
"bitmap=00000F0F00783C00007FFF03C0783C00\n"
|
|
"bitmap=00000F0F00783C0000003C03C0783C00\n"
|
|
"bitmap=00000F0F00783C0000003C03C0783C00\n"
|
|
"bitmap=00000F0F00783C0000003C03C0783C00\n"
|
|
"bitmap=00180F0F00783C0000003C03C0783C00\n"
|
|
"bitmap=001C1F0F007C7C0000003C03E0783C00\n"
|
|
"bitmap=000FFE0F003FFC0000003C01F0783C00\n"
|
|
"bitmap=0007FC0F001FBC0000003C00F0783C00\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"x=128\n"
|
|
"y=32\n"
|
|
"width=8\n"
|
|
"[Ordinal::BitMap::3]\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=001FFF03C07800000000FC03C0780000\n"
|
|
"bitmap=001FFF03C07800000003FC03C0780000\n"
|
|
"bitmap=001E0003C07800000007C003C0780000\n"
|
|
"bitmap=001E0003C0780000000F0003C0780000\n"
|
|
"bitmap=001E000FF07BF000000F000FF07BF000\n"
|
|
"bitmap=001E000FF07FF800001E000FF07FF800\n"
|
|
"bitmap=001E0003C07C7800001E0003C07C7800\n"
|
|
"bitmap=001FFC03C0783C00001EFC03C0783C00\n"
|
|
"bitmap=001FFE03C0783C00001FFE03C0783C00\n"
|
|
"bitmap=00001F03C0783C00001F1F03C0783C00\n"
|
|
"bitmap=00000F03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=00000F03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=00000F03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=00000F03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=00000F03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=00000F03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=00180F03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=001C1F03E0783C00001F1F03E0783C00\n"
|
|
"bitmap=000FFE01F0783C00000FFE01F0783C00\n"
|
|
"bitmap=0007FC00F0783C000007FC00F0783C00\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"x=128\n"
|
|
"y=32\n"
|
|
"width=8\n"
|
|
"[Ordinal::BitMap::4]\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=001FFF03C07800000007FC03C0780000\n"
|
|
"bitmap=001FFF03C0780000000FFE03C0780000\n"
|
|
"bitmap=00000F03C0780000001F1F03C0780000\n"
|
|
"bitmap=00000F03C0780000001E0F03C0780000\n"
|
|
"bitmap=00000F0FF07BF000001E0F0FF07BF000\n"
|
|
"bitmap=00001F0FF07FF800001E0F0FF07FF800\n"
|
|
"bitmap=00001E03C07C7800001E0F03C07C7800\n"
|
|
"bitmap=00003E03C0783C00001E0F03C0783C00\n"
|
|
"bitmap=00003C03C0783C00000F1E03C0783C00\n"
|
|
"bitmap=00003C03C0783C000007FC03C0783C00\n"
|
|
"bitmap=00007803C0783C000007FC03C0783C00\n"
|
|
"bitmap=00007803C0783C00000F1E03C0783C00\n"
|
|
"bitmap=00007803C0783C00001E0F03C0783C00\n"
|
|
"bitmap=0000F003C0783C00001E0F03C0783C00\n"
|
|
"bitmap=0000F003C0783C00001E0F03C0783C00\n"
|
|
"bitmap=0000F003C0783C00001E0F03C0783C00\n"
|
|
"bitmap=0000F003C0783C00001E0F03C0783C00\n"
|
|
"bitmap=0000F003E0783C00000F1E03E0783C00\n"
|
|
"bitmap=0000F001F0783C00000FFE01F0783C00\n"
|
|
"bitmap=0000F000F0783C000007FC00F0783C00\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"bitmap=00000000000000000000000000000000\n"
|
|
"x=128\n"
|
|
"y=32\n"
|
|
"width=8\n";
|
|
}
|