]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/16_us.c_
p16 is being worked on a bunch by me wwww [16_ca needs huge amounts of work and I...
[16.git] / src / lib / 16_us.c_
diff --git a/src/lib/16_us.c_ b/src/lib/16_us.c_
new file mode 100755 (executable)
index 0000000..47034db
--- /dev/null
@@ -0,0 +1,969 @@
+//\r
+//     ID Engine\r
+//     ID_US_1.c - User Manager - General routines\r
+//     v1.1d1w\r
+//     By Jason Blochowiak\r
+//     Hacked up for Catacomb 3D\r
+//     Open Watcom port by sparky4\r
+//\r
+\r
+//\r
+//     This module handles dealing with user input & feedback\r
+//\r
+//     Depends on: Input Mgr, View Mgr, some variables from the Sound, Caching,\r
+//             and Refresh Mgrs, Memory Mgr for background save/restore\r
+//\r
+//     Globals:\r
+//             ingame - Flag set by game indicating if a game is in progress\r
+//      abortgame - Flag set if the current game should be aborted (if a load\r
+//                     game fails)\r
+//             loadedgame - Flag set if a game was loaded\r
+//             abortprogram - Normally nil, this points to a terminal error message\r
+//                     if the program needs to abort\r
+//             restartgame - Normally set to gd_Continue, this is set to one of the\r
+//                     difficulty levels if a new game should be started\r
+//             PrintX, PrintY - Where the User Mgr will print (global coords)\r
+//             WindowX,WindowY,WindowW,WindowH - The dimensions of the current\r
+//                     window\r
+//\r
+\r
+#include "src/lib/16_us.h"\r
+\r
+#pragma        hdrstop\r
+\r
+#pragma        warn    -pia\r
+\r
+static word far* clockw= (word far*) 0x046C; /* 18.2hz clock */\r
+\r
+//undeced vars\r
+boolean compatability; word px,py;\r
+\r
+//     Global variables\r
+               char            *abortprogram;\r
+               boolean         NoWait;\r
+               word            PrintX,PrintY;\r
+               word            WindowX,WindowY,WindowW,WindowH;\r
+\r
+//     Internal variables\r
+#define        ConfigVersion   1\r
+\r
+static char            *ParmStrings[] = {"TEDLEVEL","NOWAIT"},\r
+                                       *ParmStrings2[] = {"COMP","NOCOMP"};\r
+static boolean         US_Started;\r
+\r
+               boolean         Button0,Button1,\r
+                                       CursorBad;\r
+               int                     CursorX,CursorY;\r
+\r
+               void            (*USL_MeasureString)(char far *,word *,word *) = VW_MeasurePropString,\r
+                                       (*USL_DrawString)(char far *) = VWB_DrawPropString;\r
+\r
+               SaveGame        Games[MaxSaveGames];\r
+               HighScore       Scores[MaxScores] =\r
+                                       {\r
+                                               {"id software-'92",10000,1},\r
+                                               {"Adrian Carmack",10000,1},\r
+                                               {"John Carmack",10000,1},\r
+                                               {"Kevin Cloud",10000,1},\r
+                                               {"Tom Hall",10000,1},\r
+                                               {"John Romero",10000,1},\r
+                                               {"Jay Wilbur",10000,1},\r
+                                       };\r
+\r
+//     Internal routines\r
+\r
+//     Public routines\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     USL_HardError() - Handles the Abort/Retry/Fail sort of errors passed\r
+//                     from DOS.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+#pragma        warn    -par\r
+#pragma        warn    -rch\r
+int\r
+USL_HardError(word errval,int ax,int bp,int si)\r
+{\r
+#define IGNORE  0\r
+#define RETRY   1\r
+#define        ABORT   2\r
+extern void    ShutdownId(void);\r
+\r
+static char            buf[32];\r
+static WindowRec       wr;\r
+               int                     dival=0;\r
+               char            c,*s,*t;\r
+\r
+       __asm {\r
+               mov     [dival],di\r
+       }\r
+       //dival = _DI;\r
+\r
+       if (ax < 0)\r
+               s = "Device Error";\r
+       else\r
+       {\r
+               if ((dival & 0x00ff) == 0)\r
+                       s = "Drive ~ is Write Protected";\r
+               else\r
+                       s = "Error on Drive ~";\r
+               for (t = buf;*s;s++,t++)        // Can't use sprintf()\r
+                       if ((*t = *s) == '~')\r
+                               *t = (ax & 0x00ff) + 'A';\r
+               *t = '\0';\r
+               s = buf;\r
+       }\r
+\r
+       c = peekb(0x40,0x49);   // Get the current screen mode\r
+       if ((c < 4) || (c == 7))\r
+               goto oh_kill_me;\r
+\r
+       // DEBUG - handle screen cleanup\r
+\r
+       US_SaveWindow(&wr);\r
+       US_CenterWindow(30,3);\r
+       US_CPrint(s);\r
+       US_CPrint("(R)etry or (A)bort?");\r
+       //++++VW_UpdateScreen();\r
+       IN_ClearKeysDown();\r
+\r
+__asm  sti     // Let the keyboard interrupts come through\r
+\r
+       while (true)\r
+       {\r
+               switch (IN_WaitForASCII())\r
+               {\r
+               case key_Escape:\r
+               case 'a':\r
+               case 'A':\r
+                       goto oh_kill_me;\r
+                       break;\r
+               case key_Return:\r
+               case key_Space:\r
+               case 'r':\r
+               case 'R':\r
+                       US_ClearWindow();\r
+                       //++++VW_UpdateScreen();\r
+                       US_RestoreWindow(&wr);\r
+                       return(RETRY);\r
+                       break;\r
+               }\r
+       }\r
+\r
+oh_kill_me:\r
+       abortprogram = s;\r
+       ShutdownId();\r
+       fprintf(stderr,"Terminal Error: %s\n",s);\r
+       if (tedlevel)\r
+               fprintf(stderr,"You launched from TED. I suggest that you reboot...\n");\r
+\r
+       return(ABORT);\r
+#undef IGNORE\r
+#undef RETRY\r
+#undef ABORT\r
+}\r
+#pragma        warn    +par\r
+#pragma        warn    +rch\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_Startup() - Starts the User Mgr\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_Startup(void)\r
+{\r
+       int     i,n;\r
+\r
+       if (US_Started)\r
+               return;\r
+\r
+       //++++_harderr(USL_HardError);  // Install the fatal error handler\r
+\r
+       US_InitRndT(true);              // Initialize the random number generator\r
+\r
+       for (i = 1;i < _argc;i++)\r
+       {\r
+               switch (US_CheckParm(_argv[i],ParmStrings2))\r
+               {\r
+               case 0:\r
+                       compatability = true;\r
+                       break;\r
+               case 1:\r
+                       compatability = false;\r
+                       break;\r
+               }\r
+       }\r
+\r
+       // Check for TED launching here\r
+       for (i = 1;i < _argc;i++)\r
+       {\r
+               n = US_CheckParm(_argv[i],ParmStrings);\r
+               switch(n)\r
+               {\r
+                case 0:\r
+                  tedlevelnum = atoi(_argv[i + 1]);\r
+                  if (tedlevelnum >= 0)\r
+                    tedlevel = true;\r
+                  break;\r
+\r
+                case 1:\r
+                  NoWait = true;\r
+                  break;\r
+               }\r
+       }\r
+\r
+       US_Started = true;\r
+}\r
+\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_Shutdown() - Shuts down the User Mgr\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_Shutdown(void)\r
+{\r
+       if (!US_Started)\r
+               return;\r
+\r
+       US_Started = false;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_CheckParm() - checks to see if a string matches one of a set of\r
+//             strings. The check is case insensitive. The routine returns the\r
+//             index of the string that matched, or -1 if no matches were found\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+int\r
+US_CheckParm(char *parm,char **strings)\r
+{\r
+       char    cp,cs,\r
+                       *p,*s;\r
+       int             i;\r
+\r
+       while (!isalpha(*parm)) // Skip non-alphas\r
+               parm++;\r
+\r
+       for (i = 0;*strings && **strings;i++)\r
+       {\r
+               for (s = *strings++,p = parm,cs = cp = 0;cs == cp;)\r
+               {\r
+                       cs = *s++;\r
+                       if (!cs)\r
+                               return(i);\r
+                       cp = *p++;\r
+\r
+                       if (isupper(cs))\r
+                               cs = tolower(cs);\r
+                       if (isupper(cp))\r
+                               cp = tolower(cp);\r
+               }\r
+       }\r
+       return(-1);\r
+}\r
+\r
+\r
+//     Window/Printing routines\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_SetPrintRoutines() - Sets the routines used to measure and print\r
+//             from within the User Mgr. Primarily provided to allow switching\r
+//             between masked and non-masked fonts\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_SetPrintRoutines(void (*measure)(char far *,word *,word *),void (*print)(char far *))\r
+{\r
+       USL_MeasureString = measure;\r
+       USL_DrawString = print;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_Print() - Prints a string in the current window. Newlines are\r
+//             supported.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_Print(char far *s)\r
+{\r
+       char    c,far *se;\r
+       word    w,h;\r
+\r
+       while (*s)\r
+       {\r
+               se = s;\r
+               while ((c = *se) && (c != '\n'))\r
+                       se++;\r
+               *se = '\0';\r
+\r
+               USL_MeasureString(s,&w,&h);\r
+               px = PrintX;\r
+               py = PrintY;\r
+               USL_DrawString(s);\r
+\r
+               s = se;\r
+               if (c)\r
+               {\r
+                       *se = c;\r
+                       s++;\r
+\r
+                       PrintX = WindowX;\r
+                       PrintY += h;\r
+               }\r
+               else\r
+                       PrintX += w;\r
+       }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_PrintUnsigned() - Prints an unsigned long\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_PrintUnsigned(word n)\r
+{\r
+       char    buffer[32];\r
+\r
+       US_Print(ultoa(n,buffer,10));\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_PrintSigned() - Prints a signed long\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_PrintSigned(long n)\r
+{\r
+       char    buffer[32];\r
+\r
+       US_Print(ltoa(n,buffer,10));\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     USL_PrintInCenter() - Prints a string in the center of the given rect\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+USL_PrintInCenter(char far *s,Rect r)\r
+{\r
+       word    w,h,\r
+                       rw,rh;\r
+\r
+       USL_MeasureString(s,&w,&h);\r
+       rw = r.lr.x - r.ul.x;\r
+       rh = r.lr.y - r.ul.y;\r
+\r
+       px = r.ul.x + ((rw - w) / 2);\r
+       py = r.ul.y + ((rh - h) / 2);\r
+       USL_DrawString(s);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_PrintCentered() - Prints a string centered in the current window.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_PrintCentered(char far *s)\r
+{\r
+       Rect    r;\r
+\r
+       r.ul.x = WindowX;\r
+       r.ul.y = WindowY;\r
+       r.lr.x = r.ul.x + WindowW;\r
+       r.lr.y = r.ul.y + WindowH;\r
+\r
+       USL_PrintInCenter(s,r);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_CPrintLine() - Prints a string centered on the current line and\r
+//             advances to the next line. Newlines are not supported.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_CPrintLine(char far *s)\r
+{\r
+       word    w,h;\r
+\r
+       USL_MeasureString(s,&w,&h);\r
+\r
+       if (w > WindowW)\r
+               Quit("US_CPrintLine() - String exceeds width");\r
+       px = WindowX + ((WindowW - w) / 2);\r
+       py = PrintY;\r
+       USL_DrawString(s);\r
+       PrintY += h;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_CPrint() - Prints a string in the current window. Newlines are\r
+//             supported.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_CPrint(char far *s)\r
+{\r
+       char    c,far *se;\r
+\r
+       while (*s)\r
+       {\r
+               se = s;\r
+               while ((c = *se) && (c != '\n'))\r
+                       se++;\r
+               *se = '\0';\r
+\r
+               US_CPrintLine(s);\r
+\r
+               s = se;\r
+               if (c)\r
+               {\r
+                       *se = c;\r
+                       s++;\r
+               }\r
+       }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_ClearWindow() - Clears the current window to white and homes the\r
+//             cursor\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_ClearWindow(void)\r
+{\r
+       VWB_Bar(WindowX,WindowY,WindowW,WindowH,WHITE);\r
+       PrintX = WindowX;\r
+       PrintY = WindowY;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_DrawWindow() - Draws a frame and sets the current window parms\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_DrawWindow(word x,word y,word w,word h)\r
+{\r
+       word    i,\r
+                       sx,sy,sw,sh;\r
+\r
+       WindowX = x * 8;\r
+       WindowY = y * 8;\r
+       WindowW = w * 8;\r
+       WindowH = h * 8;\r
+\r
+       PrintX = WindowX;\r
+       PrintY = WindowY;\r
+\r
+       sx = (x - 1) * 8;\r
+       sy = (y - 1) * 8;\r
+       sw = (w + 1) * 8;\r
+       sh = (h + 1) * 8;\r
+\r
+       US_ClearWindow();\r
+\r
+       VWB_DrawTile8(sx,sy,0),VWB_DrawTile8(sx,sy + sh,5);\r
+       for (i = sx + 8;i <= sx + sw - 8;i += 8)\r
+               VWB_DrawTile8(i,sy,1),VWB_DrawTile8(i,sy + sh,6);\r
+       VWB_DrawTile8(i,sy,2),VWB_DrawTile8(i,sy + sh,7);\r
+\r
+       for (i = sy + 8;i <= sy + sh - 8;i += 8)\r
+               VWB_DrawTile8(sx,i,3),VWB_DrawTile8(sx + sw,i,4);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_CenterWindow() - Generates a window of a given width & height in the\r
+//             middle of the screen\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_CenterWindow(word w,word h)\r
+{\r
+       US_DrawWindow(((MaxX / 8) - w) / 2,((MaxY / 8) - h) / 2,w,h);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_SaveWindow() - Saves the current window parms into a record for\r
+//             later restoration\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_SaveWindow(WindowRec *win)\r
+{\r
+       win->x = WindowX;\r
+       win->y = WindowY;\r
+       win->w = WindowW;\r
+       win->h = WindowH;\r
+\r
+       win->px = PrintX;\r
+       win->py = PrintY;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_RestoreWindow() - Sets the current window parms to those held in the\r
+//             record\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_RestoreWindow(WindowRec *win)\r
+{\r
+       WindowX = win->x;\r
+       WindowY = win->y;\r
+       WindowW = win->w;\r
+       WindowH = win->h;\r
+\r
+       PrintX = win->px;\r
+       PrintY = win->py;\r
+}\r
+\r
+//     Input routines\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     USL_XORICursor() - XORs the I-bar text cursor. Used by US_LineInput()\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_XORICursor(int x,int y,char *s,word cursor)\r
+{\r
+       static  boolean status;         // VGA doesn't XOR...\r
+       char    buf[MaxString];\r
+       int             temp;\r
+       word    w,h;\r
+\r
+       strcpy(buf,s);\r
+       buf[cursor] = '\0';\r
+       USL_MeasureString(buf,&w,&h);\r
+\r
+       px = x + w - 1;\r
+       py = y;\r
+       if (status^=1)\r
+               USL_DrawString("\x80");\r
+       else\r
+       {\r
+               temp = fontcolor;\r
+               fontcolor = backcolor;\r
+               USL_DrawString("\x80");\r
+               fontcolor = temp;\r
+       }\r
+\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+//     US_LineInput() - Gets a line of user input at (x,y), the string defaults\r
+//             to whatever is pointed at by def. Input is restricted to maxchars\r
+//             chars or maxwidth pixels wide. If the user hits escape (and escok is\r
+//             true), nothing is copied into buf, and false is returned. If the\r
+//             user hits return, the current string is copied into buf, and true is\r
+//             returned\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+boolean\r
+US_LineInput(int x,int y,char *buf,char *def,boolean escok,\r
+                               int maxchars,int maxwidth)\r
+{\r
+       boolean         redraw,\r
+                               cursorvis,cursormoved,\r
+                               done,result;\r
+       ScanCode        sc;\r
+       char            c,\r
+                               s[MaxString],olds[MaxString];\r
+       word            i,\r
+                               cursor,\r
+                               w,h,\r
+                               len,temp;\r
+       word    lasttime;\r
+       word TimeCount = *clockw;\r
+\r
+       if (def)\r
+               strcpy(s,def);\r
+       else\r
+               *s = '\0';\r
+       *olds = '\0';\r
+       cursor = strlen(s);\r
+       cursormoved = redraw = true;\r
+\r
+       cursorvis = done = false;\r
+       lasttime = TimeCount;\r
+       LastASCII = key_None;\r
+       LastScan = sc_None;\r
+\r
+       while (!done)\r
+       {\r
+               if (cursorvis)\r
+                       USL_XORICursor(x,y,s,cursor);\r
+\r
+       asm     pushf\r
+       asm     cli\r
+\r
+               sc = LastScan;\r
+               LastScan = sc_None;\r
+               c = LastASCII;\r
+               LastASCII = key_None;\r
+\r
+       asm     popf\r
+\r
+               switch (sc)\r
+               {\r
+               case sc_LeftArrow:\r
+                       if (cursor)\r
+                               cursor--;\r
+                       c = key_None;\r
+                       cursormoved = true;\r
+                       break;\r
+               case sc_RightArrow:\r
+                       if (s[cursor])\r
+                               cursor++;\r
+                       c = key_None;\r
+                       cursormoved = true;\r
+                       break;\r
+               case sc_Home:\r
+                       cursor = 0;\r
+                       c = key_None;\r
+                       cursormoved = true;\r
+                       break;\r
+               case sc_End:\r
+                       cursor = strlen(s);\r
+                       c = key_None;\r
+                       cursormoved = true;\r
+                       break;\r
+\r
+               case sc_Return:\r
+                       strcpy(buf,s);\r
+                       done = true;\r
+                       result = true;\r
+                       c = key_None;\r
+                       break;\r
+               case sc_Escape:\r
+                       if (escok)\r
+                       {\r
+                               done = true;\r
+                               result = false;\r
+                       }\r
+                       c = key_None;\r
+                       break;\r
+\r
+               case sc_BackSpace:\r
+                       if (cursor)\r
+                       {\r
+                               strcpy(s + cursor - 1,s + cursor);\r
+                               cursor--;\r
+                               redraw = true;\r
+                       }\r
+                       c = key_None;\r
+                       cursormoved = true;\r
+                       break;\r
+               case sc_Delete:\r
+                       if (s[cursor])\r
+                       {\r
+                               strcpy(s + cursor,s + cursor + 1);\r
+                               redraw = true;\r
+                       }\r
+                       c = key_None;\r
+                       cursormoved = true;\r
+                       break;\r
+\r
+               case 0x4c:      // Keypad 5\r
+               case sc_UpArrow:\r
+               case sc_DownArrow:\r
+               case sc_PgUp:\r
+               case sc_PgDn:\r
+               case sc_Insert:\r
+                       c = key_None;\r
+                       break;\r
+               }\r
+\r
+               if (c)\r
+               {\r
+                       len = strlen(s);\r
+                       USL_MeasureString(s,&w,&h);\r
+\r
+                       if\r
+                       (\r
+                               isprint(c)\r
+                       &&      (len < MaxString - 1)\r
+                       &&      ((!maxchars) || (len < maxchars))\r
+                       &&      ((!maxwidth) || (w < maxwidth))\r
+                       )\r
+                       {\r
+                               for (i = len + 1;i > cursor;i--)\r
+                                       s[i] = s[i - 1];\r
+                               s[cursor++] = c;\r
+                               redraw = true;\r
+                       }\r
+               }\r
+\r
+               if (redraw)\r
+               {\r
+                       px = x;\r
+                       py = y;\r
+                       temp = fontcolor;\r
+                       fontcolor = backcolor;\r
+                       USL_DrawString(olds);\r
+                       fontcolor = temp;\r
+                       strcpy(olds,s);\r
+\r
+                       px = x;\r
+                       py = y;\r
+                       USL_DrawString(s);\r
+\r
+                       redraw = false;\r
+               }\r
+\r
+               if (cursormoved)\r
+               {\r
+                       cursorvis = false;\r
+                       lasttime = TimeCount - TickBase;\r
+\r
+                       cursormoved = false;\r
+               }\r
+               if (TimeCount - lasttime > TickBase / 2)\r
+               {\r
+                       lasttime = TimeCount;\r
+\r
+                       cursorvis ^= true;\r
+               }\r
+               if (cursorvis)\r
+                       USL_XORICursor(x,y,s,cursor);\r
+\r
+               //++++VW_UpdateScreen();\r
+       }\r
+\r
+       if (cursorvis)\r
+               USL_XORICursor(x,y,s,cursor);\r
+       if (!result)\r
+       {\r
+               px = x;\r
+               py = y;\r
+               USL_DrawString(olds);\r
+       }\r
+       //++++VW_UpdateScreen();\r
+\r
+       IN_ClearKeysDown();\r
+       return(result);\r
+}\r
+\r
+#if 0\r
+\r
+#define PaddleMinX      (CtlPanelSX + 3)\r
+#define PaddleMaxX      (CtlPanelEX - 15)\r
+#define BallMinX        (CtlPanelSX + 2)\r
+#define BallMinY        (CtlPanelSY + 12 + 2)\r
+#define BallMaxX        (CtlPanelEX - 6)\r
+#define BallMaxY        (CtlPanelEY - 13)\r
+#define CPaddleY        (BallMinY + 4)\r
+#define KPaddleY        (BallMaxY - 2)\r
+void\r
+USL_DrawPongScore(word k,word c)\r
+{\r
+       fontcolor = HiliteColor;\r
+       PrintY = py = CtlPanelSY + 4;\r
+       px = CtlPanelSX + 6;\r
+       VWB_Bar(px,py,42,6,BackColor);\r
+       USL_DrawString("YOU:");\r
+       PrintX = px;\r
+       US_PrintUnsigned(k);\r
+       px = CtlPanelSX + 108;\r
+       VWB_Bar(px,py,50,6,BackColor);\r
+       USL_DrawString("COMP:");\r
+       PrintX = px;\r
+       US_PrintUnsigned(c);\r
+}\r
+\r
+void\r
+USL_PlayPong(void)\r
+{\r
+       boolean         ball,killball,revdir,done,lastscore;\r
+       word            cycle,\r
+                               x,y,\r
+                               kx,cx,\r
+                               rx,\r
+                               bx,by,\r
+                               kscore,cscore,\r
+                               speedup;\r
+       int                     bdx,bdy;\r
+       word        balltime,waittime;\r
+       CursorInfo      cursorinfo;\r
+\r
+       kx = cx = PaddleMinX + ((PaddleMaxX - PaddleMinX) / 2);\r
+       bx = by = bdx = bdy = 0;\r
+       kscore = cscore = 0;\r
+       USL_DrawPongScore(0,0);\r
+       cycle = 0;\r
+       revdir = false;\r
+       killball = true;\r
+       done = false;\r
+       lastscore = false;\r
+       do\r
+       {\r
+               waittime = TimeCount;\r
+\r
+               IN_ReadCursor(&cursorinfo);\r
+               if (((cursorinfo.x < 0) || IN_KeyDown(sc_LeftArrow)) && (kx > PaddleMinX))\r
+                       kx -= 2;\r
+               else if (((cursorinfo.x > 0) || IN_KeyDown(sc_RightArrow)) && (kx < PaddleMaxX))\r
+                       kx += 2;\r
+\r
+               if (killball)\r
+               {\r
+                       ball = false;\r
+                       balltime = TimeCount + TickBase;\r
+                       speedup = 10;\r
+                       killball = false;\r
+               }\r
+\r
+               if (ball && (cycle++ % 3))\r
+               {\r
+                       x = (bx >> 2);\r
+                       if (!(x & 1))\r
+                               x += (US_RndT() & 1);\r
+\r
+                       if ((cx + 6 < x) && (cx < PaddleMaxX))\r
+                               cx += 1;\r
+                       else if ((cx + 6 > x) && (cx > PaddleMinX))\r
+                               cx -= 1;\r
+               }\r
+\r
+               VWB_Bar(BallMinX,BallMinY - 1,\r
+                               BallMaxX - BallMinX + 5,BallMaxY - BallMinY + 7,\r
+                               BackColor);\r
+               VWB_DrawSprite(cx,CPaddleY,PADDLESPR);\r
+               VWB_DrawSprite(kx,KPaddleY,PADDLESPR);\r
+               if (ball)\r
+               {\r
+                       if\r
+                       (\r
+                               (((bx + bdx) >> 2) > BallMaxX)\r
+                       ||      (((bx + bdx) >> 2) < BallMinX)\r
+                       )\r
+                       {\r
+                               SD_PlaySound(BALLBOUNCESND);\r
+                               bdx = -bdx;\r
+                       }\r
+                       bx += bdx;\r
+\r
+                       if (((by + bdy) >> 2) > BallMaxY)\r
+                       {\r
+                               killball = true;\r
+                               lastscore = false;\r
+                               cscore++;\r
+                               SD_PlaySound(COMPSCOREDSND);\r
+                               USL_DrawPongScore(kscore,cscore);\r
+                               if (cscore == 21)\r
+                               {\r
+                                       USL_CtlDialog("You lost!","Press any key",nil);\r
+                                       done = true;\r
+                                       continue;\r
+                               }\r
+                       }\r
+                       else if (((by + bdy) >> 2) < BallMinY)\r
+                       {\r
+                               killball = true;\r
+                               lastscore = true;\r
+                               kscore++;\r
+                               SD_PlaySound(KEENSCOREDSND);\r
+                               USL_DrawPongScore(kscore,cscore);\r
+                               if (kscore == 21)\r
+                               {\r
+                                       USL_CtlDialog("You won!","Press any key",nil);\r
+                                       done = true;\r
+                                       continue;\r
+                               }\r
+                       }\r
+                       by += bdy;\r
+\r
+                       x = bx >> 2;\r
+                       y = by >> 2;\r
+                       if (!killball)\r
+                       {\r
+                               if\r
+                               (\r
+                                       (bdy < 0)\r
+                               &&      ((y >= CPaddleY) && (y < CPaddleY + 3))\r
+                               &&      ((x >= (cx - 5)) && (x < (cx + 11)))\r
+                               )\r
+                               {\r
+                                       rx = cx;\r
+                                       revdir = true;\r
+                                       SD_PlaySound(COMPPADDLESND);\r
+                               }\r
+                               else if\r
+                               (\r
+                                       (bdy > 0)\r
+                               &&      ((y >= (KPaddleY - 3)) && (y < KPaddleY))\r
+                               &&      ((x >= (kx - 5)) && (x < (kx + 11)))\r
+                               )\r
+                               {\r
+                                       if (((bdy >> 2) < 3) && !(--speedup))\r
+                                       {\r
+                                               bdy++;\r
+                                               speedup = 10;\r
+                                       }\r
+                                       rx = kx;\r
+                                       revdir = true;\r
+                                       SD_PlaySound(KEENPADDLESND);\r
+                               }\r
+                               if (revdir)\r
+                               {\r
+                                       bdy = -bdy;\r
+                                       bdx = ((x + 5 - rx) >> 1) - (1 << 2);\r
+                                       if (!bdx)\r
+                                               bdx--;\r
+                                       revdir = false;\r
+                               }\r
+                       }\r
+                       VWB_DrawSprite(x,y,(x & 1)? BALL1PIXELTOTHERIGHTSPR : BALLSPR);\r
+               }\r
+               else if (TimeCount >= balltime)\r
+               {\r
+                       ball = true;\r
+                       bdx = 1 - (US_RndT() % 3);\r
+                       bdy = 2;\r
+                       if (lastscore)\r
+                               bdy = -bdy;\r
+                       bx = (BallMinX + ((BallMaxX - BallMinX) / 2)) << 2;\r
+                       by = (BallMinY + ((BallMaxY - BallMinY) / 2)) << 2;\r
+               }\r
+               //++++VW_UpdateScreen();\r
+               while (waittime == TimeCount)\r
+                       ;       // DEBUG - do adaptiveness\r
+       } while ((LastScan != sc_Escape) && !done);\r
+       IN_ClearKeysDown();\r
+}\r
+\r
+#pragma argsused\r
+static boolean\r
+USL_PongCustom(UserCall call,struct UserItem far *item)\r
+{\r
+       if (call != uic_SetupCard)\r
+               return(false);\r
+\r
+       VWB_DrawPic(0,0,CP_MENUSCREENPIC);\r
+       VWB_DrawPic(CtlPanelSX + 56,CtlPanelSY,CP_PADDLEWARPIC);\r
+       VWB_Hlin(CtlPanelSX + 3,CtlPanelEX - 3,CtlPanelSY + 12,HiliteColor ^ BackColor);\r
+       VWB_Hlin(CtlPanelSX + 3,CtlPanelEX - 3,CtlPanelEY - 7,HiliteColor ^ BackColor);\r
+       USL_PlayPong();\r
+\r
+       return(true);\r
+}\r
+\r
+#endif\r