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