X-Git-Url: http://4ch.mooo.com/gitweb/?p=16.git;a=blobdiff_plain;f=16%2Fkeen456%2FKEEN4-6%2FID_US_1.C;fp=16%2Fkeen456%2FKEEN4-6%2FID_US_1.C;h=d7b27aacf7ac24236dc6d7603005ca29e2dd6829;hp=0000000000000000000000000000000000000000;hb=7d1948e210bb7b58af0a0412e71f2a0a0a2010af;hpb=ebc247a0a67daa69a027f31d9d7d9572db765e56 diff --git a/16/keen456/KEEN4-6/ID_US_1.C b/16/keen456/KEEN4-6/ID_US_1.C new file mode 100755 index 00000000..d7b27aac --- /dev/null +++ b/16/keen456/KEEN4-6/ID_US_1.C @@ -0,0 +1,1358 @@ +/* Reconstructed Commander Keen 4-6 Source Code + * Copyright (C) 2021 K1n9_Duk3 + * + * This file is primarily based on: + * Catacomb 3-D Source Code + * Copyright (C) 1993-2014 Flat Rock Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +// +// ID Engine +// ID_US_1.c - User Manager - General routines +// v1.1d1 +// By Jason Blochowiak +// Hacked up for Catacomb 3D +// + +// +// 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 "ID_HEADS.H" + +#pragma hdrstop + +#pragma warn -pia + + +// Special imports +extern boolean showscorebox; +#ifdef KEEN +extern boolean jerk; +extern boolean oldshooting; +extern ScanCode firescan; +#else + ScanCode firescan; +#endif + +// Global variables + char *abortprogram; + boolean NoWait, + HighScoresDirty; + word PrintX,PrintY; + word WindowX,WindowY,WindowW,WindowH; + +// Internal variables +#define ConfigVersion 4 + +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; + + boolean (*USL_SaveGame)(int),(*USL_LoadGame)(int); + void (*USL_ResetGame)(void); + SaveGame Games[MaxSaveGames]; + HighScore Scores[MaxScores] = + { +#if defined CAT3D + {"Sir Lancelot",500,3}, + {"",0}, + {"",0}, + {"",0}, + {"",0}, + {"",0}, + {"",0}, +#elif defined GOODTIMES + {"Id Software",10000,0}, + {"Adrian Carmack",10000,0}, + {"John Carmack",10000,0}, + {"Kevin Cloud",10000,0}, + {"Shawn Green",10000,0}, + {"Tom Hall",10000,0}, + {"John Romero",10000,0}, + {"Jay Wilbur",10000,0}, +#else + {"Id Software - '91",10000,0}, + {"",10000,0}, + {"Jason Blochowiak",10000,0}, + {"Adrian Carmack",10000,0}, + {"John Carmack",10000,0}, + {"Tom Hall",10000,0}, + {"John Romero",10000,0}, + {"",10000,0}, +#endif + }; + +// 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 di; + char c,*s,*t; + + + di = _DI; + + if (ax < 0) + s = "Device Error"; + else + { + if ((di & 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 + +/////////////////////////////////////////////////////////////////////////// +// +// USL_GiveSaveName() - Returns a pointer to a static buffer that contains +// the filename to use for the specified save game +// +/////////////////////////////////////////////////////////////////////////// +char * +USL_GiveSaveName(word game) +{ +static char name[] = "SAVEGAMx."EXTENSION; + + name[7] = '0' + game; + return(name); +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_SetLoadSaveHooks() - Sets the routines that the User Mgr calls after +// reading or writing the save game headers +// +/////////////////////////////////////////////////////////////////////////// +void +US_SetLoadSaveHooks(boolean (*load)(int),boolean (*save)(int),void (*reset)(void)) +{ + USL_LoadGame = load; + USL_SaveGame = save; + USL_ResetGame = reset; +} + +/////////////////////////////////////////////////////////////////////////// +// +// USL_ReadConfig() - Reads the configuration file, if present, and sets +// things up accordingly. If it's not present, uses defaults. This file +// includes the high scores. +// +/////////////////////////////////////////////////////////////////////////// +static void +USL_ReadConfig(void) +{ + boolean gotit, hadAdLib; + char sig[sizeof(EXTENSION)]; + word version; + int file; + SDMode sd; + SMMode sm; + ControlType ctl; + + if ((file = open("CONFIG."EXTENSION,O_BINARY | O_RDONLY)) != -1) + { + read(file,sig,sizeof(EXTENSION)); + read(file,&version,sizeof(version)); + if (strcmp(sig,EXTENSION) || (version != ConfigVersion)) + { + close(file); + goto rcfailed; + } + read(file,Scores,sizeof(HighScore) * MaxScores); + read(file,&sd,sizeof(sd)); + read(file,&sm,sizeof(sm)); + read(file,&ctl,sizeof(ctl)); + read(file,&(KbdDefs[0]),sizeof(KbdDefs[0])); + read(file,&showscorebox,sizeof(showscorebox)); + read(file,&compatability,sizeof(compatability)); + read(file,&QuietFX,sizeof(QuietFX)); + read(file,&hadAdLib,sizeof(hadAdLib)); + read(file,&jerk,sizeof(jerk)); +#ifdef KEEN + read(file,&oldshooting,sizeof(oldshooting)); + read(file,&firescan,sizeof(firescan)); +#endif + read(file,&GravisGamepad,sizeof(GravisGamepad)); + read(file,&GravisMap,sizeof(GravisMap)); + close(file); + + HighScoresDirty = false; + gotit = true; + } + else + { +rcfailed: + sd = sdm_Off; + sm = smm_Off; + ctl = ctrl_Keyboard; + showscorebox = true; +#ifdef KEEN + oldshooting = false; +#endif + + gotit = false; + HighScoresDirty = true; + } + + SD_Default(gotit? (hadAdLib==AdLibPresent) : false, sd,sm); + IN_Default(gotit,ctl); +} + +/////////////////////////////////////////////////////////////////////////// +// +// USL_WriteConfig() - Writes out the current configuration, including the +// high scores. +// +/////////////////////////////////////////////////////////////////////////// +static void +USL_WriteConfig(void) +{ + word version; + int file; + + version = ConfigVersion; + file = open("CONFIG."EXTENSION,O_CREAT | O_BINARY | O_WRONLY, + S_IREAD | S_IWRITE | S_IFREG); + if (file != -1) + { + write(file,EXTENSION,sizeof(EXTENSION)); + write(file,&version,sizeof(version)); + write(file,Scores,sizeof(HighScore) * MaxScores); + write(file,&SoundMode,sizeof(SoundMode)); + write(file,&MusicMode,sizeof(MusicMode)); +#ifdef CAT3D + if // Hack + ( + (Controls[0] == ctrl_Joystick1) + || (Controls[0] == ctrl_Joystick2) + ) + Controls[0] = ctrl_Keyboard; +#endif + write(file,&(Controls[0]),sizeof(Controls[0])); + write(file,&(KbdDefs[0]),sizeof(KbdDefs[0])); + write(file,&showscorebox,sizeof(showscorebox)); + write(file,&compatability,sizeof(compatability)); + write(file,&QuietFX,sizeof(QuietFX)); + write(file,&AdLibPresent,sizeof(AdLibPresent)); + write(file,&jerk,sizeof(jerk)); +#ifdef KEEN + write(file,&oldshooting,sizeof(oldshooting)); + write(file,&firescan,sizeof(firescan)); +#endif + write(file,&GravisGamepad,sizeof(GravisGamepad)); + write(file,&GravisMap,sizeof(GravisMap)); + close(file); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// USL_CheckSavedGames() - Checks to see which saved games are present +// & valid +// +/////////////////////////////////////////////////////////////////////////// +#ifdef KEEN +void +#else +static void +#endif +USL_CheckSavedGames(void) +{ + boolean ok; + char *filename; + word i; + int file; + SaveGame *game; + +#ifdef CAT3D + USL_SaveGame = 0; + USL_LoadGame = 0; +#endif + + for (i = 0,game = Games;i < MaxSaveGames;i++,game++) + { + filename = USL_GiveSaveName(i); + ok = false; + if ((file = open(filename,O_BINARY | O_RDONLY)) != -1) + { + if + ( + (read(file,game,sizeof(*game)) == sizeof(*game)) + && (!strcmp(game->signature,EXTENSION)) + && (game->oldtest == &PrintX) + ) + ok = true; + + close(file); + } + + if (ok) + game->present = true; + else + { + strcpy(game->signature,EXTENSION); + game->present = false; + strcpy(game->name,"Empty"); + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_Startup() - Starts the User Mgr +// +/////////////////////////////////////////////////////////////////////////// +void +US_Startup(void) +{ + int i; + + if (US_Started) + return; + + harderr(USL_HardError); // Install the fatal error handler + + US_InitRndT(true); // Initialize the random number generator + + USL_ReadConfig(); // Read config file + + for (i = 1;i < _argc;i++) + { + switch (US_CheckParm(_argv[i],ParmStrings2)) + { + case 0: + if (grmode == EGAGR) + compatability = true; + break; + case 1: + compatability = false; + break; + } + } + + US_Started = true; +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_Setup() - Does the disk access part of the User Mgr's startup +// +/////////////////////////////////////////////////////////////////////////// +void +US_Setup(void) +{ +#ifndef CAT3D + USL_SaveGame = 0; + USL_LoadGame = 0; +#endif + USL_CheckSavedGames(); // Check which saved games are present +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_Shutdown() - Shuts down the User Mgr +// +/////////////////////////////////////////////////////////////////////////// +void +US_Shutdown(void) +{ + if (!US_Started) + return; + + if (!abortprogram) + USL_WriteConfig(); + + 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); +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_ParmPresent() - checks if a given string was passed as a command +// line parameter at startup +// +/////////////////////////////////////////////////////////////////////////// +boolean +US_ParmPresent(char *arg) +{ + int i; + char *strings[2]; + + strings[0] = arg; + strings[1] = NULL; + + for (i=1; i<_argc; i++) + { + if (US_CheckParm(_argv[i], strings) != -1) + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////// +// +// USL_ScreenDraw() - Draws a chunk of the text screen (called only by +// US_TextScreen()) +// +/////////////////////////////////////////////////////////////////////////// +static void +USL_ScreenDraw(word x,word y,char *s,byte attr) +{ + byte far *screen,far *oscreen; + + screen = MK_FP(0xb800,(x * 2) + (y * 80 * 2)); + oscreen = (&introscn + 7) + ((x - 1) * 2) + (y * 80 * 2) + 1; + while (*s) + { + *screen++ = *s++; + if (attr != 0xff) + { + *screen++ = (attr & 0x8f) | (*oscreen & 0x70); + oscreen += 2; + } + else + screen++; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// USL_ClearTextScreen() - Makes sure the screen is in text mode, clears it, +// and moves the cursor to the leftmost column of the bottom line +// +/////////////////////////////////////////////////////////////////////////// +static void +USL_ClearTextScreen(void) +{ + // Set to 80x25 color text mode + _AL = 3; // Mode 3 + _AH = 0x00; + geninterrupt(0x10); + + // Use BIOS to move the cursor to the bottom of the screen + _AH = 0x0f; + geninterrupt(0x10); // Get current video mode into _BH + _DL = 0; // Lefthand side of the screen + _DH = 24; // Bottom row + _AH = 0x02; + geninterrupt(0x10); +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_TextScreen() - Puts up the startup text screen +// Note: These are the only User Manager functions that can be safely called +// before the User Mgr has been started up +// +/////////////////////////////////////////////////////////////////////////// +void +US_TextScreen(void) +{ + word i,n; + + USL_ClearTextScreen(); + + _fmemcpy(MK_FP(0xb800,0),7 + &introscn,80 * 25 * 2); + + // Check for TED launching here + for (i = 1;i < _argc;i++) + { + n = US_CheckParm(_argv[i],ParmStrings); + if (n == 0) + { + tedlevelnum = atoi(_argv[i + 1]); + if (tedlevelnum >= 0) + { + tedlevel = true; + return; + } + else + break; + } + else if (n == 1) + { + NoWait = true; + return; + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// USL_Show() - Changes the appearance of one of the fields on the text +// screen. Possibly adds a checkmark in front of it and highlights it +// +/////////////////////////////////////////////////////////////////////////// +static void +USL_Show(word x,word y,word w,boolean show,boolean hilight) +{ + byte far *screen,far *oscreen; + + screen = MK_FP(0xb800,((x - 1) * 2) + (y * 80 * 2)); + oscreen = (&introscn + 7) + ((x - 1) * 2) + (y * 80 * 2) - 1; + *screen++ = show? 251 : ' '; // Checkmark char or space +// *screen = 0x48; +// *screen = (*oscreen & 0xf0) | 8; + oscreen += 2; + if (show && hilight) + { + for (w++;w--;screen += 2,oscreen += 2) + *screen = (*oscreen & 0xf0) | 0x0f; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// USL_ShowMem() - Right justifies a longword in one of the memory fields on +// the text screen +// +/////////////////////////////////////////////////////////////////////////// +static void +USL_ShowMem(word x,word y,long mem) +{ + char buf[16]; + word i; + + for (i = strlen(ltoa(mem,buf,10));i < 5;i++) + USL_ScreenDraw(x++,y," ",0xff); + USL_ScreenDraw(x,y,buf,0xff); +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_UpdateTextScreen() - Called after the ID libraries are started up. +// Displays what hardware is present. +// +/////////////////////////////////////////////////////////////////////////// +void +US_UpdateTextScreen(void) +{ + boolean b; + longword totalmem; + + // Show video card info + b = (grmode == CGAGR); + USL_Show(21,7,4,(videocard >= CGAcard) && (videocard <= VGAcard),b); + b = (grmode == EGAGR || grmode == VGAGR); + USL_Show(21,8,7,(videocard >= EGAcard) && (videocard <= VGAcard),b); +// b = (grmode == VGAGR); +// USL_Show(21,9,4,videocard == VGAcard,b); +#if GRMODE != CGAGR + if (compatability) + USL_ScreenDraw(5,10,"SVGA Compatibility Mode Enabled.",0x4f); +#endif + + // Show input device info + USL_Show(60,7,8,true,true); + USL_Show(60,8,11,JoysPresent[0],true); + USL_Show(60,9,11,JoysPresent[1],true); + USL_Show(60,10,5,MousePresent,true); + + // Show sound hardware info + USL_Show(21,14,11,true,SoundMode == sdm_PC); + b = (SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib); + USL_Show(21,15,14,AdLibPresent,b); + if (b && AdLibPresent) // Hack because of two lines + { + byte far *screen,far *oscreen; + word x,y,w; + + x = 21; + y = 16; + w = 14; + screen = MK_FP(0xb800,(x * 2) + (y * 80 * 2) - 1); + oscreen = (&introscn + 7) + (x * 2) + (y * 80 * 2) - 1; + oscreen += 2; + for (w++;w--;screen += 2,oscreen += 2) + *screen = (*oscreen & 0xf0) | 0x0f; + } + + // Show memory available/used + USL_ShowMem(63,15,mminfo.mainmem / 1024); + USL_Show(53,15,23,true,true); + USL_ShowMem(63,16,mminfo.EMSmem / 1024); + USL_Show(53,16,23,mminfo.EMSmem? true : false,true); + USL_ShowMem(63,17,mminfo.XMSmem / 1024); + USL_Show(53,17,23,mminfo.XMSmem? true : false,true); + totalmem = mminfo.mainmem + mminfo.EMSmem + mminfo.XMSmem; + USL_ShowMem(63,18,totalmem / 1024); + USL_Show(53,18,23,true,true); // DEBUG + USL_ScreenDraw(52,18," ",0xff); + + // Change Initializing... to Loading... + USL_ScreenDraw(27,22," Loading... ",0x9c); +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_FinishTextScreen() - After the main program has finished its initial +// loading, this routine waits for a keypress and then clears the screen +// +/////////////////////////////////////////////////////////////////////////// +void +US_FinishTextScreen(void) +{ +static byte colors[] = {4,6,13,15,15,15,15,15,15}; + boolean up; + int i,c; + + // Change Loading... to Press a Key + + if (!(tedlevel || NoWait)) + { + IN_ClearKeysDown(); + for (i = 0,up = true;!IN_UserInput(4,true);) + { + c = colors[i]; + if (up) + { + if (++i == 9) + i = 8,up = false; + } + else + { + if (--i < 0) + i = 1,up = true; + } + + USL_ScreenDraw(29,22," Ready - Press a Key ",0x00 + c); + } + } + else + USL_ScreenDraw(29,22," Ready - Press a Key ",0x9a); + + IN_ClearKeysDown(); + + USL_ClearTextScreen(); +} + +// 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 *s) +{ + char c,*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(longword 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 *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 *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 *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 *s) +{ + char c,*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_DrawTile8M(sx,sy,0),VWB_DrawTile8M(sx,sy + sh,6); + for (i = sx + 8;i <= sx + sw - 8;i += 8) + VWB_DrawTile8M(i,sy,1),VWB_DrawTile8M(i,sy + sh,7); + VWB_DrawTile8M(i,sy,2),VWB_DrawTile8M(i,sy + sh,8); + + for (i = sy + 8;i <= sy + sh - 8;i += 8) + VWB_DrawTile8M(sx,i,3),VWB_DrawTile8M(sx + sw,i,5); +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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_CenterSaveWindow() - Generates a window of a given width & height in +// the middle of the screen, saving the background +// +/////////////////////////////////////////////////////////////////////////// +void +US_CenterSaveWindow(word w,word h,memptr *save) +{ + word x,y, + screen; + + x = ((MaxX / 8) - w) / 2; + y = ((MaxY / 8) - h) / 2; + MM_GetPtr(save,(w * h) * CHARWIDTH); + screen = bufferofs + panadjust + ylookup[y] + (x * CHARWIDTH); + VW_ScreenToMem(screen,*save,w * CHARWIDTH,h); + US_DrawWindow(((MaxX / 8) - w) / 2,((MaxY / 8) - h) / 2,w,h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_RestoreSaveWindow() - Restores the background of the size of the +// current window from the memory specified by save +// +/////////////////////////////////////////////////////////////////////////// +void +US_RestoreSaveWindow(memptr *save) +{ + word screen; + + screen = bufferofs + panadjust + ylookup[WindowY] + (WindowX * CHARWIDTH); + VW_MemToScreen(*save,screen,WindowW * CHARWIDTH,WindowH); + MM_FreePtr(save); +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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; +} + +// Cursor routines + +#if 0 +/////////////////////////////////////////////////////////////////////////// +// +// US_StartCursor() - Sets up the cursor for User Mgr use +// +/////////////////////////////////////////////////////////////////////////// +void +US_StartCursor(void) +{ + CursorInfo info; + + VW_SetCursor(CURSORARROWSPR); + CursorX = MaxX / 2; + CursorY = MaxY / 2; + VW_MoveCursor(CursorX,CursorY); + VW_ShowCursor(); + + IN_ReadCursor(&info); // Dispose of any accumulated movement +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_ShutCursor() - Cleans up after US_StartCursor() +// +/////////////////////////////////////////////////////////////////////////// +void +US_ShutCursor(void) +{ + VW_HideCursor(); +} + +/////////////////////////////////////////////////////////////////////////// +// +// US_UpdateCursor() - Gets the new cursor position & button states from +// the Input Mgr and tells the View Mgr where the cursor is +// +/////////////////////////////////////////////////////////////////////////// +boolean +US_UpdateCursor(void) +{ + CursorInfo info; + + IN_ReadCursor(&info); + if (info.x || info.y || CursorBad) + { + CursorX += info.x; + if (CursorX >= MaxX) + CursorX = MaxX - 1; + else if (CursorX < 0) + CursorX = 0; + + CursorY += info.y; + if (CursorY >= MaxY) + CursorY = MaxY - 1; + else if (CursorY < 0) + CursorY = 0; + + VW_MoveCursor(CursorX,CursorY); + CursorBad = false; + } + Button0 = info.button0; + Button1 = info.button1; + return(Button0 || Button1); +} +#endif + +// 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) +{ + char buf[MaxString]; + word w,h; + + strcpy(buf,s); + buf[cursor] = '\0'; + USL_MeasureString(buf,&w,&h); + + px = x + w - 1; + py = y; + USL_DrawString("\x80"); +} + +/////////////////////////////////////////////////////////////////////////// +// +// 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; + longword lasttime; + + VW_HideCursor(); + + 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; + USL_DrawString(olds); + 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_ShowCursor(); + VW_UpdateScreen(); + + IN_ClearKeysDown(); + return(result); +}