Commit ac9e5d59 authored by Rob Swindell's avatar Rob Swindell 💬
Browse files

Merge branch 'master' of gitlab.synchro.net:main/sbbs

parents 88f5586f 4c53afa1
SlyEdit message editor
Version 1.82
Release date: 2022-12-01
Version 1.83
Release date: 2022-12-14
by
Eric Oulashin
Sysop of Digital Distortion BBS
BBS internet address: digdist.bbsindex.com
BBS internet address: digitaldistortionbbs.com
Alternate: digdist.synchro.net
Email: eric.oulashin@gmail.com
......@@ -144,7 +145,7 @@ ICE parameter for IceEdit emulation:
¦ ¦Native (32-bit) Executable No ¦
¦ ¦Use Shell to Execute No ¦
¦ ¦Record Terminal Width Yes ¦
¦ ¦Word-wrap Quoted Text Yes, for 80 columns ¦
¦ ¦Word-wrap Quoted Text Yes, for terminal width ¦
¦ ¦Automatically Quoted Text All ¦
¦ ¦Editor Information Files QuickBBS MSGINF/MSGTMP ¦
¦ ¦Expand Line Feeds to CRLF Yes ¦
......@@ -917,6 +918,14 @@ message to lower-case and comparing them with the words in the dictionary.
===================
Version Date Description
------- ---- -----------
1.83 2022-12-13 Quote lines that are wider than the user's terminal width
are now wrapped to the user's terminal width to ensure
all the quote lines are entirely available to be quoted.
1.82 2022-12-01 Bug fix: Added some safety checks when reading the
configuration file
1.81 2022-11-26 Refactored the way the configuration file is read. Also,
the color configuration files now can just specify
attribute characters, without the control character.
1.80 2022-07-04 Added the ability to change/set the text color (using the
CTRL-K hotkey). If desired, changing the text color can
be disabled if, and the colors can be saved as ANSI
......
......@@ -21,6 +21,10 @@
* 2022-12-01 Eric Oulashin Version 1.82
* Added some safety checks when reading the configuration file
* (that section of code was refactored recently).
* 2022-12-13 Eric Oulashin Version 1.83
* Quote lines that are wider than the user's terminal width are
* now wrapped to the user's terminal width to ensure all the
* quote lines are entirely available to be quoted.
*/
"use strict";
......@@ -118,8 +122,8 @@ if (console.screen_columns < 80)
}
// Version information
var EDITOR_VERSION = "1.82";
var EDITOR_VER_DATE = "2022-12-01";
var EDITOR_VERSION = "1.83";
var EDITOR_VER_DATE = "2022-12-14";
// Program variables
......@@ -953,7 +957,7 @@ function readQuoteOrMessageFile()
{
textLine = inputFile.readln(2048);
// Only use textLine if it's actually a string.
if (typeof(textLine) == "string")
if (typeof(textLine) === "string")
{
textLine = strip_ctrl(textLine);
// If the line has only whitespace and/or > characters,
......@@ -961,7 +965,22 @@ function readQuoteOrMessageFile()
// gQuoteLines.
if (/^[\s>]+$/.test(textLine))
textLine = "";
gQuoteLines.push(textLine);
// If the quote line length is within the user's terminal width, then add it as-is.
if (textLine.length <= console.screen_columns-1)
gQuoteLines.push(textLine);
else
{
// Word-wrap the quote line to ensure the quote lines are no wider than the user's
// terminal width (minus 1 character)
var wrappedLine = word_wrap(textLine, console.screen_columns-1, textLine.length, false);
var wrappedLines = wrappedLine.split("\n");
// If splitting results in an empty line at the end of the array (due to a newline at the
// end of the last line), then remove that line. Then add the wrapped lines to the quote lines.
if (wrappedLines.length > 0 && wrappedLines[wrappedLines.length-1].length == 0)
wrappedLines.splice(-1);
for (var i = 0; i < wrappedLines.length; ++i)
gQuoteLines.push(wrappedLines[i]);
}
}
}
}
......
......@@ -145,6 +145,7 @@ function send_newuser_welcome_msg(fname)
subject: "Welcome to " + system.name + "!"
};
msgtxt = msgtxt.replace(/@(\w+)@/, function (code) { return bbs.atcode(code); });
var result = msgbase.save_msg(hdr, msgtxt);
if(!result)
log(LOG_ERR, "!ERROR " + msgbase.error + " saving mail message");
......
......@@ -1671,7 +1671,7 @@ CIOLIBEXPORT struct ciolib_screen * ciolib_savescreen(void)
}
if (vmode != -1) {
ret->pixels = ciolib_getpixels(0, 0, vparams[vmode].charwidth * vparams[vmode].cols - 1, vparams[vmode].charheight * vparams[vmode].rows - 1, TRUE);
ret->pixels = ciolib_getpixels(0, 0, vparams[vmode].xres - 1, vparams[vmode].yres - 1, FALSE);
}
ciolib_vmem_gettext(1, 1, ret->text_info.screenwidth, ret->text_info.screenheight, ret->vmem);
ret->fg_colour = ciolib_fg;
......
......@@ -1759,6 +1759,8 @@ static void parse_sixel_string(struct cterminal *cterm, bool finish)
if (!*p)
continue;
cterm->sx_repeat = strtoul(p, &p, 10);
if (cterm->sx_repeat > 0x7fff)
cterm->sx_repeat = 0x7fff;
break;
case '#': // Colour Introducer
p++;
......
......@@ -239,6 +239,29 @@ ESC _ Application Program String (APS)
Begins a string consisting of the characters 0x08 - 0x0d and
0x20-0x7e, terminated by a String Terminator (ST)
The string is currently ignored.
SyncTERM implements the following APS commands:
APS SyncTERM:C;S;Ps1;Ps2 ST (Store file)
Where Ps1 is a filename and Ps2 is the base64 encoded
contents of the file. The named file is stored in the
cache directory for the current connection.
APS SyncTERM:C;L ST (List Files)
List files in cache. SyncTERM responds with
an APS string with lines separated by newlines. The
first line is always "SyncTERM:C;L\n" and for each
matching file, a line in the form
<Filename> TAB <MD5 sum> LF is sent
(ie: "coolfont.fnt\t595f44fec1e92a71d3e9e77456ba80d1\n")
And additional argument can be specified as a glob(3)
pattern (defaults to "*") in APS SyncTERM:C;L;Ps ST.
APS SyncTERM:C;SetFont;Pn;Ps
Where Pn is a font slot number (max 255) and Ps is a
filename in the cache. This sets font slot Pn to use
the specified font file.
ESC c Reset to Initial State (RIS)
Resets all the terminal settings, clears the screen, and homes
......@@ -1281,3 +1304,69 @@ heard it, ALWAYS follow it with an 0x0f 0x0e is the shift lock character which
*will* cause people with anything but an ANSI-BBS terminal (ie: *nix users
using the bundled telnet app) to have their screen messed up. 0x0f "undoes"
the 0x0e.
Sequences sent by SyncTERM
The following keys in SyncTERM result in the specified sequence being
sent to the remote. This is not part of CTerm, but are documented here
for people who want to maintain compatibility.
Left Arrow "\033[D"
Right Arrow "\033[C"
Up Arrow "\033[A"
Down Arrow "\033[B"
Home "\033[H"
End "\033[K"
Select "\033[K" (Same as End due to termcap weirdness)
Delete "\x7f"
Page Down "\033[U"
Page Up "\033[V"
F1 "\033[11~"
F2 "\033[12~"
F3 "\033[13~"
F4 "\033[14~"
F5 "\033[15~"
F6 "\033[17~" (Note the jump from 15 to 17 here)
F7 "\033[18~"
F8 "\033[19~"
F9 "\033[20~"
F10 "\033[21~"
F11 "\033[23~" (Note the jump from 21 to 23 here)
F12 "\033[24~"
Shift + F1 "\033[11;2~"
Shift + F2 "\033[12;2~"
Shift + F3 "\033[13;2~"
Shift + F4 "\033[14;2~"
Shift + F5 "\033[15;2~"
Shift + F6 "\033[17;2~"
Shift + F7 "\033[18;2~"
Shift + F8 "\033[19;2~"
Shift + F9 "\033[20;2~"
Shift + F10 "\033[21;2~"
Shift + F11 "\033[23;2~"
Shift + F12 "\033[24;2~"
Alt + F1 "\033[11;3~"
Alt + F2 "\033[12;3~"
Alt + F3 "\033[13;3~"
Alt + F4 "\033[14;3~"
Alt + F5 "\033[15;3~"
Alt + F6 "\033[17;3~"
Alt + F7 "\033[18;3~"
Alt + F8 "\033[19;3~"
Alt + F9 "\033[20;3~"
Alt + F10 "\033[21;3~"
Alt + F11 "\033[23;3~"
Alt + F12 "\033[24;3~"
Control + F1 "\033[11;5~"
Control + F2 "\033[12;5~"
Control + F3 "\033[13;5~"
Control + F4 "\033[14;5~"
Control + F5 "\033[15;5~"
Control + F6 "\033[17;5~"
Control + F7 "\033[18;5~"
Control + F8 "\033[19;5~"
Control + F9 "\033[20;5~"
Control + F10 "\033[21;5~"
Control + F11 "\033[23;5~"
Control + F12 "\033[24;5~"
Insert "\033[@"
Back Tab "\033[Z"
......@@ -41,6 +41,26 @@ aspect_fix(int *x, int *y, int aspect_width, int aspect_height)
bestx = lround((double)*y * aspect_width / aspect_height);
besty = lround((double)*x * aspect_height / aspect_width);
if (bestx < *x && besty > 0)
*y = besty;
else
*x = bestx;
}
/*
* Corrects width/height to have the specified aspect ratio
*/
void
aspect_fix_low(int *x, int *y, int aspect_width, int aspect_height)
{
int bestx, besty;
// Nothing we can do here...
if (aspect_width == 0 || aspect_height == 0)
return;
bestx = lround((double)*y * aspect_width / aspect_height);
besty = lround((double)*x * aspect_height / aspect_width);
if (bestx < *x && bestx > 0)
*x = bestx;
else
......
......@@ -19,3 +19,4 @@ struct graphics_buffer * do_scale(struct rectlist* rect, int xscale, int yscale,
void aspect_correct(int *x, int *y, int aspect_width, int aspect_height);
void aspect_reverse(int *x, int *y, int scrnwidth, int scrnheight, int aspect_width, int aspect_height);
void aspect_fix(int *x, int *y, int aspect_width, int aspect_height);
void aspect_fix_low(int *x, int *y, int aspect_width, int aspect_height);
......@@ -46,6 +46,8 @@ SDL_Cursor *curs=NULL;
SDL_Renderer *renderer=NULL;
SDL_Texture *texture=NULL;
pthread_mutex_t win_mutex;
pthread_mutex_t sdl_mode_mutex;
bool sdl_mode;
SDL_Surface *sdl_icon=NULL;
sem_t sdl_ufunc_ret;
......@@ -187,6 +189,7 @@ const struct sdl_keyvals sdl_keyval[] =
};
void sdl_video_event_thread(void *data);
static void setup_surfaces_locked(void);
static void sdl_user_func(int func, ...)
{
......@@ -254,11 +257,16 @@ static int sdl_user_func_ret(int func, ...)
/* Drain the swamp */
while(1) {
switch(func) {
case SDL_USEREVENT_SETVIDMODE:
ev.user.data1 = NULL + va_arg(argptr, int);
ev.user.data2 = NULL + va_arg(argptr, int);
while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)!=1)
YIELD();
break;
case SDL_USEREVENT_GETWINPOS:
ev.user.data1 = va_arg(argptr, void *);
ev.user.data2 = va_arg(argptr, void *);
// Fallthrough
case SDL_USEREVENT_SETVIDMODE:
case SDL_USEREVENT_INIT:
case SDL_USEREVENT_QUIT:
while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)!=1)
......@@ -343,7 +351,7 @@ window_can_scale_internally(int winwidth, int winheight)
static void
internal_scaling_factors(int winwidth, int winheight, int *x, int *y)
{
aspect_fix(&winwidth, &winheight, cvstat.aspect_width, cvstat.aspect_height);
aspect_fix_low(&winwidth, &winheight, cvstat.aspect_width, cvstat.aspect_height);
aspect_reverse(&winwidth, &winheight, cvstat.scrnwidth, cvstat.scrnheight, cvstat.aspect_width, cvstat.aspect_height);
*x = winwidth / cvstat.scrnwidth;
*y = winheight / cvstat.scrnheight;
......@@ -356,6 +364,7 @@ internal_scaling_factors(int winwidth, int winheight, int *x, int *y)
static int sdl_init_mode(int mode)
{
int oldcols;
int scaling = 1;
if (mode != CIOLIB_MODE_CUSTOM) {
pthread_mutex_lock(&vstatlock);
......@@ -372,9 +381,13 @@ static int sdl_init_mode(int mode)
pthread_mutex_lock(&vstatlock);
oldcols = cvstat.cols;
bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
vstat.winwidth = lround((double)cvstat.winwidth / cvstat.scrnwidth * vstat.scrnwidth);
vstat.winheight = lround((double)cvstat.winheight / cvstat.scrnheight * vstat.scrnheight);
aspect_correct(&vstat.winwidth, &cvstat.winheight, cvstat.aspect_width, cvstat.aspect_height);
if (cvstat.scrnwidth > 0) {
for (scaling = 1; (scaling + 1) * cvstat.scrnwidth < cvstat.winwidth; scaling++)
;
}
vstat.winwidth = vstat.scrnwidth * scaling;
vstat.winheight = vstat.scrnheight * scaling;
aspect_fix(&vstat.winwidth, &vstat.winheight, vstat.aspect_width, vstat.aspect_height);
if (oldcols != vstat.cols) {
if (oldcols == 0) {
if (ciolib_initial_window_width > 0)
......@@ -400,10 +413,13 @@ static int sdl_init_mode(int mode)
cvstat = vstat;
internal_scaling = window_can_scale_internally(vstat.winwidth, vstat.winheight);
pthread_mutex_lock(&sdl_mode_mutex);
sdl_mode = true;
pthread_mutex_unlock(&sdl_mode_mutex);
pthread_mutex_unlock(&vstatlock);
pthread_mutex_unlock(&blinker_lock);
sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE);
sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE, cvstat.winwidth, cvstat.winheight);
return(0);
}
......@@ -438,8 +454,9 @@ int sdl_init(int mode)
return(-1);
}
void sdl_setwinsize_locked(int w, int h)
static void internal_setwinsize(int w, int h)
{
pthread_mutex_lock(&vstatlock);
if (w > 16384)
w = 16384;
if (h > 16384)
......@@ -451,13 +468,13 @@ void sdl_setwinsize_locked(int w, int h)
cvstat.winwidth = vstat.winwidth = w;
cvstat.winheight = vstat.winheight = h;
internal_scaling = window_can_scale_internally(cvstat.winwidth, cvstat.winheight);
setup_surfaces_locked();
pthread_mutex_unlock(&vstatlock);
}
void sdl_setwinsize(int w, int h)
{
pthread_mutex_lock(&vstatlock);
sdl_setwinsize_locked(w, h);
pthread_mutex_unlock(&vstatlock);
sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE, w, h);
}
void sdl_setwinposition(int x, int y)
......@@ -597,20 +614,21 @@ static void setup_surfaces_locked(void)
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
#endif
pthread_mutex_lock(&win_mutex);
idealmw = cvstat.scrnwidth;
idealmh = cvstat.scrnheight;
aspect_correct(&idealmw, &idealmh, cvstat.aspect_width, cvstat.aspect_height);
idealw = cvstat.winwidth;
idealh = cvstat.winheight;
aspect_fix(&idealw, &idealh, cvstat.aspect_width, cvstat.aspect_height);
internal_scaling = window_can_scale_internally(idealw, idealh);
sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, internal_scaling ? "0" : "2");
if (win == NULL) {
// SDL2: This is slow sometimes... not sure why.
if (sdl.CreateWindowAndRenderer(cvstat.winwidth, cvstat.winheight, flags, &win, &renderer) == 0) {
sdl.GetWindowSize(win, &idealw, &idealh);
cvstat.winwidth = idealw;
cvstat.winheight = idealh;
sdl.RenderClear(renderer);
if (internal_scaling)
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, idealw, idealh);
......@@ -629,6 +647,9 @@ static void setup_surfaces_locked(void)
else {
sdl.SetWindowMinimumSize(win, idealmw, idealmh);
sdl.SetWindowSize(win, idealw, idealh);
sdl.GetWindowSize(win, &idealw, &idealh);
cvstat.winwidth = idealw;
cvstat.winheight = idealh;
if (internal_scaling)
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, idealw, idealh);
else
......@@ -1013,43 +1034,14 @@ void sdl_video_event_thread(void *data)
case SDL_WINDOWEVENT_SIZE_CHANGED:
// SDL2: User resized window
case SDL_WINDOWEVENT_RESIZED:
{
// SDL2: Something resized window
const char *newh;
pthread_mutex_lock(&vstatlock);
pthread_mutex_lock(&win_mutex);
internal_scaling = window_can_scale_internally(ev.window.data1, ev.window.data2);
if (internal_scaling) {
newh = "0";
}
else {
newh = "2";
}
sdl.GetWindowSize(win, &cvstat.winwidth, &cvstat.winheight);
if (strcmp(newh, sdl.GetHint(SDL_HINT_RENDER_SCALE_QUALITY))) {
SDL_Texture *newtexture;
sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, newh);
if (internal_scaling) {
int idealw, idealh;
idealw = cvstat.winwidth;
idealh = cvstat.winheight;
aspect_fix(&idealw, &idealh, cvstat.aspect_width, cvstat.aspect_height);
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, idealw, idealh);
}
else
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.scrnwidth, cvstat.scrnheight);
sdl.RenderClear(renderer);
if (texture)
sdl.DestroyTexture(texture);
texture = newtexture;
}
sdl.RenderClear(renderer);
bitmap_drv_request_pixels();
pthread_mutex_unlock(&win_mutex);
pthread_mutex_unlock(&vstatlock);
pthread_mutex_lock(&sdl_mode_mutex);
if (sdl_mode) {
pthread_mutex_unlock(&sdl_mode_mutex);
break;
}
pthread_mutex_unlock(&sdl_mode_mutex);
internal_setwinsize(ev.window.data1, ev.window.data2);
break;
case SDL_WINDOWEVENT_EXPOSED:
bitmap_drv_request_pixels();
break;
......@@ -1069,20 +1061,25 @@ void sdl_video_event_thread(void *data)
pthread_mutex_lock(&win_mutex);
if (win != NULL) {
pthread_mutex_lock(&sdl_headlock);
pthread_mutex_lock(&sdl_mode_mutex);
list = update_list;
update_list = update_list_tail = NULL;
bool skipit = sdl_mode;
pthread_mutex_unlock(&sdl_mode_mutex);
pthread_mutex_unlock(&sdl_headlock);
for (; list; list = old_next) {
SDL_Rect src;
SDL_Rect dst;
old_next = list->next;
if (list->next == NULL) {
if (list->next == NULL && !skipit) {
void *pixels;
int pitch;
int row;
int tw, th;
sdl.RenderClear(renderer);
pthread_mutex_lock(&vstatlock);
if (internal_scaling) {
struct graphics_buffer *gb;
int xscale, yscale;
......@@ -1093,8 +1090,10 @@ void sdl_video_event_thread(void *data)
src.y = 0;
src.w = gb->w;
src.h = gb->h;
sdl.QueryTexture(texture, NULL, NULL, &tw, &th);
sdl.LockTexture(texture, &src, &pixels, &pitch);
if (sdl.QueryTexture(texture, NULL, NULL, &tw, &th) != 0)
fprintf(stderr, "Unable to query texture (%s)\n", sdl.GetError());
if (sdl.LockTexture(texture, &src, &pixels, &pitch) != 0)
fprintf(stderr, "Unable to lock texture (%s)\n", sdl.GetError());
if (pitch != gb->w * sizeof(gb->data[0])) {
// If this happens, we need to copy a row at a time...
for (row = 0; row < gb->h && row < th; row++) {
......@@ -1123,8 +1122,10 @@ void sdl_video_event_thread(void *data)
src.y = 0;
src.w = list->rect.width;
src.h = list->rect.height;
sdl.QueryTexture(texture, NULL, NULL, &tw, &th);
sdl.LockTexture(texture, &src, &pixels, &pitch);
if (sdl.QueryTexture(texture, NULL, NULL, &tw, &th) != 0)
fprintf(stderr, "Unable to query texture (%s)\n", sdl.GetError());
if (sdl.LockTexture(texture, &src, &pixels, &pitch) != 0)
fprintf(stderr, "Unable to lock texture (%s)\n", sdl.GetError());
if (pitch != list->rect.width * sizeof(list->data[0])) {
// If this happens, we need to copy a row at a time...
for (row = 0; row < list->rect.height && row < th; row++) {
......@@ -1149,12 +1150,15 @@ void sdl_video_event_thread(void *data)
dst.x = (cvstat.winwidth - dst.w) / 2;
dst.y = (cvstat.winheight - dst.h) / 2;
}
sdl.RenderCopy(renderer, texture, &src, &dst);
pthread_mutex_unlock(&vstatlock);
if (sdl.RenderCopy(renderer, texture, &src, &dst))
fprintf(stderr, "RenderCopy() failed! (%s)\n", sdl.GetError());
}
bitmap_drv_free_rect(list);
}
sdl.RenderPresent(renderer);
}
pthread_mutex_unlock(&win_mutex);
break;
case SDL_USEREVENT_SETNAME:
......@@ -1188,9 +1192,11 @@ void sdl_video_event_thread(void *data)
free(ev.user.data1);
break;
case SDL_USEREVENT_SETVIDMODE:
pthread_mutex_lock(&vstatlock);
setup_surfaces_locked();
pthread_mutex_unlock(&vstatlock);
pthread_mutex_lock(&sdl_mode_mutex);
sdl_mode = false;
pthread_mutex_unlock(&sdl_mode_mutex);
internal_setwinsize(ev.user.data1 - NULL, ev.user.data2 - NULL);
sdl_ufunc_retval=0;
sem_post(&sdl_ufunc_ret);
break;
......@@ -1277,6 +1283,7 @@ int sdl_initciolib(int mode)
pthread_mutex_init(&sdl_headlock, NULL);
pthread_mutex_init(&win_mutex, NULL);
pthread_mutex_init(&sdl_keylock, NULL);
pthread_mutex_init(&sdl_mode_mutex, NULL);
return(sdl_init(mode));
}
......
%C|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
|14Top Players
|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
|13No.6 |12 321,239,486,352 XP |09Level XXIII |11Kingdom of Peasants
|13O.J. Simpson |12 45,523,074,630 XP |09Level XXII |11Kingdom of Lies
|13Joe Blow |12 23,636,534,605 XP |09Level XXI |11Kingdom of Blowholes
|13Evil Doer |12 6,666,666,666 XP |09Level XX |11Kingdom of Satan
|13The Clap |12 3,079,023,054 XP |09Level XIX |11Kingdom of Satan
|13Widowmaker |12 1,075,598,743 XP |09Level XVII |11Kingdom of Widows
|13Layman |12 94,078,746 XP |09Level XV |11Kingdom of Lay-Me
|13The Doctor |12 45,065,045 XP |09Level XIIV |11Kingdom of Hospital
|13Dude |12 548 XP |09Level II |11Kingdom of Dudes
|13I Suck |12 23 XP |09Level I |11Kingdom of Dudes
%P |13John Doe |12 13 XP |09Level I |11Kingdom of John
|13Frank |12 2 XP |09Level I |11Kingdom of John
|13Tom |12 2 XP |09Level I |11Kingdom of Shmoes
|13Dick |12 1 XP |09Level I |11Kingdom of Shmoes
|13Harry |12 0 XP |09Level I |11Kingdom of Shmoes
|13This Game Sux|12 0 XP |09Level I |11Kingdom of Sux
|13Newbie |12 0 XP |09Level I |11Kingdom of Newbies
|13I Hate Doors |12 0 XP |09Level I |11Kingdom of IDoors
|13Napolean |12 0 XP |09Level I |11Kingdom of France
%C|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
|14Top Players
|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
|13No.6 |12 321,239,486,352 XP |09Level XXIII |11Kingdom of Peasants
|13O.J. Simpson |12 45,523,074,630 XP |09Level XXII |11Kingdom of Lies
|13Joe Blow |12 23,636,534,605 XP |09Level XXI |11Kingdom of Blowholes
|13Evil Doer |12 6,666,666,666 XP |09Level XX |11Kingdom of Satan
|13The Clap |12 3,079,023,054 XP |09Level XIX |11Kingdom of Satan
|13Widowmaker |12 1,075,598,743 XP |09Level XVII |11Kingdom of Widows
|13Layman |12 94,078,746 XP |09Level XV |11Kingdom of Lay-Me
|13The Doctor |12 45,065,045 XP |09Level XIIV |11Kingdom of Hospital
|13Dude |12 548 XP |09Level II |11Kingdom of Dudes
|13I Suck |12 23 XP |09Level I |11Kingdom of Dudes
%P |13John Doe |12 13 XP |09Level I |11Kingdom of John
|13Frank |12 2 XP |09Level I |11Kingdom of John
|13Tom |12 2 XP |09Level I |11Kingdom of Shmoes
|13Dick |12 1 XP |09Level I |11Kingdom of Shmoes
|13Harry |12 0 XP |09Level I |11Kingdom of Shmoes
|13This Game Sux|12 0 XP |09Level I |11Kingdom of Sux
|13Newbie |12 0 XP |09Level I |11Kingdom of Newbies
|13I Hate Doors |12 0 XP |09Level I |11Kingdom of IDoors
|13Napolean |12 0 XP |09Level I |11Kingdom of France
%C|07
|04|07
|04 |12 |04 |13This door game is rated PG for Pretty Good. |04|07
|04 |12 |04 |12Warning: |05This door game contains scenes |04|07
|04 |12 |07 |04 |05of hilarity, violence, and great fun.|07 |04|07
|04 |12 |04|07 |04|07
|04 |12 |04 |05This game was not found to be addictive by |04|07
|04 |12|07 |12 |04 |05the Sergeant General.|07 |04|07
|04 |07 |04|07 |04|07
|04 |07
%C|07
|04|07
|04 |12 |04 |13This door game is rated PG for Pretty Good. |04|07
|04 |12 |04 |12Warning: |05This door game contains scenes |04|07
|04 |12 |07 |04 |05of hilarity, violence, and great fun.|07 |04|07
|04 |12 |04|07 |04|07
|04 |12 |04 |05This game was not found to be addictive by |04|07
|04 |12|07 |12 |04 |05the Sergeant General.|07 |04|07
|04 |07 |04|07 |04|07