mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-24 21:02:26 +00:00
fa0c73d33b
Added .psd, .pbm/.pgm/.ppm, .pfm, and .hdr image formats. Extensions NOT added to r_imageextensions. png (and the above formats) can now be loaded as RGBA16, instead of being truncated to RGBA8 (8bit pngs not affected). r_imagelist will now show images from memory, instead of potentially loading new/different ones from disk. Fix serverbrowser bug being too eager to join the server (eg from alt+tab). Don't send ipv6 packets to qw/q2 masters. They won't be able to report ipv6 addresses anyway, and this reduces warnings when a host STILL has no ipv6 (my ISP sucks). this does not affect q3/dpmasters, for people without ipv4 addresses. Tried to improve compat with Bloodshot's particle effects. Fixed a couple of issues with R_AddTrisoup. Fixed string tokenizing bug where it was using the wrong buffer size values. Don't show link-local/localhost addresses in eg the status command (unless developer). qtv-rel is now an easier target, for new qtv releases. qtv warning fixes. added a nailtrail effect to 'high' particles. fixed terrain shaders. fixed fogged water issue (on one of bal's maps). first attempt at gltf2 format support git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5400 fc73d0e0-1445-4013-8a0c-d673dee63da5
593 lines
No EOL
16 KiB
C
593 lines
No EOL
16 KiB
C
#include "qtv.h"
|
|
|
|
#define CENTERTIME 1.5
|
|
|
|
void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
|
|
{
|
|
//build a possible message, even though it'll probably not be sent
|
|
|
|
sv_t *sv;
|
|
int i, min;
|
|
|
|
switch(viewer->menunum)
|
|
{
|
|
default:
|
|
if (buttonnum < 0)
|
|
QW_SetMenu(viewer, MENU_MAIN); //no other sort of back button...
|
|
break;
|
|
|
|
case MENU_MAIN:
|
|
if (buttonnum < 0)
|
|
viewer->menuop -= (MENU_MAIN_ITEMCOUNT + 1)/2;
|
|
else if (buttonnum > 0)
|
|
viewer->menuop += (MENU_MAIN_ITEMCOUNT + 1)/2;
|
|
else if (buttonnum == 0)
|
|
{
|
|
switch(viewer->menuop)
|
|
{
|
|
case MENU_MAIN_STREAMS: //Streams
|
|
QW_SetMenu(viewer, MENU_SERVERS);
|
|
break;
|
|
case MENU_MAIN_CLIENTLIST://Client List
|
|
QW_SetMenu(viewer, MENU_CLIENTS);
|
|
break;
|
|
|
|
case MENU_MAIN_NEWSTREAM://New Stream
|
|
QW_PrintfToViewer(viewer, "Not implemented yet\n");
|
|
break;
|
|
case MENU_MAIN_DEMOS://Demos
|
|
Cluster_BuildAvailableDemoList(cluster);
|
|
QW_SetMenu(viewer, MENU_DEMOS);
|
|
break;
|
|
|
|
case MENU_MAIN_SERVERBROWSER://Server Browser
|
|
QW_PrintfToViewer(viewer, "Not implemented yet\n");
|
|
break;
|
|
case MENU_MAIN_ADMIN://Admin
|
|
QW_SetMenu(viewer, MENU_ADMIN);
|
|
break;
|
|
|
|
case MENU_MAIN_PREVPROX://Previous Proxy
|
|
if (viewer->isproxy)
|
|
{
|
|
QW_SetMenu(viewer, MENU_NONE);
|
|
QW_StuffcmdToViewer(viewer, "say proxy:menu\n");
|
|
}
|
|
else
|
|
QW_PrintfToViewer(viewer, "No client proxy detected\n");
|
|
break;
|
|
case MENU_MAIN_NEXTPROX://Next Proxy
|
|
if (viewer->server && viewer->server->serverisproxy && viewer->server->controller == viewer)
|
|
{
|
|
viewer->server->proxyisselected = false;
|
|
QW_SetMenu(viewer, MENU_NONE);
|
|
SendClientCommand(viewer->server, "say .menu");
|
|
}
|
|
else
|
|
QW_PrintfToViewer(viewer, "No server proxy detected\n");
|
|
break;
|
|
|
|
case MENU_MAIN_HELP://Help Menu
|
|
QW_PrintfToViewer(viewer, "Not implemented yet\n");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MENU_CLIENTS:
|
|
if (buttonnum >= 0)
|
|
{
|
|
viewer_t *v = cluster->viewers;
|
|
for (i = 0; i < viewer->menuop && v; i++)
|
|
v = v->next;
|
|
if (!v)
|
|
break;
|
|
if (v == viewer)
|
|
{
|
|
if (viewer->commentator)
|
|
QW_SetCommentator(cluster, viewer, NULL);
|
|
else
|
|
QW_PrintfToViewer(viewer, "Please stop touching yourself\n");
|
|
}
|
|
else
|
|
QW_SetCommentator(cluster, viewer, v);
|
|
}
|
|
else
|
|
QW_SetMenu(viewer, MENU_MAIN);
|
|
break;
|
|
|
|
case MENU_DEMOS:
|
|
if (buttonnum >= 0)
|
|
QW_StuffcmdToViewer(viewer, "say .demo %s\n", cluster->availdemos[viewer->menuop].name);
|
|
else
|
|
QW_SetMenu(viewer, MENU_MAIN);
|
|
break;
|
|
|
|
case MENU_ADMINSERVER:
|
|
if (viewer->server)
|
|
{
|
|
i = 0;
|
|
sv = viewer->server;
|
|
if (i++ == viewer->menuop)
|
|
{ //auto disconnect
|
|
sv->autodisconnect = sv->autodisconnect?AD_NO:AD_WHENEMPTY;
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //disconnect
|
|
QTV_ShutdownStream(viewer->server);
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{
|
|
if (sv->controller == viewer)
|
|
sv->controller = NULL;
|
|
else
|
|
{
|
|
sv->controller = viewer;
|
|
sv->controllersquencebias = viewer->netchan.outgoing_sequence - sv->netchan.outgoing_sequence;
|
|
}
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //back
|
|
QW_SetMenu(viewer, MENU_ADMIN);
|
|
}
|
|
break;
|
|
}
|
|
//fallthrough
|
|
case MENU_SERVERS:
|
|
if (buttonnum < 0)
|
|
QW_SetMenu(viewer, MENU_MAIN);
|
|
else if (!cluster->servers)
|
|
{
|
|
QW_StuffcmdToViewer(viewer, "echo Please enter a server ip\nmessagemode\n");
|
|
strcpy(viewer->expectcommand, "insecadddemo");
|
|
}
|
|
else
|
|
{
|
|
if (viewer->menuop < 0)
|
|
viewer->menuop = 0;
|
|
i = 0;
|
|
min = viewer->menuop - 10;
|
|
if (min < 0)
|
|
min = 0;
|
|
for (sv = cluster->servers; sv && i<min; sv = sv->next, i++)
|
|
{//skip over the early connections.
|
|
}
|
|
min+=20;
|
|
for (; sv && i < min; sv = sv->next, i++)
|
|
{
|
|
if (i == viewer->menuop)
|
|
{
|
|
/*if (sv->parsingconnectiondata || !sv->modellist[1].name[0])
|
|
{
|
|
QW_PrintfToViewer(viewer, "But that stream isn't connected\n");
|
|
}
|
|
else*/
|
|
{
|
|
QW_SetViewersServer(cluster, viewer, sv);
|
|
QW_SetMenu(viewer, MENU_NONE);
|
|
viewer->thinksitsconnected = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MENU_ADMIN:
|
|
i = 0;
|
|
if (i++ == viewer->menuop)
|
|
{ //connection stuff
|
|
QW_SetMenu(viewer, MENU_ADMINSERVER);
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //qw port
|
|
QW_StuffcmdToViewer(viewer, "echo You will need to reconnect\n");
|
|
cluster->qwlistenportnum += (buttonnum<0)?-1:1;
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //hostname
|
|
strcpy(viewer->expectcommand, "hostname");
|
|
QW_StuffcmdToViewer(viewer, "echo Please enter the new hostname\nmessagemode\n");
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //master
|
|
strcpy(viewer->expectcommand, "master");
|
|
QW_StuffcmdToViewer(viewer, "echo Please enter the master dns or ip\necho Enter '.' for masterless mode\nmessagemode\n");
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //password
|
|
strcpy(viewer->expectcommand, "password");
|
|
QW_StuffcmdToViewer(viewer, "echo Please enter the new rcon password\nmessagemode\n");
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //add server
|
|
strcpy(viewer->expectcommand, "messagemode");
|
|
QW_StuffcmdToViewer(viewer, "echo Please enter the new qtv server dns or ip\naddserver\n");
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //add demo
|
|
strcpy(viewer->expectcommand, "adddemo");
|
|
QW_StuffcmdToViewer(viewer, "echo Please enter the name of the demo to play\nmessagemode\n");
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //choke
|
|
cluster->chokeonnotupdated ^= 1;
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //late forwarding
|
|
cluster->lateforward ^= 1;
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //no talking
|
|
cluster->notalking ^= 1;
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //nobsp
|
|
cluster->nobsp ^= 1;
|
|
}
|
|
if (i++ == viewer->menuop)
|
|
{ //back
|
|
QW_SetMenu(viewer, MENU_NONE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void WriteStringSelection(netmsg_t *b, qboolean selected, const char *str)
|
|
{
|
|
if (selected)
|
|
{
|
|
WriteByte(b, 13);
|
|
while(*str)
|
|
WriteByte(b, 128|*str++);
|
|
}
|
|
else
|
|
{
|
|
WriteByte(b, ' ');
|
|
while(*str)
|
|
WriteByte(b, *str++);
|
|
}
|
|
}
|
|
|
|
void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
|
|
{
|
|
char buffer[2048];
|
|
char str[256];
|
|
sv_t *sv;
|
|
int i, min;
|
|
unsigned char *s;
|
|
|
|
netmsg_t m;
|
|
|
|
if (viewer->backbuffered)
|
|
return;
|
|
|
|
if (viewer->menunum == MENU_FORWARDING)
|
|
return;
|
|
|
|
if (viewer->menuspamtime > cluster->curtime && viewer->menuspamtime < cluster->curtime + CENTERTIME*2000)
|
|
return;
|
|
viewer->menuspamtime = cluster->curtime + CENTERTIME*1000;
|
|
|
|
InitNetMsg(&m, buffer, sizeof(buffer));
|
|
|
|
WriteByte(&m, svc_centerprint);
|
|
|
|
WriteString2(&m, "/PFTEQTV "QTV_VERSION_STRING"\n");
|
|
WriteString2(&m, PROXYWEBSITE"\n");
|
|
WriteString2(&m, "-------------\n");
|
|
|
|
if (strcmp(cluster->hostname, DEFAULT_HOSTNAME))
|
|
WriteString2(&m, cluster->hostname);
|
|
|
|
switch(viewer->menunum)
|
|
{
|
|
default:
|
|
WriteString2(&m, "bad menu");
|
|
break;
|
|
|
|
case MENU_MAIN:
|
|
{
|
|
WriteString2(&m, "\n\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f\n");
|
|
while (viewer->menuop < 0)
|
|
viewer->menuop += MENU_MAIN_ITEMCOUNT;
|
|
while (viewer->menuop >= MENU_MAIN_ITEMCOUNT)
|
|
viewer->menuop -= MENU_MAIN_ITEMCOUNT;
|
|
i = viewer->menuop;
|
|
|
|
WriteStringSelection(&m, i==MENU_MAIN_STREAMS, "Streams ");
|
|
WriteStringSelection(&m, i==MENU_MAIN_CLIENTLIST, "Client List ");
|
|
WriteByte(&m, '\n');
|
|
WriteStringSelection(&m, i==MENU_MAIN_NEWSTREAM, "New Stream ");
|
|
WriteStringSelection(&m, i==MENU_MAIN_DEMOS, "Demos ");
|
|
WriteByte(&m, '\n');
|
|
WriteStringSelection(&m, i==MENU_MAIN_SERVERBROWSER,"Server Browser ");
|
|
WriteStringSelection(&m, i==MENU_MAIN_ADMIN, "Admin ");
|
|
WriteByte(&m, '\n');
|
|
WriteStringSelection(&m, i==MENU_MAIN_PREVPROX, "Previous Proxy ");
|
|
WriteStringSelection(&m, i==MENU_MAIN_NEXTPROX, "Next Proxy ");
|
|
WriteByte(&m, '\n');
|
|
WriteStringSelection(&m, i==MENU_MAIN_HELP, "Help ");
|
|
WriteString2(&m, " ");
|
|
|
|
WriteString2(&m, "\n\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f\n");
|
|
}
|
|
break;
|
|
|
|
case MENU_CLIENTS:
|
|
{
|
|
int start;
|
|
viewer_t *v;
|
|
char *srv;
|
|
int c;
|
|
v = cluster->viewers;
|
|
|
|
if (viewer->menuop < 0)
|
|
viewer->menuop = 0;
|
|
if (viewer->menuop > cluster->numviewers - 1)
|
|
viewer->menuop = cluster->numviewers - 1;
|
|
|
|
WriteString2(&m, "\nActive Clients\n\n");
|
|
|
|
start = viewer->menuop & ~7;
|
|
for (i = 0; i < start && v; i++)
|
|
v = v->next;
|
|
for (i = start; i < start+8 && v; i++, v = v->next)
|
|
{
|
|
for (c = strlen(v->name); c < 14; c++)
|
|
WriteByte(&m, ' ');
|
|
WriteStringSelection(&m, viewer->menuop == i, v->name);
|
|
WriteString2(&m, ": ");
|
|
if (v->server)
|
|
{
|
|
if (!v->server->sourcefile && !v->server->parsingconnectiondata)
|
|
srv = v->server->map.hostname;
|
|
else
|
|
srv = v->server->server;
|
|
}
|
|
else
|
|
srv = "None";
|
|
for (c = 0; c < 20; c++)
|
|
{
|
|
if (*srv)
|
|
WriteByte(&m, *srv++);
|
|
else
|
|
WriteByte(&m, ' ');
|
|
}
|
|
|
|
WriteByte(&m, '\n');
|
|
}
|
|
for (; i < start+8; i++)
|
|
WriteByte(&m, '\n');
|
|
}
|
|
break;
|
|
|
|
|
|
case MENU_DEMOS:
|
|
{
|
|
int start;
|
|
|
|
WriteString2(&m, "\nAvailable Demos\n\n");
|
|
|
|
if (cluster->availdemoscount == 0)
|
|
{
|
|
WriteString2(&m, "No demos are available");
|
|
break;
|
|
}
|
|
|
|
if (viewer->menuop < 0)
|
|
viewer->menuop = 0;
|
|
if (viewer->menuop > cluster->availdemoscount-1)
|
|
viewer->menuop = cluster->availdemoscount-1;
|
|
|
|
start = viewer->menuop & ~7;
|
|
for (i = start; i < start+8; i++)
|
|
{
|
|
char cleanname[128];
|
|
char *us;
|
|
strlcpy(cleanname, cluster->availdemos[i].name, sizeof(cleanname));
|
|
for (us = cleanname; *us; us++)
|
|
if (*us == '_')
|
|
*us = ' ';
|
|
WriteStringSelection(&m, i == viewer->menuop, cleanname);
|
|
WriteByte(&m, '\n');
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MENU_ADMINSERVER: //per-connection options
|
|
if (viewer->server)
|
|
{
|
|
sv = viewer->server;
|
|
WriteString2(&m, "\n\nConnection Admin\n");
|
|
WriteString2(&m, sv->map.hostname);
|
|
if (sv->sourcefile)
|
|
WriteString2(&m, " (demo)");
|
|
WriteString2(&m, "\n\n");
|
|
|
|
if (viewer->menuop < 0)
|
|
viewer->menuop = 0;
|
|
|
|
i = 0;
|
|
|
|
WriteString2(&m, " auto disconnect");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
switch(viewer->server->autodisconnect)
|
|
{
|
|
default:
|
|
case AD_NO:
|
|
sprintf(str, "%-20s", "permanent connection");
|
|
break;
|
|
case AD_REVERSECONNECT:
|
|
sprintf(str, "%-20s", "when server disconnects");
|
|
break;
|
|
case AD_WHENEMPTY:
|
|
sprintf(str, "%-20s", "when inactive");
|
|
break;
|
|
case AD_STATUSPOLL:
|
|
sprintf(str, "%-20s", "idle when empty");
|
|
break;
|
|
}
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, "force disconnect");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " take control");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " back");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
if (viewer->menuop >= i)
|
|
viewer->menuop = i - 1;
|
|
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " status");
|
|
WriteString2(&m, " : ");
|
|
sprintf(str, "%-20s", viewer->server->status);
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
break;
|
|
}
|
|
//fallthrough
|
|
case MENU_SERVERS: //connections list
|
|
|
|
WriteString2(&m, "\n\nServers\n\n");
|
|
|
|
if (!cluster->servers)
|
|
{
|
|
WriteString2(&m, "No active connections");
|
|
}
|
|
else
|
|
{
|
|
if (viewer->menuop < 0)
|
|
viewer->menuop = 0;
|
|
i = 0;
|
|
min = viewer->menuop - 10;
|
|
if (min < 0)
|
|
min = 0;
|
|
for (sv = cluster->servers; sv && i<min; sv = sv->next, i++)
|
|
{//skip over the early connections.
|
|
}
|
|
min+=20;
|
|
for (; sv && i < min; sv = sv->next, i++)
|
|
{
|
|
//Info_ValueForKey(sv->serverinfo, "hostname", str, sizeof(str));
|
|
//if (sv->parsingconnectiondata || !sv->modellist[1].name[0])
|
|
// snprintf(str, sizeof(str), "%s", sv->server);
|
|
snprintf(str, sizeof(str), "%s", *sv->map.hostname?sv->map.hostname:sv->server);
|
|
|
|
if (i == viewer->menuop)
|
|
for (s = (unsigned char *)str; *s; s++)
|
|
{
|
|
if ((unsigned)*s >= ' ')
|
|
*s = 128 | (*s&~128);
|
|
}
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MENU_ADMIN: //admin menu
|
|
|
|
WriteString2(&m, "\n\nCluster Admin\n\n");
|
|
|
|
if (viewer->menuop < 0)
|
|
viewer->menuop = 0;
|
|
i = 0;
|
|
|
|
WriteString2(&m, " this connection");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " port");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20i", cluster->qwlistenportnum);
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " hostname");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", cluster->hostname);
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " master");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", cluster->master);
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " password");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " add server");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " add demo");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " choke");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", cluster->chokeonnotupdated?"yes":"no");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, "delay forwarding");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", cluster->lateforward?"yes":"no");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " talking");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", cluster->notalking?"no":"yes");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " nobsp");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", cluster->nobsp?"yes":"no");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
WriteString2(&m, " back");
|
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
|
sprintf(str, "%-20s", "...");
|
|
WriteString2(&m, str);
|
|
WriteString2(&m, "\n");
|
|
|
|
if (viewer->menuop >= i)
|
|
viewer->menuop = i - 1;
|
|
break;
|
|
}
|
|
|
|
|
|
WriteByte(&m, 0);
|
|
SendBufferToViewer(viewer, m.data, m.cursize, true);
|
|
} |