+/* Catacomb Armageddon Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+//\r
+// ID Engine\r
+// ID_US.c - User Manager\r
+// v1.0d1\r
+// By Jason Blochowiak\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
+// DEBUG - handle LPT3 for Sound Source\r
+\r
+#include "ID_HEADS.H"\r
+\r
+#define CTL_M_ADLIBUPPIC CTL_S_ADLIBUPPIC\r
+#define CTL_M_ADLIBDNPIC CTL_S_ADLIBDNPIC\r
+\r
+#pragma hdrstop\r
+\r
+#pragma warn -pia\r
+\r
+#define MaxX 320\r
+#define MaxY 200\r
+\r
+#define MaxHelpLines 500\r
+\r
+#define MaxHighName 57\r
+#define MaxScores 10\r
+typedef struct\r
+ {\r
+ char name[MaxHighName + 1];\r
+ long score;\r
+ word completed;\r
+ } HighScore;\r
+\r
+#define MaxGameName 32\r
+#define MaxSaveGames 7\r
+typedef struct\r
+ {\r
+ char signature[4];\r
+ boolean present;\r
+ char name[MaxGameName + 1];\r
+ } SaveGame;\r
+\r
+// Hack import for TED launch support\r
+extern boolean tedlevel;\r
+extern word tedlevelnum;\r
+extern void TEDDeath(void);\r
+static char *ParmStrings[] = {"TEDLEVEL","NOWAIT",""};\r
+\r
+\r
+// Global variables\r
+ boolean ingame,abortgame,loadedgame;\r
+ char *abortprogram;\r
+ GameDiff restartgame = gd_Continue;\r
+ word PrintX,PrintY;\r
+ word WindowX,WindowY,WindowW,WindowH;\r
+\r
+// Internal variables\r
+static boolean US_Started;\r
+static boolean GameIsDirty,\r
+ HighScoresDirty,\r
+ QuitToDos,\r
+ ResumeGame,\r
+ NoWait;\r
+\r
+static memptr LineOffsets;\r
+\r
+static boolean Button0,Button1,\r
+ CursorBad;\r
+static int CursorX,CursorY;\r
+\r
+static void (*USL_MeasureString)(char far *,word *,word *) = VW_MeasurePropString,\r
+ (*USL_DrawString)(char far *) = VWB_DrawPropString;\r
+\r
+static boolean (*USL_SaveGame)(int),(*USL_LoadGame)(int);\r
+static void (*USL_ResetGame)(void);\r
+static SaveGame Games[MaxSaveGames];\r
+static HighScore Scores[MaxScores] =\r
+ {\r
+ {"Sir Lancelot",500},\r
+ {"",0},\r
+ {"",0},\r
+ {"",0},\r
+ {"",0},\r
+ {"",0},\r
+ {"",0},\r
+ {"",0},\r
+ {"",0},\r
+ {"",0}\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
+static boolean oldleavedriveon;\r
+ int di;\r
+ char c,*s,*t;\r
+\r
+\r
+ di = _DI;\r
+\r
+ oldleavedriveon = LeaveDriveOn;\r
+ LeaveDriveOn = false;\r
+\r
+ if (ax < 0)\r
+ s = "Device Error";\r
+ else\r
+ {\r
+ if ((di & 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
+ LeaveDriveOn = oldleavedriveon;\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
+// USL_GiveSaveName() - Returns a pointer to a static buffer that contains\r
+// the filename to use for the specified save game\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static char *\r
+USL_GiveSaveName(word game)\r
+{\r
+static char filename[32];\r
+ char *s,*t;\r
+\r
+ for (s = "SAVEGM",t = filename;*s;)\r
+ *t++ = *s++;\r
+ *t++ = game + '0';\r
+ for (s = "."EXTENSION;*s;)\r
+ *t++ = *s++;\r
+ *t = '\0';\r
+\r
+ return(filename);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_SetLoadSaveHooks() - Sets the routines that the User Mgr calls after\r
+// reading or writing the save game headers\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_SetLoadSaveHooks(boolean (*load)(int),boolean (*save)(int),void (*reset)(void))\r
+{\r
+ USL_LoadGame = load;\r
+ USL_SaveGame = save;\r
+ USL_ResetGame = reset;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_ReadConfig() - Reads the configuration file, if present, and sets\r
+// things up accordingly. If it's not present, uses defaults. This file\r
+// includes the high scores.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_ReadConfig(void)\r
+{\r
+ boolean gotit;\r
+ int file;\r
+ SDMode sd;\r
+ SMMode sm;\r
+ ControlType ctl;\r
+\r
+ if ((file = open("CONFIG."EXTENSION,O_BINARY | O_RDONLY)) != -1)\r
+ {\r
+ read(file,Scores,sizeof(HighScore) * MaxScores);\r
+ read(file,&sd,sizeof(sd));\r
+ read(file,&sm,sizeof(sm));\r
+ read(file,&ctl,sizeof(ctl));\r
+ read(file,&(KbdDefs[0]),sizeof(KbdDefs[0]));\r
+ close(file);\r
+\r
+ HighScoresDirty = false;\r
+ gotit = true;\r
+ }\r
+ else\r
+ {\r
+ sd = sdm_Off;\r
+ sm = smm_Off;\r
+ ctl = ctrl_Keyboard;\r
+\r
+ gotit = false;\r
+ HighScoresDirty = true;\r
+ }\r
+\r
+ SD_Default(gotit,sd,sm);\r
+ IN_Default(gotit,ctl);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_WriteConfig() - Writes out the current configuration, including the\r
+// high scores.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_WriteConfig(void)\r
+{\r
+ int file;\r
+\r
+ file = open("CONFIG."EXTENSION,O_CREAT | O_BINARY | O_WRONLY,\r
+ S_IREAD | S_IWRITE | S_IFREG);\r
+ if (file != -1)\r
+ {\r
+ write(file,Scores,sizeof(HighScore) * MaxScores);\r
+ write(file,&SoundMode,sizeof(SoundMode));\r
+ write(file,&MusicMode,sizeof(MusicMode));\r
+ write(file,&(Controls[0]),sizeof(Controls[0]));\r
+ write(file,&(KbdDefs[0]),sizeof(KbdDefs[0]));\r
+ close(file);\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CheckSavedGames() - Checks to see which saved games are present\r
+// & valid\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_CheckSavedGames(void)\r
+{\r
+ boolean ok;\r
+ char *filename;\r
+ word i;\r
+ int file;\r
+ SaveGame *game;\r
+\r
+ USL_SaveGame = 0;\r
+ USL_LoadGame = 0;\r
+\r
+ for (i = 0,game = Games;i < MaxSaveGames;i++,game++)\r
+ {\r
+ filename = USL_GiveSaveName(i);\r
+ ok = false;\r
+ if ((file = open(filename,O_BINARY | O_RDONLY)) != -1)\r
+ {\r
+ if\r
+ (\r
+ (read(file,game,sizeof(*game)) == sizeof(*game))\r
+ && (!strcmp(game->signature,EXTENSION))\r
+ )\r
+ ok = true;\r
+\r
+ close(file);\r
+ }\r
+\r
+ if (ok)\r
+ game->present = true;\r
+ else\r
+ {\r
+ strcpy(game->signature,EXTENSION);\r
+ game->present = false;\r
+ strcpy(game->name,"Empty");\r
+ }\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_Startup() - Starts the User Mgr\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_Startup(void)\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
+ USL_ReadConfig(); // Read config file\r
+\r
+ US_Started = true;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_Setup() - Does the disk access part of the User Mgr's startup\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_Setup(void)\r
+{\r
+ USL_CheckSavedGames(); // Check which saved games are present\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
+ if (!abortprogram)\r
+ USL_WriteConfig();\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
+//\r
+// USL_ScreenDraw() - Draws a chunk of the text screen (called only by\r
+// US_TextScreen())\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_ScreenDraw(word x,word y,char *s,byte attr)\r
+{\r
+ byte far *screen;\r
+\r
+ screen = MK_FP(0xb800,(x * 2) + (y * 80 * 2));\r
+ while (*s)\r
+ {\r
+ *screen++ = *s++;\r
+ *screen++ = attr;\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_ClearTextScreen() - Makes sure the screen is in text mode, clears it,\r
+// and moves the cursor to the leftmost column of the bottom line\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_ClearTextScreen(void)\r
+{\r
+ // Set to 80x25 color text mode\r
+ _AL = 3; // Mode 3\r
+ _AH = 0x00;\r
+ geninterrupt(0x10);\r
+\r
+ // Use BIOS to move the cursor to the bottom of the screen\r
+ _AH = 0x0f;\r
+ geninterrupt(0x10); // Get current video mode into _BH\r
+ _DL = 0; // Lefthand side of the screen\r
+ _DH = 24; // Bottom row\r
+ _AH = 0x02;\r
+ geninterrupt(0x10);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_TextScreen() - Puts up the startup text screen\r
+// Note: These are the only User Manager functions that can be safely called\r
+// before the User Mgr has been started up\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_TextScreen(void)\r
+{\r
+ word i,n,\r
+ sx,sy;\r
+extern char far introscn;\r
+\r
+ USL_ClearTextScreen();\r
+\r
+ _fmemcpy(MK_FP(0xb800,0),7 + &introscn,80 * 25 * 2);\r
+\r
+ // Check for TED launching here\r
+ for (i = 1;i < _argc;i++)\r
+ {\r
+ n = US_CheckParm(_argv[i],ParmStrings);\r
+ if (n == 0)\r
+ {\r
+ tedlevelnum = atoi(_argv[i + 1]);\r
+ if (tedlevelnum >= 0)\r
+ {\r
+ tedlevel = true;\r
+ return;\r
+ }\r
+ else\r
+ break;\r
+ }\r
+ else if (n == 1)\r
+ {\r
+ NoWait = true;\r
+ return;\r
+ }\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_Show() - Changes the appearance of one of the fields on the text\r
+// screen. Possibly adds a checkmark in front of it and highlights it\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_Show(word x,word y,word w,boolean show,boolean hilight)\r
+{\r
+ byte far *screen;\r
+\r
+ screen = MK_FP(0xb800,((x - 1) * 2) + (y * 80 * 2));\r
+ *screen++ = show? 251 : ' '; // Checkmark char or space\r
+ *screen = 0x48;\r
+ if (show && hilight)\r
+ {\r
+ for (w++;w--;screen += 2)\r
+ *screen = 0x4f;\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_ShowMem() - Right justifies a longword in one of the memory fields on\r
+// the text screen\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_ShowMem(word x,word y,long mem)\r
+{\r
+ char buf[16];\r
+ word i;\r
+\r
+ for (i = strlen(ltoa(mem,buf,10));i < 5;i++)\r
+ USL_ScreenDraw(x++,y," ",0x48);\r
+ USL_ScreenDraw(x,y,buf,0x48);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_UpdateTextScreen() - Called after the ID libraries are started up.\r
+// Displays what hardware is present.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_UpdateTextScreen(void)\r
+{\r
+ boolean b;\r
+ byte far *screen;\r
+ word i;\r
+ longword totalmem;\r
+\r
+ // Show video card info\r
+ b = (grmode == CGAGR);\r
+ USL_Show(21,7,4,(videocard >= CGAcard) && (videocard <= VGAcard),b);\r
+ b = (grmode == EGAGR);\r
+ USL_Show(21,8,4,(videocard >= EGAcard) && (videocard <= VGAcard),b);\r
+ b = (grmode == VGAGR);\r
+ USL_Show(21,9,4,videocard == VGAcard,b);\r
+ if (compatability)\r
+ USL_ScreenDraw(5,10,"SVGA Compatibility Mode Enabled.",0x4f);\r
+\r
+ // Show input device info\r
+ USL_Show(60,7,8,true,true);\r
+ USL_Show(60,8,11,JoysPresent[0],true);\r
+ USL_Show(60,9,11,JoysPresent[1],true);\r
+ USL_Show(60,10,5,MousePresent,true);\r
+\r
+ // Show sound hardware info\r
+ USL_Show(21,14,11,true,SoundMode == sdm_PC);\r
+ b = (SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib);\r
+ USL_Show(21,15,5,AdLibPresent && !SoundBlasterPresent,\r
+ b && !SoundBlasterPresent);\r
+ USL_Show(21,16,13,SoundBlasterPresent,\r
+ SoundBlasterPresent && (b || (SoundMode == sdm_SoundBlaster)));\r
+ USL_Show(21,17,13,SoundSourcePresent,SoundMode == sdm_SoundSource);\r
+\r
+ // Show memory available/used\r
+ USL_ShowMem(63,15,mminfo.mainmem / 1024);\r
+ USL_Show(53,15,23,true,true);\r
+ USL_ShowMem(63,16,mminfo.EMSmem / 1024);\r
+ USL_Show(53,16,23,mminfo.EMSmem? true : false,true);\r
+ USL_ShowMem(63,17,mminfo.XMSmem / 1024);\r
+ USL_Show(53,17,23,mminfo.XMSmem? true : false,true);\r
+ totalmem = mminfo.mainmem + mminfo.EMSmem + mminfo.XMSmem;\r
+ USL_ShowMem(63,18,totalmem / 1024);\r
+ screen = MK_FP(0xb800,1 + (((63 - 1) * 2) + (18 * 80 * 2)));\r
+ for (i = 0;i < 13;i++,screen += 2)\r
+ *screen = 0x4f;\r
+\r
+ // Change Initializing... to Loading...\r
+ USL_ScreenDraw(27,22," Loading... ",0x9c);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_FinishTextScreen() - After the main program has finished its initial\r
+// loading, this routine waits for a keypress and then clears the screen\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_FinishTextScreen(void)\r
+{\r
+ // Change Loading... to Press a Key\r
+ USL_ScreenDraw(29,22," Ready - Press a Key ",0x9a);\r
+\r
+ if (!(tedlevel || NoWait))\r
+ {\r
+ IN_ClearKeysDown();\r
+ IN_Ack();\r
+ }\r
+ IN_ClearKeysDown();\r
+\r
+ USL_ClearTextScreen();\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 *s)\r
+{\r
+ char c,*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(longword 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
+static void\r
+USL_PrintInCenter(char *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 *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 *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 *s)\r
+{\r
+ char c,*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
+ 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_DrawTile8M(sx,sy,0),VWB_DrawTile8M(sx,sy + sh,6);\r
+ for (i = sx + 8;i <= sx + sw - 8;i += 8)\r
+ VWB_DrawTile8M(i,sy,1),VWB_DrawTile8M(i,sy + sh,7);\r
+ VWB_DrawTile8M(i,sy,2),VWB_DrawTile8M(i,sy + sh,8);\r
+\r
+ for (i = sy + 8;i <= sy + sh - 8;i += 8)\r
+ VWB_DrawTile8M(sx,i,3),VWB_DrawTile8M(sx + sw,i,5);\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_CenterSaveWindow() - Generates a window of a given width & height in\r
+// the middle of the screen, saving the background\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_CenterSaveWindow(word w,word h,memptr *save)\r
+{\r
+ word x,y,\r
+ screen;\r
+\r
+ x = ((MaxX / 8) - w) / 2;\r
+ y = ((MaxY / 8) - h) / 2;\r
+ MM_GetPtr(save,(w * h) * CHARWIDTH);\r
+ screen = bufferofs + panadjust + ylookup[y] + (x * CHARWIDTH);\r
+ VW_ScreenToMem(screen,*save,w * CHARWIDTH,h);\r
+ US_DrawWindow(((MaxX / 8) - w) / 2,((MaxY / 8) - h) / 2,w,h);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_RestoreSaveWindow() - Restores the background of the size of the\r
+// current window from the memory specified by save\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_RestoreSaveWindow(memptr *save)\r
+{\r
+ word screen;\r
+\r
+ screen = bufferofs + panadjust + ylookup[WindowY] + (WindowX * CHARWIDTH);\r
+ VW_MemToScreen(*save,screen,WindowW * CHARWIDTH,WindowH);\r
+ MM_FreePtr(save);\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
+// Cursor routines\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_StartCursor() - Sets up the cursor for User Mgr use\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_StartCursor(void)\r
+{\r
+ CursorInfo info;\r
+\r
+ VW_SetCursor(CURSORARROWSPR);\r
+ CursorX = MaxX / 2;\r
+ CursorY = MaxY / 2;\r
+ VW_MoveCursor(CursorX,CursorY);\r
+ VW_ShowCursor();\r
+\r
+ IN_ReadCursor(&info); // Dispose of any accumulated movement\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_ShutCursor() - Cleans up after US_StartCursor()\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_ShutCursor(void)\r
+{\r
+ VW_HideCursor();\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_UpdateCursor() - Gets the new cursor position & button states from\r
+// the Input Mgr and tells the View Mgr where the cursor is\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+boolean\r
+US_UpdateCursor(void)\r
+{\r
+ CursorInfo info;\r
+\r
+ IN_ReadCursor(&info);\r
+ if (info.x || info.y || CursorBad)\r
+ {\r
+ CursorX += info.x;\r
+ if (CursorX >= MaxX)\r
+ CursorX = MaxX - 1;\r
+ else if (CursorX < 0)\r
+ CursorX = 0;\r
+\r
+ CursorY += info.y;\r
+ if (CursorY >= MaxY)\r
+ CursorY = MaxY - 1;\r
+ else if (CursorY < 0)\r
+ CursorY = 0;\r
+\r
+ VW_MoveCursor(CursorX,CursorY);\r
+ CursorBad = false;\r
+ }\r
+ Button0 = info.button0;\r
+ Button1 = info.button1;\r
+ return(Button0 || Button1);\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
+ char buf[MaxString];\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
+ USL_DrawString("\x80");\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;\r
+ longword lasttime;\r
+\r
+ VW_HideCursor();\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
+ USL_DrawString(olds);\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_ShowCursor();\r
+ VW_UpdateScreen();\r
+\r
+ IN_ClearKeysDown();\r
+ return(result);\r
+}\r
+\r
+// Control panel routines\r
+\r
+static boolean FlushHelp;\r
+static WindowRec HelpWindow,BottomWindow;\r
+typedef enum\r
+ {\r
+ uic_Draw,uic_Hit\r
+ } UserCall;\r
+typedef enum\r
+ {\r
+ uii_Bad,uii_Button,uii_RadioButton,uii_CheckBox,uii_KeyCap\r
+ } UIType;\r
+#define ui_Normal 0\r
+#define ui_Selected 1\r
+#define ui_Disabled 2\r
+\r
+ // Prototype the custom routines\r
+static boolean USL_CtlButtonCustom(UserCall,word,word),\r
+ USL_CtlPButtonCustom(UserCall,word,word),\r
+ USL_CtlPSButtonCustom(UserCall,word,word),\r
+ USL_CtlPRButtonCustom(UserCall,word,word),\r
+ USL_CtlHButtonCustom(UserCall,word,word),\r
+ USL_CtlDButtonCustom(UserCall,word,word),\r
+ USL_CtlDEButtonCustom(UserCall,word,word),\r
+ USL_CtlDLButtonCustom(UserCall,word,word),\r
+ USL_CtlDSButtonCustom(UserCall,word,word),\r
+ USL_CtlSButtonCustom(UserCall,word,word),\r
+ USL_CtlCButtonCustom(UserCall,word,word),\r
+ USL_CtlCKbdButtonCustom(UserCall,word,word),\r
+ USL_CtlCJoyButtonCustom(UserCall,word,word);\r
+\r
+ // The structure of a user interaction item\r
+typedef struct {\r
+ Rect r; // The enclosing rectangle\r
+ UIType type; // The type of item\r
+ int picup,picdown; // What to draw when up/down\r
+ char *help; // Floating help string\r
+ ScanCode key; // Key equiv\r
+ word sel; // Interaction flags (ui_XXX)\r
+ boolean (*custom)(UserCall,word,word); // Custom routine\r
+ char *text; // Text for some items\r
+ } UserItem;\r
+typedef struct {\r
+ ScanCode key;\r
+ word i,n, // Hit CtlPanels2[i][n]\r
+ toi,ton; // Move to CtlPanels2[toi][ton]\r
+ } HotKey; // MARK\r
+\r
+static ScanCode *KeyMaps[] =\r
+ {\r
+ &KbdDefs[0].button0,&KbdDefs[0].button1,\r
+ &KbdDefs[0].upleft,&KbdDefs[0].up,&KbdDefs[0].upright,\r
+ &KbdDefs[0].left, &KbdDefs[0].right,\r
+ &KbdDefs[0].downleft,&KbdDefs[0].down,&KbdDefs[0].downright,\r
+ };\r
+\r
+// Some macros to make rectangle definition quite a bit less unpleasant\r
+#define CtlPanelX 8\r
+#define CtlPanelY 4\r
+#define CtlPanel2X (8*8)\r
+#define CtlPanel2Y (2*8)\r
+#define CtlPanel3X (8*8)\r
+#define CtlPanel3Y (7*8)\r
+\r
+#define CtlPanelR(n) { CtlPanelX,CtlPanelY+(32 * (n)),\\r
+ CtlPanelX+40,CtlPanelY+(32 * (n)) + 32}\r
+#define CtlPanel2R(x,y) { CtlPanel2X+(x)*8,CtlPanel2Y+(y)*8,\\r
+ CtlPanel2X+32+(x)*8,CtlPanel2Y+24+(y)*8}\r
+#define CtlPanel3R(x,y) { CtlPanel3X+(x)*8,CtlPanel3Y+(y)*8,\\r
+ CtlPanel3X+32+(x)*8,CtlPanel3Y+24+(y)*8}\r
+static UserItem CtlPanels[] =\r
+ {\r
+{CtlPanelR(0),uii_RadioButton,CTL_STARTUPPIC,CTL_STARTDNPIC,"Start or Resume a Game",sc_None,ui_Normal,USL_CtlButtonCustom},\r
+{CtlPanelR(1),uii_RadioButton,CTL_HELPUPPIC,CTL_HELPDNPIC,"Get Help With Commander Keen",sc_None,ui_Normal,USL_CtlButtonCustom},\r
+{CtlPanelR(2),uii_RadioButton,CTL_DISKUPPIC,CTL_DISKDNPIC,"Load / Save / Quit",sc_None,ui_Normal,USL_CtlButtonCustom},\r
+{CtlPanelR(3),uii_RadioButton,CTL_CONTROLSUPPIC,CTL_CONTROLSDNPIC,"Choose Controls",sc_C,ui_Normal,USL_CtlButtonCustom},\r
+{CtlPanelR(4),uii_RadioButton,CTL_SOUNDUPPIC,CTL_SOUNDDNPIC,"Select Sound Device",sc_F2,ui_Normal,USL_CtlButtonCustom},\r
+{CtlPanelR(5),uii_RadioButton,CTL_MUSICUPPIC,CTL_MUSICDNPIC,"Turn Music On / Off",sc_F7,ui_Normal,USL_CtlButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlPPanels[] =\r
+ {\r
+{CtlPanel2R(10,0),uii_RadioButton,CTL_P_NEWGAMEUPPIC,CTL_P_NEWGAMEDNPIC,"Choose Difficulty for the New Game",sc_F5,ui_Normal,USL_CtlPButtonCustom},\r
+{CtlPanel2R(15,0),uii_RadioButton,CTL_P_RESUMEUPPIC,CTL_P_RESUMEDNPIC,"Go Back to Current Game",sc_None,ui_Normal,USL_CtlPButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlPSPanels[] =\r
+ {\r
+{CtlPanel3R(13,5),uii_Button,CTL_P_MEDUPPIC,CTL_P_MEDDNPIC,"Start New Game in Normal Mode",sc_None,ui_Normal,USL_CtlPSButtonCustom},\r
+{CtlPanel3R(8,5),uii_Button,CTL_P_EASYUPPIC,CTL_P_EASYDNPIC,"Start New Game in Easy Mode",sc_None,ui_Normal,USL_CtlPSButtonCustom},\r
+{CtlPanel3R(18,5),uii_Button,CTL_P_HARDUPPIC,CTL_P_HARDDNPIC,"Start New Game in Hard Mode",sc_None,ui_Normal,USL_CtlPSButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlPRPanels[] =\r
+ {\r
+{CtlPanel3R(13,5),uii_Button,CTL_P_GORESUMEUPPIC,CTL_P_GORESUMEDNPIC,"Resume Current Game",sc_None,ui_Normal,USL_CtlPRButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlHPanels[] =\r
+ {\r
+{CtlPanel2R(8,0),uii_Button,CTL_H_LOSTUPPIC,CTL_H_LOSTDNPIC,"Help Me, I'm Lost!",sc_F1,ui_Normal,USL_CtlHButtonCustom},\r
+{CtlPanel2R(13,0),uii_Button,CTL_H_CTRLUPPIC,CTL_H_CTRLDNPIC,"Get Help with Controls",sc_None,ui_Normal,USL_CtlHButtonCustom},\r
+{CtlPanel2R(18,0),uii_Button,CTL_H_STORYUPPIC,CTL_H_STORYDNPIC,"Read Story & Game Tips",sc_None,ui_Normal,USL_CtlHButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlDPanels[] =\r
+ {\r
+{CtlPanel2R(9,0),uii_RadioButton,CTL_D_LSGAMEUPPIC,CTL_D_LSGAMEDNPIC,"Load or Save a Game",sc_F6,ui_Normal,USL_CtlDButtonCustom},\r
+{CtlPanel2R(15,0),uii_RadioButton,CTL_D_DOSUPPIC,CTL_D_DOSDNPIC,"Exit to DOS",sc_Q,ui_Normal,USL_CtlDButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlDLSPanels[] =\r
+ {\r
+#define CtlPanel3LSR(x,y) { CtlPanel3X+(x)*8,CtlPanel3Y+(y)*8,\\r
+ CtlPanel3X+32+(x)*8,CtlPanel3Y+16+(y)*8}\r
+{CtlPanel3LSR(1,0),uii_Button,CTL_D_LOADUPPIC,CTL_D_LOADDNPIC,"Load This Game",sc_None,ui_Normal,USL_CtlDLButtonCustom},\r
+{CtlPanel3LSR(6,0),uii_Button,CTL_D_SAVEUPPIC,CTL_D_SAVEDNPIC,"Save Current Game Here",sc_None,ui_Normal,USL_CtlDSButtonCustom},\r
+{CtlPanel3LSR(1,2),uii_Button,CTL_D_LOADUPPIC,CTL_D_LOADDNPIC,"Load This Game",sc_None,ui_Normal,USL_CtlDLButtonCustom},\r
+{CtlPanel3LSR(6,2),uii_Button,CTL_D_SAVEUPPIC,CTL_D_SAVEDNPIC,"Save Current Game Here",sc_None,ui_Normal,USL_CtlDSButtonCustom},\r
+{CtlPanel3LSR(1,4),uii_Button,CTL_D_LOADUPPIC,CTL_D_LOADDNPIC,"Load This Game",sc_None,ui_Normal,USL_CtlDLButtonCustom},\r
+{CtlPanel3LSR(6,4),uii_Button,CTL_D_SAVEUPPIC,CTL_D_SAVEDNPIC,"Save Current Game Here",sc_None,ui_Normal,USL_CtlDSButtonCustom},\r
+{CtlPanel3LSR(1,6),uii_Button,CTL_D_LOADUPPIC,CTL_D_LOADDNPIC,"Load This Game",sc_None,ui_Normal,USL_CtlDLButtonCustom},\r
+{CtlPanel3LSR(6,6),uii_Button,CTL_D_SAVEUPPIC,CTL_D_SAVEDNPIC,"Save Current Game Here",sc_None,ui_Normal,USL_CtlDSButtonCustom},\r
+{CtlPanel3LSR(1,8),uii_Button,CTL_D_LOADUPPIC,CTL_D_LOADDNPIC,"Load This Game",sc_None,ui_Normal,USL_CtlDLButtonCustom},\r
+{CtlPanel3LSR(6,8),uii_Button,CTL_D_SAVEUPPIC,CTL_D_SAVEDNPIC,"Save Current Game Here",sc_None,ui_Normal,USL_CtlDSButtonCustom},\r
+{CtlPanel3LSR(1,10),uii_Button,CTL_D_LOADUPPIC,CTL_D_LOADDNPIC,"Load This Game",sc_None,ui_Normal,USL_CtlDLButtonCustom},\r
+{CtlPanel3LSR(6,10),uii_Button,CTL_D_SAVEUPPIC,CTL_D_SAVEDNPIC,"Save Current Game Here",sc_None,ui_Normal,USL_CtlDSButtonCustom},\r
+{CtlPanel3LSR(1,12),uii_Button,CTL_D_LOADUPPIC,CTL_D_LOADDNPIC,"Load This Game",sc_None,ui_Normal,USL_CtlDLButtonCustom},\r
+{CtlPanel3LSR(6,12),uii_Button,CTL_D_SAVEUPPIC,CTL_D_SAVEDNPIC,"Save Current Game Here",sc_None,ui_Normal,USL_CtlDSButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlDEPanels[] =\r
+ {\r
+#define CtlPanel3ER(x,y) { CtlPanel3X+(x)*8,CtlPanel3Y+(y)*8,\\r
+ CtlPanel3X+40+(x)*8,CtlPanel3Y+24+(y)*8}\r
+{CtlPanel3ER(12,5),uii_Button,CTL_D_EXITUPPIC,CTL_D_EXITDNPIC,"Really Exit to DOS",sc_None,ui_Normal,USL_CtlDEButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlCPanels[] =\r
+ {\r
+{CtlPanel2R(8,0),uii_RadioButton,CTL_C_KBDUPPIC,CTL_C_KBDDNPIC,"Use / Configure Keyboard",sc_F3,ui_Normal,USL_CtlCButtonCustom},\r
+{CtlPanel2R(13,0),uii_RadioButton,CTL_C_JOY1UPPIC,CTL_C_JOY1DNPIC,"Use / Configure Joystick 1",sc_None,ui_Normal,USL_CtlCButtonCustom},\r
+{CtlPanel2R(18,0),uii_RadioButton,CTL_C_JOY2UPPIC,CTL_C_JOY2DNPIC,"Use / Configure Joystick 2",sc_None,ui_Normal,USL_CtlCButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+#define CtlPanelKC3R(x,y) { CtlPanel3X+(x)*8,CtlPanel3Y+(y)*8,\\r
+ CtlPanel3X+56+(x)*8,CtlPanel3Y+32+(y)*8}\r
+ CtlCKbdPanels[] =\r
+ {\r
+{CtlPanelKC3R(1,2),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key for Jumping",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(1,6),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key for Throwing",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(8,0),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Up & Left",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(15,0),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Up",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(22,0),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Up & Right",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(8,4),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Left",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(22,4),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Right",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(8,8),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Down & Left",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(15,8),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Down",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{CtlPanelKC3R(22,8),uii_KeyCap,CTL_KEYCAPPIC,CTL_KEYCAPCURPIC,"Define Key to move Down & Right",sc_None,ui_Normal,USL_CtlCKbdButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlCJoyPanels[] =\r
+ {\r
+{CtlPanel3R(13,5),uii_Button,CTL_C_CALIBRATEUPPIC,CTL_C_CALIBRATEDNPIC,"Configure Joystick",sc_None,ui_Normal,USL_CtlCJoyButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlSPanels[] =\r
+ {\r
+{CtlPanel2R(3,0),uii_RadioButton,CTL_S_NOSNDUPPIC,CTL_S_NOSNDDNPIC,"Turn Sound Off",sc_None,ui_Normal,USL_CtlSButtonCustom},\r
+{CtlPanel2R(8,0),uii_RadioButton,CTL_S_PCSNDUPPIC,CTL_S_PCSNDDNPIC,"Use PC Speaker",sc_None,ui_Normal,USL_CtlSButtonCustom},\r
+{CtlPanel2R(13,0),uii_RadioButton,CTL_S_ADLIBUPPIC,CTL_S_ADLIBDNPIC,"Use AdLib Sound Effects",sc_None,ui_Normal,USL_CtlSButtonCustom},\r
+{CtlPanel2R(18,0),uii_RadioButton,CTL_S_SNDBLUPPIC,CTL_S_SNDBLDNPIC,"Use SoundBlaster Sound Effects",sc_None,ui_Normal,USL_CtlSButtonCustom},\r
+{CtlPanel2R(23,0),uii_RadioButton,CTL_S_SNDSRCUPPIC,CTL_S_SNDSRCDNPIC,"Use Sound Source Sound Effects",sc_None,ui_Normal,USL_CtlSButtonCustom},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlSSSPanels[] =\r
+ {\r
+{CtlPanel3R(7,2),uii_CheckBox,CTL_CHECKUPPIC,CTL_CHECKDNPIC,"Turn Tandy Mode On / Off",sc_None,ui_Normal,0,"Tandy Mode"},\r
+{CtlPanel3R(7,6),uii_CheckBox,CTL_CHECKUPPIC,CTL_CHECKDNPIC,"Switch between LPT1 & LPT2",sc_None,ui_Normal,0,"Use LPT2"},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ CtlMPanels[] =\r
+ {\r
+{CtlPanel2R(9,0),uii_RadioButton,CTL_M_NOMUSUPPIC,CTL_M_NOMUSDNPIC,"Background Music Off"},\r
+{CtlPanel2R(15,0),uii_RadioButton,CTL_M_ADLIBUPPIC,CTL_M_ADLIBDNPIC,"Use AdLib/SoundBlaster Music"},\r
+{-1,-1,-1,-1,uii_Bad}\r
+ },\r
+ *CtlPanels2[] =\r
+ {\r
+ CtlPPanels, // Start\r
+ CtlHPanels, // Help\r
+ CtlDPanels, // Disk\r
+ CtlCPanels, // Controls\r
+ CtlSPanels, // Sound\r
+ CtlMPanels // Music\r
+ },\r
+ *TheItems[4] = {CtlPanels};\r
+static int CtlPanelButton;\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_TurnOff() - Goes through a list of UserItems and sets them all to\r
+// the normal state\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_TurnOff(UserItem *ip)\r
+{\r
+ while (ip->type != uii_Bad)\r
+ {\r
+ ip->sel = ui_Normal;\r
+ ip++;\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_FindDown() - Finds which UserItem, if any, is selected in the given\r
+// list\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static int\r
+USL_FindDown(UserItem *ip)\r
+{\r
+ int i;\r
+\r
+ for (i = 0;ip->type != uii_Bad;i++,ip++)\r
+ if (ip->sel & ui_Selected)\r
+ return(i);\r
+ return(-1);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_ShowHelp() - Shows the specified string in the help window\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_ShowHelp(char *s)\r
+{\r
+ WindowRec wr;\r
+\r
+ if (!s)\r
+ return;\r
+\r
+ US_SaveWindow(&wr);\r
+ US_RestoreWindow(&HelpWindow);\r
+\r
+ US_ClearWindow();\r
+ US_PrintCentered(s);\r
+\r
+ US_RestoreWindow(&wr);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_HandleError() - Handles telling the user that there's been an error\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_HandleError(int num)\r
+{\r
+ char buf[64];\r
+\r
+ strcpy(buf,"Error: ");\r
+ if (num < 0)\r
+ strcat(buf,"Unknown");\r
+ else if (num == ENOMEM)\r
+ strcat(buf,"Disk is Full");\r
+ else if (num == EINVFMT)\r
+ strcat(buf,"File is Incomplete");\r
+ else\r
+ strcat(buf,sys_errlist[num]);\r
+\r
+ VW_HideCursor();\r
+\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp(buf);\r
+ fontcolor = F_BLACK;\r
+ VW_UpdateScreen();\r
+\r
+ IN_ClearKeysDown();\r
+ IN_Ack();\r
+\r
+ VW_ShowCursor();\r
+ VW_UpdateScreen();\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_DrawItem() - Draws a UserItem. If there's a custom routine, this will\r
+// call it with a uic_Draw command. If the custom routine returns true,\r
+// then the routine handled all of the drawing. If it returns false,\r
+// then this routine does the default drawing.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_DrawItem(word hiti,word hitn)\r
+{\r
+ boolean handled,centered;\r
+ char *text;\r
+ word w,h;\r
+ int picup,picdown;\r
+ Rect r;\r
+ UserItem *ip;\r
+\r
+ ip = &TheItems[hiti][hitn];\r
+ if (ip->custom)\r
+ handled = ip->custom(uic_Draw,hiti,hitn);\r
+ else\r
+ handled = false;\r
+\r
+ if (!handled)\r
+ {\r
+ picup = ip->picup;\r
+ picdown = ip->picdown;\r
+ switch (ip->type)\r
+ {\r
+ case uii_CheckBox:\r
+ px = ip->r.lr.x + 8;\r
+ py = ip->r.ul.y + 8;\r
+ text = ip->text;\r
+ centered = false;\r
+ break;\r
+ case uii_KeyCap:\r
+ if (!(ip->sel & ui_Selected))\r
+ {\r
+ text = ip->text;\r
+ if (text)\r
+ {\r
+ r = ip->r;\r
+ centered = true;\r
+ }\r
+ }\r
+ else\r
+ text = nil;\r
+ break;\r
+ default:\r
+ text = nil;\r
+ break;\r
+ }\r
+\r
+ VWB_DrawPic(ip->r.ul.x,ip->r.ul.y,\r
+ (ip->sel & ui_Selected)? picdown : picup);\r
+ if (text)\r
+ {\r
+ if (centered)\r
+ USL_PrintInCenter(text,r);\r
+ else\r
+ {\r
+ USL_MeasureString(text,&w,&h);\r
+ VWB_Bar(px,py,w + 7,h,WHITE);\r
+ USL_DrawString(text);\r
+ }\r
+ }\r
+ if (ip->sel & ui_Disabled)\r
+ {\r
+ if ((picup == CTL_D_LOADUPPIC) || (picup == CTL_D_SAVEUPPIC))\r
+ VWB_DrawMPic(ip->r.ul.x,ip->r.ul.y,CTL_LSMASKPICM);\r
+ else\r
+ VWB_DrawMPic(ip->r.ul.x,ip->r.ul.y,CTL_LITTLEMASKPICM);\r
+ }\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_DoHit() - Handles a hit on a UserItem. If there's a custom routine,\r
+// it will be called. If it returns true, then don't do anything\r
+// more. If it returns false, then use the standard behaviour\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_DoHit(word hiti,word hitn)\r
+{\r
+ boolean handled;\r
+ word i;\r
+ UserItem *ip;\r
+\r
+ ip = &TheItems[hiti][hitn];\r
+ if (ip->custom)\r
+ handled = ip->custom(uic_Hit,hiti,hitn);\r
+ else\r
+ handled = false;\r
+\r
+ if (!handled)\r
+ {\r
+ if (TheItems[hiti][hitn].sel & ui_Disabled)\r
+ {\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp("This Item is Disabled");\r
+ fontcolor = F_BLACK;\r
+ return;\r
+ }\r
+\r
+ FlushHelp = true;\r
+\r
+ switch (ip->type)\r
+ {\r
+ case uii_Button:\r
+ // Must have a custom routine to handle hits - this just redraws\r
+ ip->sel ^= ui_Selected;\r
+ USL_DrawItem(hiti,hitn);\r
+ case uii_CheckBox:\r
+ ip->sel ^= ui_Selected;\r
+ USL_DrawItem(hiti,hitn);\r
+ break;\r
+ case uii_RadioButton:\r
+ for (i = 0,ip = TheItems[hiti];ip->type != uii_Bad;i++,ip++)\r
+ {\r
+ if\r
+ (\r
+ (i != hitn)\r
+ && (ip->type == uii_RadioButton)\r
+ && (ip->sel & ui_Selected)\r
+ )\r
+ {\r
+ ip->sel &= ~ui_Selected;\r
+ USL_DrawItem(hiti,i);\r
+ }\r
+ }\r
+ TheItems[hiti][hitn].sel |= ui_Selected;\r
+ USL_DrawItem(hiti,hitn);\r
+ break;\r
+ case uii_KeyCap:\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_IsInRect() - Checks to see if the coordinates given are within any\r
+// of the Rects in the UserItem list. If so, returns true & sets the\r
+// index & number for lookup. If not, returns false.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_IsInRect(word x,word y,word *index,word *number)\r
+{\r
+ UserItem *item,**items;\r
+\r
+ items = TheItems;\r
+ *index = 0;\r
+ while (*items)\r
+ {\r
+ item = *items;\r
+ *number = 0;\r
+ while (item->type != uii_Bad)\r
+ {\r
+ if\r
+ (\r
+ (x >= item->r.ul.x)\r
+ && (x < item->r.lr.x)\r
+ && (y >= item->r.ul.y)\r
+ && (y < item->r.lr.y)\r
+ )\r
+ return(true);\r
+ (*number)++;\r
+ item++;\r
+ }\r
+\r
+ (*index)++;\r
+ items++;\r
+ }\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_TrackItem() - Tracks the given item. If the cursor is inside of the\r
+// item, it's redrawn as down. If the cursor is outside, the item is\r
+// drawn in its original state. Returns true if the button was released\r
+// while the cursor was inside the item, or false if it wasn't.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_TrackItem(word hiti,word hitn)\r
+{\r
+ boolean inside,last;\r
+ word ini,inn,\r
+ on,\r
+ sel,othersel;\r
+ UserItem *ip,*op;\r
+\r
+ ip = &TheItems[hiti][hitn];\r
+ sel = ip->sel;\r
+ if (ip->type == uii_RadioButton)\r
+ {\r
+ inside = false;\r
+ for (op = TheItems[hiti],on = 0;op->type != uii_Bad;op++,on++)\r
+ {\r
+ if (op->sel & ui_Selected)\r
+ {\r
+ inside = true;\r
+ break;\r
+ }\r
+ }\r
+ if (!inside)\r
+ op = ip;\r
+ othersel = op->sel;\r
+ }\r
+ else\r
+ op = nil;\r
+\r
+ if (ip->sel & ui_Disabled)\r
+ {\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp("This item is disabled");\r
+ fontcolor = F_BLACK;\r
+\r
+ while (US_UpdateCursor())\r
+ VW_UpdateScreen();\r
+\r
+ FlushHelp = true;\r
+ return(false);\r
+ }\r
+\r
+ last = false;\r
+ do\r
+ {\r
+ USL_IsInRect(CursorX,CursorY,&ini,&inn);\r
+ inside = (ini == hiti) && (inn == hitn);\r
+ if (inside != last)\r
+ {\r
+ if (inside)\r
+ {\r
+ if (op)\r
+ {\r
+ op->sel &= ~ui_Selected;\r
+ ip->sel |= ui_Selected;\r
+ }\r
+ else\r
+ ip->sel = sel ^ ui_Selected;\r
+ }\r
+ else\r
+ {\r
+ if (op && (op != ip))\r
+ {\r
+ op->sel |= ui_Selected;\r
+ ip->sel &= ~ui_Selected;\r
+ }\r
+ else\r
+ ip->sel = sel;\r
+ }\r
+\r
+ USL_DrawItem(hiti,hitn);\r
+ if (op && (op != ip))\r
+ USL_DrawItem(hiti,on);\r
+\r
+ last = inside;\r
+ }\r
+ VW_UpdateScreen();\r
+ } while (US_UpdateCursor());\r
+\r
+ if (op)\r
+ op->sel = othersel;\r
+ ip->sel = sel;\r
+ if (!inside)\r
+ {\r
+ if (op && (op != ip))\r
+ USL_DrawItem(hiti,on);\r
+ USL_DrawItem(hiti,hitn);\r
+ VW_UpdateScreen();\r
+ }\r
+\r
+ return(inside);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_GlideCursor() - Smoothly moves the cursor to the given location\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_GlideCursor(long newx,long newy)\r
+{\r
+ word steps;\r
+ long x,y,\r
+ dx,dy;\r
+\r
+ if (grmode == CGAGR)\r
+ steps = 1;\r
+ else\r
+ steps = 8;\r
+\r
+ x = (long)CursorX << 16;\r
+ dx = ((newx << 16) - x) / steps;\r
+ y = (long)CursorY << 16;\r
+ dy = ((newy << 16) - y) / steps;\r
+\r
+ while ((CursorX != newx) || (CursorY != newy))\r
+ {\r
+ x += dx;\r
+ y += dy;\r
+\r
+ CursorX = x >> 16;\r
+ CursorY = y >> 16;\r
+ VW_MoveCursor(CursorX,CursorY);\r
+ VW_UpdateScreen();\r
+ }\r
+ CursorBad = true;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_FindRect() - Code so ugly you'll puke! Given a Rect and direction,\r
+// this routine will try to find a UserItem to move the cursor to\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_FindRect(Rect r,Motion xd,Motion yd)\r
+{\r
+ word i,i1,i2,i3;\r
+ Motion m1,m2;\r
+ Point diffs[9],diff,*dp;\r
+ Rect *rp,*good,*goods[9];\r
+ UserItem *ip,**items;\r
+\r
+ for (m1 = motion_Up,dp = diffs;m1 <= motion_Down;m1++)\r
+ {\r
+ for (m2 = motion_Left;m2 <= motion_Right;m2++,dp++)\r
+ {\r
+ dp->x = m2 * 1024;\r
+ dp->y = m1 * 1024;\r
+ }\r
+ }\r
+ for (i = 0;i < 9;i++)\r
+ goods[i] = nil;\r
+\r
+ // Find out which octants all of the rects (except r) are in\r
+ for (items = TheItems;*items;items++)\r
+ {\r
+ for (ip = *items;ip->type != uii_Bad;ip++)\r
+ {\r
+ rp = &ip->r;\r
+ diff.x = rp->ul.x - r.ul.x;\r
+ diff.y = rp->ul.y - r.ul.y;\r
+ if (!(diff.x || diff.y))\r
+ continue;\r
+\r
+ if // 1,4,7\r
+ (\r
+ ((rp->ul.x >= r.ul.x) && (rp->ul.x < r.lr.x))\r
+ || ((rp->lr.x > r.ul.x) && (rp->lr.x <= r.lr.x))\r
+ )\r
+ {\r
+ if (rp->lr.y <= r.ul.y)\r
+ {\r
+ if (!(goods[1] && (diff.y < diffs[1].y)))\r
+ {\r
+ goods[1] = rp;\r
+ diffs[1] = diff;\r
+ }\r
+ }\r
+ else if (rp->ul.y >= r.lr.y)\r
+ {\r
+ if (!(goods[7] && (diff.y > diffs[7].y)))\r
+ {\r
+ goods[7] = rp;\r
+ diffs[7] = diff;\r
+ }\r
+ }\r
+ }\r
+\r
+ if // 3,4,5\r
+ (\r
+ ((rp->ul.y >= r.ul.y) && (rp->ul.y < r.lr.y))\r
+ || ((rp->lr.y > r.ul.y) && (rp->lr.y <= r.lr.y))\r
+ )\r
+ {\r
+ if (rp->lr.x <= r.ul.x)\r
+ {\r
+ if (!(goods[3] && (diff.x < diffs[3].x)))\r
+ {\r
+ goods[3] = rp;\r
+ diffs[3] = diff;\r
+ }\r
+ }\r
+ else if (rp->ul.x >= r.lr.x)\r
+ {\r
+ if (!(goods[5] && (diff.x > diffs[5].x)))\r
+ {\r
+ goods[5] = rp;\r
+ diffs[5] = diff;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (rp->ul.x < r.ul.x) // 0,6\r
+ {\r
+ if (rp->lr.y <= r.ul.y)\r
+ {\r
+ if\r
+ (\r
+ (!goods[0])\r
+ || (diff.y > diffs[0].y)\r
+ || (diff.x > diffs[6].x)\r
+ )\r
+ {\r
+ goods[0] = rp;\r
+ diffs[0] = diff;\r
+ }\r
+ }\r
+ else if (rp->ul.y >= r.lr.y)\r
+ {\r
+ if\r
+ (\r
+ (!goods[6])\r
+ || (diff.y < diffs[6].y)\r
+ || (diff.x > diffs[6].x)\r
+ )\r
+ {\r
+ goods[6] = rp;\r
+ diffs[6] = diff;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (rp->lr.x > r.lr.x) // 2,8\r
+ {\r
+ if (rp->lr.y <= r.ul.y)\r
+ {\r
+ if\r
+ (\r
+ (!goods[2])\r
+ || (diff.y > diffs[2].y)\r
+ || (diff.x < diffs[2].x)\r
+ )\r
+ {\r
+ goods[2] = rp;\r
+ diffs[2] = diff;\r
+ }\r
+ }\r
+ else if (rp->ul.y >= r.lr.y)\r
+ {\r
+ if\r
+ (\r
+ (!goods[8])\r
+ || (diff.y < diffs[8].y)\r
+ || (diff.x < diffs[8].x)\r
+ )\r
+ {\r
+ goods[8] = rp;\r
+ diffs[8] = diff;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ switch (yd)\r
+ {\r
+ case motion_Up:\r
+ i1 = 1,i2 = 0,i3 = 2;\r
+ break;\r
+ case motion_None:\r
+ switch (xd)\r
+ {\r
+ case motion_Left:\r
+ i1 = 3,i2 = 0,i3 = 6;\r
+ break;\r
+ case motion_Right:\r
+ i1 = 5,i2 = 8,i3 = 2;\r
+ break;\r
+ }\r
+ break;\r
+ case motion_Down:\r
+ i1 = 7,i2 = 8,i3 = 6;\r
+ break;\r
+ }\r
+\r
+ (\r
+ (good = goods[i1])\r
+ || (good = goods[i2])\r
+ || (good = goods[i3])\r
+ || (good = &r)\r
+ );\r
+#if 0\r
+ CursorX = good->lr.x - 8;\r
+ CursorY = good->lr.y - 8;\r
+ CursorBad = true;\r
+ US_UpdateCursor();\r
+#endif\r
+ USL_GlideCursor(good->lr.x - 8,good->lr.y - 8);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlButtonCustom() - The custom routine for all of the Control Panel\r
+// (leftmost) buttons. Clears all of the other item lists, clears the\r
+// large area, and draws the line dividing the top and bottom areas.\r
+// Then it sets up and draws the appropriate top row of icons.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlButtonCustom(UserCall call,word i,word n)\r
+{\r
+ word j;\r
+ UserItem *ip;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ if (n == CtlPanelButton)\r
+ return(true);\r
+\r
+ US_ClearWindow();\r
+ for (j = 8;j < 38;j++)\r
+ {\r
+ VWB_DrawTile8M(j * 8,6 * 8,10);\r
+ VWB_DrawTile8M(j * 8,21 * 8,10);\r
+ }\r
+ VWB_DrawTile8M(7 * 8,6 * 8,9);\r
+ VWB_DrawTile8M(38 * 8,6 * 8,11);\r
+ VWB_DrawTile8M(7 * 8,21 * 8,9);\r
+ VWB_DrawTile8M(38 * 8,21 * 8,11);\r
+\r
+ for (j = 1;j < 4;j++)\r
+ TheItems[j] = nil;\r
+\r
+ // Set to new button\r
+ CtlPanelButton = n;\r
+\r
+ // Draw new items\r
+ TheItems[1] = ip = CtlPanels2[CtlPanelButton];\r
+ j = 0;\r
+ while (ip && (ip->type != uii_Bad))\r
+ {\r
+ USL_DrawItem(i + 1,j);\r
+ if (ip->sel & ui_Selected)\r
+ USL_DoHit(i + 1,j);\r
+ j++;\r
+ ip++;\r
+ }\r
+\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlCKbdButtonCustom() - The custom routine for the keyboard keycaps.\r
+// This routine gets a scancode and puts it in the appropriate\r
+// KbdDefs[0] member.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlCKbdButtonCustom(UserCall call,word i,word n)\r
+{\r
+ boolean state;\r
+ word j;\r
+ ScanCode scan;\r
+ longword time;\r
+ UserItem *ip;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ ip = &TheItems[i][n];\r
+\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp(ip->help);\r
+ fontcolor = F_BLACK;\r
+ VW_HideCursor();\r
+ VWB_DrawPic(ip->r.ul.x,ip->r.ul.y,ip->picdown);\r
+ VW_UpdateScreen();\r
+\r
+ LastScan = sc_None;\r
+ time = TimeCount;\r
+ state = true;\r
+ do\r
+ {\r
+ if (TimeCount - time > 35) // Half-second delays\r
+ {\r
+ state ^= true;\r
+ VWB_DrawPic(ip->r.ul.x,ip->r.ul.y,state? ip->picdown : ip->picup);\r
+ VW_UpdateScreen();\r
+ time = TimeCount;\r
+ }\r
+ if (US_UpdateCursor())\r
+ {\r
+ while (US_UpdateCursor())\r
+ ;\r
+ scan = sc_Escape;\r
+ break;\r
+ }\r
+\r
+ asm pushf\r
+ asm cli\r
+ if (LastScan == sc_LShift)\r
+ LastScan = sc_None;\r
+ asm popf\r
+ } while (!(scan = LastScan));\r
+ IN_ClearKey(scan);\r
+ if (scan != sc_Escape)\r
+ {\r
+ for (j = 0,state = false;j < 10;j++)\r
+ {\r
+ if (j == n)\r
+ continue;\r
+ if (*(KeyMaps[j]) == scan)\r
+ {\r
+ state = true;\r
+ break;\r
+ }\r
+ }\r
+ if (state)\r
+ {\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp("That Key is Already Used!");\r
+ fontcolor = F_BLACK;\r
+ }\r
+ else\r
+ {\r
+ ip->text = IN_GetScanName(scan);\r
+ *(KeyMaps[n]) = scan;\r
+ FlushHelp = true;\r
+ }\r
+ }\r
+\r
+ USL_DrawItem(i,n);\r
+ VW_ShowCursor();\r
+ VW_UpdateScreen();\r
+\r
+ return(true);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlCJoyButtonCustom() - The custom button routine for joystick\r
+// calibration\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlCJoyButtonCustom(UserCall call,word i,word n)\r
+{\r
+ word joy,\r
+ minx,maxx,\r
+ miny,maxy;\r
+\r
+ i++,n++; // Shut the compiler up\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ IN_ClearKeysDown();\r
+ joy = USL_FindDown(CtlCPanels) - 1;\r
+\r
+ VW_HideCursor();\r
+ FlushHelp = true;\r
+ fontcolor = F_SECONDCOLOR;\r
+\r
+ USL_ShowHelp("Move Joystick to the Upper-Left");\r
+ VW_UpdateScreen();\r
+ while ((LastScan != sc_Escape) && !IN_GetJoyButtonsDB(joy))\r
+ ;\r
+ if (LastScan != sc_Escape)\r
+ {\r
+ IN_GetJoyAbs(joy,&minx,&miny);\r
+ while (IN_GetJoyButtonsDB(joy))\r
+ ;\r
+\r
+ USL_ShowHelp("Move Joystick to the Lower-Right");\r
+ VW_UpdateScreen();\r
+ while ((LastScan != sc_Escape) && !IN_GetJoyButtonsDB(joy))\r
+ ;\r
+ if (LastScan != sc_Escape)\r
+ {\r
+ IN_GetJoyAbs(0,&maxx,&maxy);\r
+ IN_SetupJoy(joy,minx,maxx,miny,maxy);\r
+ }\r
+ }\r
+\r
+ if (LastScan != sc_Escape)\r
+ while (IN_GetJoyButtonsDB(joy))\r
+ ;\r
+\r
+ if (LastScan)\r
+ IN_ClearKeysDown();\r
+\r
+ fontcolor = F_BLACK;\r
+ VW_ShowCursor();\r
+\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_ClearBottom() - Clears the bottom part of the window\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_ClearBottom(void)\r
+{\r
+ WindowRec wr;\r
+\r
+ US_SaveWindow(&wr);\r
+ US_RestoreWindow(&BottomWindow);\r
+\r
+ US_ClearWindow();\r
+\r
+ US_RestoreWindow(&wr);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_FormatHelp() - Formats helptext. Runs through and calculates the\r
+// number of lines, and the offset for the start of each line. Stops\r
+// after len bytes or when it hits a tilde ('~'). Munges the text.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static word\r
+USL_FormatHelp(char far *text,long len)\r
+{\r
+ word line,\r
+ w,h,\r
+ far *off;\r
+ char c,\r
+ far *s,far *l,far *le;\r
+\r
+ WindowX += 4;\r
+ WindowW -= 4;\r
+\r
+ MM_GetPtr(&LineOffsets,MaxHelpLines * sizeof(word));\r
+ off = (word far *)LineOffsets;\r
+ for (line = 0,le = l = s = text;(s - text < len) && (*s != '~');s++)\r
+ {\r
+ if ((c = *s) == '\n')\r
+ {\r
+ *s = '\0';\r
+ *off++ = l - text; // Save offset of start of line\r
+ line++; // Bump line number\r
+ le = l = s + 1; // Set start of line ptr\r
+ }\r
+\r
+ if (c == '\r')\r
+ c = *s = ' ';\r
+ if // Strip orphaned spaces\r
+ (\r
+ (c == ' ')\r
+ && (s == l)\r
+ && (*(s - 1) == '\0')\r
+ && (*(s + 1) != ' ')\r
+ && (s > text)\r
+ )\r
+ le = l = s + 1;\r
+ else if (c == ' ')\r
+ {\r
+ *s = '\0';\r
+ USL_MeasureString(l,&w,&h);\r
+ if (w >= WindowW) // If string width exceeds window,\r
+ {\r
+ *s = c; // Replace null char with proper char\r
+ *le = '\0'; // Go back to last line end\r
+ *off++ = l - text; // Save offset of start of line\r
+ line++; // Bump line number\r
+ l = s = le + 1; // Start next time through after last line end\r
+ }\r
+ else\r
+ {\r
+ *s = c; // Width still ok - put char back\r
+ le = s; // And save ptr to last ok end of word\r
+ }\r
+ }\r
+ }\r
+\r
+ WindowX -= 4;\r
+ WindowW += 4;\r
+\r
+ return(line);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_DrawHelp() - Draws helptext in the current window\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_DrawHelp(char far *text,word start,word end,word line,word h,word far *lp)\r
+{\r
+ px = WindowX + 4;\r
+ py = WindowY + (line * h);\r
+ for (lp += start;start < end;start++,px = WindowX + 4,py += h)\r
+ USL_DrawString(text + *lp++);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_DoHelp() - Formats and displays the specified help\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_DoHelp(memptr text,long len)\r
+{\r
+ boolean done,\r
+ moved;\r
+ int scroll;\r
+ word i,\r
+ pixdiv,\r
+ w,h,\r
+ lines,cur,page,\r
+ top,num,loc,\r
+ far *lp,\r
+ base,srcbase,destbase;\r
+ ScanCode waitkey;\r
+ longword lasttime;\r
+ WindowRec wr;\r
+ CursorInfo info;\r
+\r
+ USL_ShowHelp("Arrow Keys Move / Escape Exits");\r
+ fontcolor = F_BLACK;\r
+\r
+ US_SaveWindow(&wr);\r
+ US_RestoreWindow(&BottomWindow);\r
+ US_ClearWindow();\r
+\r
+ VW_HideCursor();\r
+ VW_UpdateScreen();\r
+\r
+ lines = USL_FormatHelp((char far *)text,len);\r
+ USL_MeasureString("",&w,&h);\r
+ page = WindowH / h;\r
+ cur = 0;\r
+ lp = LineOffsets;\r
+\r
+ IN_ClearKeysDown();\r
+ moved = true;\r
+ lasttime = 0;\r
+ scroll = 0;\r
+ done = false;\r
+ waitkey = sc_None;\r
+ while (!done)\r
+ {\r
+ if (moved)\r
+ {\r
+ while (TimeCount - lasttime < 5)\r
+ ;\r
+ lasttime = TimeCount;\r
+\r
+ if (scroll == -1)\r
+ {\r
+ top = cur;\r
+ num = 1;\r
+ loc = 0;\r
+ }\r
+ else if (scroll == +1)\r
+ {\r
+ num = 1;\r
+ loc = page - 1;\r
+ top = cur + loc;\r
+ }\r
+ else\r
+ {\r
+ top = cur;\r
+ num = (page < lines)? page : lines;\r
+ loc = 0;\r
+ }\r
+ if (scroll)\r
+ {\r
+ if (grmode == CGAGR)\r
+ {\r
+ pixdiv = 4;\r
+ base = bufferofs + panadjust + (WindowX / pixdiv);\r
+ }\r
+ else if (grmode == EGAGR)\r
+ {\r
+ VWB_Bar(WindowX,WindowY + (loc * h),WindowW,num * h,WHITE);\r
+ USL_DrawHelp((char far *)text,top,top + num,loc,h,lp);\r
+\r
+ pixdiv = 8;\r
+ base = displayofs + panadjust + (WindowX / pixdiv);\r
+ }\r
+ else if (grmode == VGAGR)\r
+ pixdiv = 1;\r
+\r
+ if (scroll == 1)\r
+ {\r
+ srcbase = base + ylookup[WindowY + h];\r
+ destbase = base + ylookup[WindowY];\r
+ if (grmode == EGAGR)\r
+ {\r
+ EGAWRITEMODE(1);\r
+ VW_WaitVBL(1);\r
+ }\r
+ VW_ScreenToScreen(srcbase,destbase,WindowW / pixdiv,\r
+ WindowH - h);\r
+ }\r
+ else\r
+ {\r
+ i = WindowY + (h * (page - 1));\r
+ srcbase = base + ylookup[i - h];\r
+ destbase = base + ylookup[i];\r
+ base = ylookup[h];\r
+ for (i = page - 1;i;i--,srcbase -= base,destbase -= base)\r
+ VW_ScreenToScreen(srcbase,destbase,WindowW / pixdiv,h);\r
+ }\r
+ if (grmode == CGAGR)\r
+ {\r
+ VWB_Bar(WindowX,WindowY + (loc * h),WindowW,num * h,WHITE);\r
+ USL_DrawHelp((char far *)text,top,top + num,loc,h,lp);\r
+ VW_UpdateScreen();\r
+ }\r
+ else if (grmode == EGAGR)\r
+ {\r
+ base = panadjust + (WindowX / pixdiv) +\r
+ ylookup[WindowY + (loc * h)];\r
+ VW_ScreenToScreen(base + bufferofs,base + displayofs,\r
+ WindowW / pixdiv,h);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ US_ClearWindow();\r
+ USL_DrawHelp((char far *)text,top,top + num,loc,h,lp);\r
+ VW_UpdateScreen();\r
+ }\r
+\r
+ moved = false;\r
+ scroll = 0;\r
+ }\r
+\r
+ if (waitkey)\r
+ while (IN_KeyDown(waitkey))\r
+ ;\r
+ waitkey = sc_None;\r
+\r
+ IN_ReadCursor(&info);\r
+ if (info.y < 0)\r
+ {\r
+ if (cur > 0)\r
+ {\r
+ scroll = -1;\r
+ cur--;\r
+ moved = true;\r
+ }\r
+ }\r
+ else if (info.y > 0)\r
+ {\r
+ if (cur + page < lines)\r
+ {\r
+ scroll = +1;\r
+ cur++;\r
+ moved = true;\r
+ }\r
+ }\r
+ else if (info.button0 || info.button1)\r
+ done = true;\r
+ else if (IN_KeyDown(LastScan))\r
+ {\r
+ switch (LastScan)\r
+ {\r
+ case sc_Escape:\r
+ done = true;\r
+ break;\r
+ case sc_UpArrow:\r
+ if (cur > 0)\r
+ {\r
+ scroll = -1;\r
+ cur--;\r
+ moved = true;\r
+ }\r
+ break;\r
+ case sc_DownArrow:\r
+ if (cur + page < lines)\r
+ {\r
+ scroll = +1;\r
+ cur++;\r
+ moved = true;\r
+ }\r
+ break;\r
+ case sc_PgUp:\r
+ if (cur > page)\r
+ cur -= page;\r
+ else\r
+ cur = 0;\r
+ moved = true;\r
+ waitkey = sc_PgUp;\r
+ break;\r
+ case sc_PgDn:\r
+ if (cur + page < lines)\r
+ {\r
+ cur += page;\r
+ if (cur + page >= lines)\r
+ cur = lines - page;\r
+ moved = true;\r
+ }\r
+ waitkey = sc_PgDn;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ IN_ClearKeysDown();\r
+ do\r
+ {\r
+ IN_ReadCursor(&info);\r
+ } while (info.button0 || info.button1);\r
+\r
+ VW_ShowCursor();\r
+ US_ClearWindow();\r
+ VW_UpdateScreen();\r
+ US_RestoreWindow(&wr);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlHButtonCustom() - The custom routine for all of the help buttons\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlHButtonCustom(UserCall call,word i,word n)\r
+{\r
+ word j;\r
+ UserItem *ip;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ ip = &TheItems[i][n];\r
+ if (ip->sel & ui_Disabled)\r
+ return(false);\r
+\r
+ ip->sel |= ui_Selected;\r
+ USL_DrawItem(i,n);\r
+\r
+ USL_ClearBottom();\r
+\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp("Loading & Formatting Text...");\r
+ VW_UpdateScreen();\r
+\r
+#ifdef HELPTEXTLINKED // Ugly hack because of lack of disk space...\r
+ {\r
+extern char far gametext,far context,far story;\r
+ char far *buf;\r
+ memptr dupe;\r
+\r
+ switch (n)\r
+ {\r
+ case 0:\r
+ buf = &gametext;\r
+ break;\r
+ case 1:\r
+ buf = &context;\r
+ break;\r
+ case 2:\r
+ buf = &story;\r
+ break;\r
+ }\r
+\r
+ MM_GetPtr(&dupe,5000);\r
+ _fmemcpy((char far *)dupe,buf,5000);\r
+\r
+ USL_DoHelp(dupe,5000);\r
+\r
+ MM_FreePtr(&dupe);\r
+ if (LineOffsets)\r
+ MM_FreePtr(&LineOffsets);\r
+ }\r
+#else\r
+ {\r
+ char *name;\r
+ int file;\r
+ long len;\r
+ memptr buf;\r
+\r
+ switch (n)\r
+ {\r
+ case 0:\r
+ name = "GAMETEXT."EXTENSION;\r
+ break;\r
+ case 1:\r
+ name = "CONTEXT."EXTENSION;\r
+ break;\r
+ case 2:\r
+ name = "STORY."EXTENSION;\r
+ break;\r
+ default:\r
+ Quit("Bad help button number");\r
+ }\r
+\r
+ if ((file = open(name,O_RDONLY | O_TEXT)) == -1)\r
+ USL_HandleError(errno);\r
+ else\r
+ {\r
+ len = filelength(file);\r
+ MM_GetPtr(&buf,len);\r
+\r
+ if (CA_FarRead(file,(byte far *)buf,len))\r
+ USL_DoHelp(buf,len);\r
+ else\r
+ USL_HandleError(errno);\r
+\r
+ close(file);\r
+ MM_FreePtr(&buf);\r
+ }\r
+\r
+ if (LineOffsets)\r
+ MM_FreePtr(&LineOffsets);\r
+ }\r
+#endif\r
+\r
+ fontcolor = F_BLACK;\r
+\r
+ ip->sel &= ~ui_Selected;\r
+ USL_DrawItem(i,n);\r
+\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlDButtonCustom() - The custom routine for all of the disk buttons.\r
+// Sets up the bottom area of the window with the appropriate buttons\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlDButtonCustom(UserCall call,word i,word n)\r
+{\r
+ word j;\r
+ UserItem *ip;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ ip = &TheItems[i][n];\r
+ if (ip->sel & ui_Disabled)\r
+ return(false);\r
+\r
+ USL_ClearBottom();\r
+\r
+ j = 0;\r
+ TheItems[i + 1] = ip = n? CtlDEPanels : CtlDLSPanels;\r
+ while (ip && (ip->type != uii_Bad))\r
+ {\r
+ USL_DrawItem(i + 1,j++);\r
+ ip++;\r
+ }\r
+\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_DLSRect() - Draw the rectangle for the save game names\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static Rect\r
+USL_DLSRect(UserItem *ip)\r
+{\r
+ Rect r;\r
+\r
+ r.ul.x = ip->r.lr.x + 40 + 2;\r
+ r.ul.y = ip->r.ul.y + 2;\r
+ r.lr.x = WindowX + WindowW - 8 - 2;\r
+ r.lr.y = ip->r.lr.y - 2;\r
+\r
+ VWB_Bar(r.ul.x,r.ul.y,r.lr.x - r.ul.x,r.lr.y - r.ul.y,WHITE);\r
+\r
+ VWB_Hlin(r.ul.x,r.lr.x,r.ul.y,BLACK);\r
+ VWB_Hlin(r.ul.x,r.lr.x,r.lr.y,BLACK);\r
+ VWB_Vlin(r.ul.y,r.lr.y,r.ul.x,BLACK);\r
+ VWB_Vlin(r.ul.y,r.lr.y,r.lr.x,BLACK);\r
+\r
+ px = r.ul.x + 2;\r
+ py = r.ul.y + 2;\r
+\r
+ return(r);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlDLButtonCustom() - The load game custom routine\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlDLButtonCustom(UserCall call,word i,word n)\r
+{\r
+ char *filename,\r
+ msg[MaxGameName + 12];\r
+ word err;\r
+ int file;\r
+ UserItem *ip;\r
+ SaveGame *game;\r
+ WindowRec wr;\r
+\r
+ // DEBUG - deal with warning user about loading a game causing abort\r
+\r
+ game = &Games[n / 2];\r
+ ip = &TheItems[i][n];\r
+\r
+ switch (call)\r
+ {\r
+ case uic_Draw:\r
+ if (!loadedgame)\r
+ {\r
+ USL_DLSRect(ip);\r
+ fontcolor = game->present? F_BLACK : F_FIRSTCOLOR;\r
+ USL_DrawString(game->present? game->name : "Empty");\r
+ fontcolor = F_BLACK;\r
+ }\r
+ break;\r
+ case uic_Hit:\r
+ if (ip->sel & ui_Disabled)\r
+ return(false);\r
+\r
+ LeaveDriveOn++;\r
+ filename = USL_GiveSaveName(n / 2);\r
+\r
+ US_SaveWindow(&wr);\r
+ US_CenterWindow(30,3);\r
+ strcpy(msg,"Loading `");\r
+ strcat(msg,game->name);\r
+ strcat(msg,"\'");\r
+ US_PrintCentered(msg);\r
+ VW_HideCursor();\r
+ VW_UpdateScreen();\r
+\r
+ err = 0;\r
+ if ((file = open(filename,O_BINARY | O_RDONLY)) != -1)\r
+ {\r
+ if (read(file,game,sizeof(*game)) == sizeof(*game))\r
+ {\r
+ if (USL_LoadGame)\r
+ if (!USL_LoadGame(file))\r
+ USL_HandleError(err = errno);\r
+ }\r
+ else\r
+ USL_HandleError(err = errno);\r
+ close(file);\r
+ }\r
+ else\r
+ USL_HandleError(err = errno);\r
+ if (err)\r
+ abortgame = true;\r
+ else\r
+ loadedgame = true;\r
+ game->present = true;\r
+\r
+ if (loadedgame)\r
+ Paused = true;\r
+\r
+ VW_ShowCursor();\r
+ US_RestoreWindow(&wr);\r
+\r
+ LeaveDriveOn--;\r
+ break;\r
+ }\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlDSButtonCustom() - The save game custom routine\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlDSButtonCustom(UserCall call,word i,word n)\r
+{\r
+ boolean ok;\r
+ char *filename;\r
+ word err;\r
+ int file;\r
+ Rect r;\r
+ UserItem *ip;\r
+ SaveGame *game;\r
+ WindowRec wr;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ game = &Games[n / 2];\r
+ ip = &TheItems[i][n];\r
+ if (ip->sel & ui_Disabled)\r
+ return(false);\r
+\r
+ FlushHelp = true;\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp("Enter Game Name / Escape Aborts");\r
+ fontcolor = F_BLACK;\r
+\r
+ r = USL_DLSRect(ip - 1);\r
+ ok = US_LineInput(px,py,game->name,game->present? game->name : nil,true,\r
+ MaxGameName,r.lr.x - r.ul.x - 8);\r
+ if (!strlen(game->name))\r
+ strcpy(game->name,"Untitled");\r
+ if (ok)\r
+ {\r
+ US_SaveWindow(&wr);\r
+ US_CenterWindow(10,3);\r
+ US_PrintCentered("Saving");\r
+ VW_HideCursor();\r
+ VW_UpdateScreen();\r
+\r
+ LeaveDriveOn++;\r
+ filename = USL_GiveSaveName(n / 2);\r
+ err = 0;\r
+ file = open(filename,O_CREAT | O_BINARY | O_WRONLY,\r
+ S_IREAD | S_IWRITE | S_IFREG);\r
+ if (file != -1)\r
+ {\r
+ if (write(file,game,sizeof(*game)) == sizeof(*game))\r
+ {\r
+ if (USL_SaveGame)\r
+ ok = USL_SaveGame(file);\r
+ if (!ok)\r
+ USL_HandleError(err = errno);\r
+ }\r
+ else\r
+ USL_HandleError(err = ((errno == ENOENT)? ENOMEM : errno));\r
+ close(file);\r
+ }\r
+ else\r
+ USL_HandleError(err = ((errno == ENOENT)? ENOMEM : errno));\r
+ if (err)\r
+ {\r
+ remove(filename);\r
+ ok = false;\r
+ }\r
+ LeaveDriveOn--;\r
+\r
+ VW_ShowCursor();\r
+ US_RestoreWindow(&wr);\r
+ USL_DoHit(i - 1,0);\r
+ VW_UpdateScreen();\r
+ }\r
+\r
+ if (!game->present)\r
+ game->present = ok;\r
+\r
+ if (ok)\r
+ {\r
+ GameIsDirty = false;\r
+ (ip - 1)->sel &= ~ui_Disabled;\r
+ }\r
+\r
+ USL_DrawItem(i,n - 1);\r
+// USL_CtlDLButtonCustom(uic_Draw,i,n - 1);\r
+\r
+ return(true);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlSButtonCustom() - The custom routine for all of the sound buttons\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlSButtonCustom(UserCall call,word i,word n)\r
+{\r
+ word j;\r
+ UserItem *ip;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ ip = &TheItems[i][n];\r
+ if (ip->sel & ui_Disabled)\r
+ return(false);\r
+\r
+ USL_ClearBottom();\r
+\r
+ if (n == sdm_SoundSource)\r
+ {\r
+ j = 0;\r
+ TheItems[i + 1] = ip = CtlSSSPanels;\r
+ while (ip && (ip->type != uii_Bad))\r
+ {\r
+ USL_DrawItem(i + 1,j++);\r
+ ip++;\r
+ }\r
+ }\r
+ else\r
+ TheItems[i + 1] = nil;\r
+\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlPButtonCustom() - The custom routine for all of the start game btns\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlPButtonCustom(UserCall call,word i,word n)\r
+{\r
+ word j;\r
+ UserItem *ip;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ ip = &TheItems[i][n];\r
+ if (ip->sel & ui_Disabled)\r
+ return(false);\r
+\r
+ USL_ClearBottom();\r
+\r
+ j = 0;\r
+ TheItems[i + 1] = ip = n? CtlPRPanels : CtlPSPanels;\r
+ while (ip && (ip->type != uii_Bad))\r
+ {\r
+ USL_DrawItem(i + 1,j++);\r
+ ip++;\r
+ }\r
+\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_GiveAbortWarning() - Draws a string that warns the user that an\r
+// action they're about to take will abort the game in progress\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_GiveAbortWarning(void)\r
+{\r
+ WindowRec wr;\r
+\r
+ if (!GameIsDirty)\r
+ return;\r
+\r
+ US_SaveWindow(&wr);\r
+ US_RestoreWindow(&BottomWindow);\r
+ US_HomeWindow();\r
+ PrintY += 5;\r
+\r
+ VWB_Bar(WindowX,WindowY,WindowW,30,WHITE);\r
+ fontcolor = F_SECONDCOLOR;\r
+ US_CPrint("Warning! If you do this, you'll");\r
+ US_CPrint("abort the current game.");\r
+ fontcolor = F_BLACK;\r
+\r
+ US_RestoreWindow(&wr);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlPSButtonCustom() - The custom routine for the start game button\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlPSButtonCustom(UserCall call,word i,word n)\r
+{\r
+ boolean result;\r
+ UserItem *ip;\r
+\r
+ i++; // Shut the compiler up\r
+\r
+ switch (call)\r
+ {\r
+ case uic_Hit:\r
+ switch (n)\r
+ {\r
+ case 0:\r
+ restartgame = gd_Normal;\r
+ break;\r
+ case 1:\r
+ restartgame = gd_Easy;\r
+ break;\r
+ case 2:\r
+ restartgame = gd_Hard;\r
+ break;\r
+ }\r
+ if (restartgame && ingame && USL_ResetGame)\r
+ USL_ResetGame();\r
+ result = false;\r
+ break;\r
+ case uic_Draw:\r
+ USL_GiveAbortWarning();\r
+ result = false;\r
+ break;\r
+ default:\r
+ result = false;\r
+ break;\r
+ }\r
+ return(result);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlPRButtonCustom() - The custom routine for the resume game button\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlPRButtonCustom(UserCall call,word i,word n)\r
+{\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ i++,n++; // Shut the compiler up\r
+ ResumeGame = true;\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlDEButtonCustom() - The custom routine for the exit to DOS button\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlDEButtonCustom(UserCall call,word i,word n)\r
+{\r
+ boolean result;\r
+ UserItem *ip;\r
+\r
+ i++,n++; // Shut the compiler up\r
+\r
+ switch (call)\r
+ {\r
+ case uic_Hit:\r
+ QuitToDos = true;\r
+ break;\r
+ case uic_Draw:\r
+ USL_GiveAbortWarning();\r
+ default:\r
+ result = false;\r
+ break;\r
+ }\r
+ return(result);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CtlCButtonCustom() - The custom routine for all of the control\r
+// buttons\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CtlCButtonCustom(UserCall call,word i,word n)\r
+{\r
+ word j;\r
+ Point p;\r
+ UserItem *ip;\r
+\r
+ if (call != uic_Hit)\r
+ return(false);\r
+\r
+ ip = &TheItems[i][n];\r
+ if (ip->sel & ui_Disabled)\r
+ return(false);\r
+\r
+ USL_ClearBottom();\r
+ if (n == 0) // Keyboard\r
+ {\r
+ TheItems[i + 1] = ip = CtlCKbdPanels;\r
+ p = CtlCKbdPanels[2].r.lr;\r
+ VWB_DrawPic(p.x,p.y,CTL_DIRSPIC);\r
+ }\r
+ else\r
+ TheItems[i + 1] = ip = CtlCJoyPanels;\r
+\r
+ j = 0;\r
+ while (ip && (ip->type != uii_Bad))\r
+ {\r
+ USL_DrawItem(i + 1,j++);\r
+ ip++;\r
+ }\r
+\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_HitHotKey() - After a hotkey was hit, move the cursor to the first\r
+// selected item in the group after the group containing the item\r
+// holding the hotkey\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_HitHotKey(int i,int n)\r
+{\r
+ UserItem *ip;\r
+\r
+ if (ip = TheItems[++i])\r
+ {\r
+ if ((n = USL_FindDown(TheItems[i])) == -1)\r
+ n = 0;\r
+ ip += n;\r
+ CursorX = ip->r.lr.x - 8;\r
+ CursorY = ip->r.lr.y - 8;\r
+ CursorBad = true;\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_CheckScan() - Checks to see if the scancode in LastScan corresponds\r
+// to anything in the list of useritems. If so, selects the item.\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static boolean\r
+USL_CheckScan(word *ci,word *cn)\r
+{\r
+ word i,n;\r
+ UserItem *ip;\r
+\r
+ if (!LastScan)\r
+ return(false);\r
+\r
+#if 1 // DEBUG - probably kill this code\r
+ // Use 1..? for the items across the top row\r
+ if (TheItems[1] && !IN_KeyDown(sc_RShift))\r
+ {\r
+ for (i = 0,ip = TheItems[1];(ip->type != uii_Bad) && (i < 9);i++,ip++)\r
+ ;\r
+ for (n = 0;n < i;n++)\r
+ {\r
+ if (LastScan == 2 + n) // Numbers from 1..9\r
+ {\r
+ if (!(TheItems[1][n].sel & ui_Disabled))\r
+ {\r
+ LastScan = sc_None;\r
+ USL_DoHit(1,n);\r
+ return(true);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // Use Alt-1..6 for the items in the leftmost column\r
+ if (IN_KeyDown(sc_RShift))\r
+ {\r
+ n = LastScan - 2;\r
+ if (n < 6) // Numbers from 1..6\r
+ {\r
+ USL_DoHit(0,n);\r
+ LastScan = sc_None;\r
+ return(true);\r
+ }\r
+ }\r
+#endif\r
+\r
+ // Check normal hotkeys for the leftmost column\r
+ for (i = 0;CtlPanels[i].type != uii_Bad;i++)\r
+ {\r
+ if (CtlPanels[i].key == LastScan)\r
+ {\r
+ LastScan = sc_None;\r
+ USL_DoHit(0,i);\r
+ *ci = 0;\r
+ *cn = i;\r
+ USL_HitHotKey(0,i);\r
+ return(true);\r
+ }\r
+ }\r
+\r
+ // Check normal hotkeys for the top row\r
+ for (i = 0;i < 6;i++)\r
+ {\r
+ for (n = 0,ip = CtlPanels2[i];ip && ip->type != uii_Bad;n++,ip++)\r
+ {\r
+ if ((ip->key == LastScan) && !(ip->sel & ui_Disabled))\r
+ {\r
+ LastScan = sc_None;\r
+ USL_DoHit(0,i);\r
+ USL_DoHit(1,n);\r
+ *ci = 1;\r
+ *cn = n;\r
+ USL_HitHotKey(1,n);\r
+ return(true);\r
+ }\r
+ }\r
+ }\r
+ return(false);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_SetUpCtlPanel() - Sets the states of the UserItems to reflect the\r
+// values of all the appropriate variables\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_SetUpCtlPanel(void)\r
+{\r
+ word i,j;\r
+\r
+ GameIsDirty = ingame;\r
+\r
+ // Set up restart game\r
+ USL_TurnOff(CtlPPanels);\r
+ CtlPPanels[0].sel = ingame? ui_Normal : ui_Selected;\r
+ CtlPPanels[1].sel = ingame? ui_Selected : ui_Disabled;\r
+\r
+ // Set up disk stuff - default to load/save game\r
+ USL_TurnOff(CtlDPanels);\r
+ CtlDPanels[0].sel = ui_Selected;\r
+\r
+ // Set up load/save buttons\r
+ USL_TurnOff(CtlDLSPanels);\r
+ for (i = 0;i < MaxSaveGames;i++)\r
+ {\r
+ if (!Games[i].present)\r
+ CtlDLSPanels[i * 2].sel = ui_Disabled;\r
+ if (!ingame)\r
+ CtlDLSPanels[(i * 2) + 1].sel = ui_Disabled;\r
+ }\r
+\r
+ // Set up Controls\r
+ USL_TurnOff(CtlCPanels);\r
+ CtlCPanels[1].sel = JoysPresent[0]? ui_Normal : ui_Disabled;\r
+ CtlCPanels[2].sel = JoysPresent[1]? ui_Normal : ui_Disabled;\r
+ if (Controls[0] == ctrl_Keyboard)\r
+ i = 0;\r
+ else\r
+ i = (Controls[0] == ctrl_Joystick1)? 1 : 2;\r
+ CtlCPanels[i].sel |= ui_Selected;\r
+ if (JoysPresent[1] && !JoysPresent[0])\r
+ CtlCPanels[2].key = sc_F4;\r
+ else\r
+ CtlCPanels[1].key = sc_F4;\r
+\r
+ // Set up Keyboard\r
+ for (i = 0;i < 10;i++)\r
+ CtlCKbdPanels[i].text = IN_GetScanName(*(KeyMaps[i]));\r
+\r
+ // Set up Sounds\r
+ USL_TurnOff(CtlSPanels);\r
+ CtlSPanels[sdm_AdLib].sel = AdLibPresent? ui_Normal : ui_Disabled;\r
+#if 0 // DEBUG - hack because no space for digitized sounds on Keen Dreams\r
+ CtlSPanels[sdm_SoundBlaster].sel =\r
+ SoundBlasterPresent? ui_Normal : ui_Disabled;\r
+ CtlSPanels[sdm_SoundSource].sel =\r
+ SoundSourcePresent? ui_Normal : ui_Disabled;\r
+#else\r
+ CtlSPanels[sdm_SoundBlaster].sel = ui_Disabled;\r
+ CtlSPanels[sdm_SoundSource].sel = ui_Disabled;\r
+#endif\r
+ CtlSPanels[SoundMode].sel |= ui_Selected;\r
+\r
+ // Set up SoundSource\r
+ USL_TurnOff(CtlSSSPanels);\r
+ CtlSSSPanels[0].sel = ssIsTandy? ui_Selected : ui_Normal;\r
+ CtlSSSPanels[1].sel = (ssPort == 2)? ui_Selected : ui_Normal;\r
+\r
+ // Set up Music\r
+ USL_TurnOff(CtlMPanels);\r
+ CtlMPanels[smm_AdLib].sel = AdLibPresent? ui_Normal : ui_Disabled;\r
+ CtlMPanels[MusicMode].sel |= ui_Selected;\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// USL_TearDownCtlPanel() - Given the state of the control panel, sets the\r
+// modes and values as appropriate\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+static void\r
+USL_TearDownCtlPanel(void)\r
+{\r
+ int i;\r
+\r
+ i = USL_FindDown(CtlCPanels);\r
+ if (i != -1)\r
+ {\r
+ i = i? (i == 1? ctrl_Joystick1 : ctrl_Joystick2) : ctrl_Keyboard;\r
+ IN_SetControlType(0,i);\r
+ }\r
+\r
+ CtlCPanels[1].key = CtlCPanels[2].key = sc_None;\r
+\r
+ i = USL_FindDown(CtlSPanels);\r
+ if (i != -1)\r
+ SD_SetSoundMode(i);\r
+\r
+ ssIsTandy = CtlSSSPanels[0].sel & ui_Selected;\r
+ ssPort = (CtlSSSPanels[1].sel & ui_Selected)? 2 : 1;\r
+\r
+ i = USL_FindDown(CtlMPanels);\r
+ if (i != -1)\r
+ {\r
+ SD_SetMusicMode(i);\r
+\r
+ if (!QuitToDos)\r
+ {\r
+ US_CenterWindow(20,8);\r
+ US_CPrint("Loading");\r
+#if 0\r
+ fontcolor = F_SECONDCOLOR;\r
+ US_CPrint("Sounds");\r
+ fontcolor = F_BLACK;\r
+#endif\r
+ VW_UpdateScreen();\r
+\r
+ CA_LoadAllSounds();\r
+ }\r
+ }\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_ControlPanel() - This is the main routine for the control panel\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_ControlPanel(void)\r
+{\r
+ char gamename[MaxGameName + 10 + 1];\r
+ ScanCode c;\r
+ boolean done,\r
+ buttondown,inrect;\r
+ word hiti,hitn,\r
+ i,n,\r
+ lasti,lastn,\r
+ lastx,lasty;\r
+ longword lasttime;\r
+ Point p;\r
+ Rect userect;\r
+ UserItem *ip;\r
+\r
+ c = LastScan;\r
+ if (c == sc_Escape) // Map escape from game to Exit to DOS\r
+ c = sc_Q;\r
+\r
+ CA_UpLevel();\r
+ for (i = CONTROLS_LUMP_START;i <= CONTROLS_LUMP_END;i++)\r
+ CA_MarkGrChunk(i);\r
+ CA_MarkGrChunk(CTL_LITTLEMASKPICM);\r
+ CA_MarkGrChunk(CTL_LSMASKPICM);\r
+ CA_CacheMarks("Options Screen");\r
+\r
+ USL_SetUpCtlPanel();\r
+\r
+ US_SetPrintRoutines(VW_MeasurePropString,VWB_DrawPropString);\r
+ fontcolor = F_BLACK;\r
+\r
+ VW_InitDoubleBuffer();\r
+\r
+ VWB_Bar(0,0,MaxX,MaxY,FIRSTCOLOR);\r
+ US_DrawWindow(8,22,30,2);\r
+ US_SaveWindow(&HelpWindow);\r
+ US_DrawWindow(8,7,30,14);\r
+ US_SaveWindow(&BottomWindow);\r
+ US_DrawWindow(8,1,30,20);\r
+\r
+ for (ip = CtlPanels;ip->type != uii_Bad;ip++)\r
+ VWB_DrawPic(ip->r.ul.x,ip->r.ul.y,ip->picup);\r
+\r
+ US_StartCursor();\r
+ CursorX = (8 * 8) + ((MaxX - (8 * 8)) / 2);\r
+ CursorBad = true;\r
+\r
+ CtlPanelButton = -1;\r
+ LastScan = c;\r
+ USL_CheckScan(&i,&n);\r
+ if (CtlPanelButton == -1)\r
+ USL_DoHit(0,0);\r
+\r
+ ResumeGame = false;\r
+ done = false;\r
+ FlushHelp = true;\r
+ lastx = lasty = -1;\r
+ while\r
+ (\r
+ (restartgame == gd_Continue)\r
+ && !(done || loadedgame || ResumeGame)\r
+ )\r
+ {\r
+ VW_UpdateScreen();\r
+\r
+ buttondown = US_UpdateCursor();\r
+ inrect = USL_IsInRect(CursorX,CursorY,&i,&n);\r
+\r
+ if (FlushHelp)\r
+ {\r
+ lasti = -2;\r
+ lasttime = TimeCount;\r
+ FlushHelp = false;\r
+ }\r
+ if (inrect)\r
+ {\r
+ if ((lasti != i) || (lastn != n))\r
+ {\r
+ // If over a Load button\r
+ if\r
+ (\r
+ (CtlPanelButton == 2)\r
+ && (i == 2)\r
+ && (TheItems[1][0].sel & ui_Selected)\r
+ && (Games[n / 2].present)\r
+ && !(n & 1)\r
+ )\r
+ {\r
+ strcpy(gamename,"Load `");\r
+ strcat(gamename,Games[n / 2].name);\r
+ strcat(gamename,"'");\r
+ USL_ShowHelp(gamename);\r
+ }\r
+ else\r
+ USL_ShowHelp(TheItems[i][n].help);\r
+ lasti = i;\r
+ lastn = n;\r
+ }\r
+ }\r
+ else if (lasti != (word)-1)\r
+ {\r
+ USL_ShowHelp("Select a Button");\r
+ lasti = -1;\r
+ }\r
+\r
+ hiti = i;\r
+ hitn = n;\r
+\r
+ if (inrect)\r
+ userect = TheItems[i][n].r;\r
+ else\r
+ {\r
+ userect.ul.x = CursorX;\r
+ userect.ul.y = CursorY;\r
+ userect.lr = userect.ul;\r
+ }\r
+\r
+ if (IN_KeyDown(sc_UpArrow))\r
+ {\r
+ USL_FindRect(userect,motion_None,motion_Up);\r
+ buttondown = false;\r
+ IN_ClearKey(sc_UpArrow);\r
+ }\r
+ else if (IN_KeyDown(sc_DownArrow))\r
+ {\r
+ USL_FindRect(userect,motion_None,motion_Down);\r
+ buttondown = false;\r
+ IN_ClearKey(sc_DownArrow);\r
+ }\r
+ else if (IN_KeyDown(sc_LeftArrow))\r
+ {\r
+ USL_FindRect(userect,motion_Left,motion_None);\r
+ buttondown = false;\r
+ IN_ClearKey(sc_LeftArrow);\r
+ }\r
+ else if (IN_KeyDown(sc_RightArrow))\r
+ {\r
+ USL_FindRect(userect,motion_Right,motion_None);\r
+ buttondown = false;\r
+ IN_ClearKey(sc_RightArrow);\r
+ }\r
+ else if\r
+ (\r
+ IN_KeyDown(c = sc_Return)\r
+ || IN_KeyDown(c = KbdDefs[0].button0)\r
+ || IN_KeyDown(c = KbdDefs[0].button1)\r
+ )\r
+ {\r
+ IN_ClearKey(c);\r
+ if (inrect)\r
+ {\r
+ ip = &TheItems[hiti][hitn];\r
+\r
+ if ((ip->type == uii_Button) && !(ip->sel & ui_Disabled))\r
+ {\r
+ lasttime = TimeCount;\r
+\r
+ ip->sel |= ui_Selected;\r
+ USL_DrawItem(hiti,hitn);\r
+ VW_UpdateScreen();\r
+\r
+ while (TimeCount - lasttime < TickBase / 4)\r
+ ;\r
+ lasttime = TimeCount;\r
+\r
+ ip->sel &= ~ui_Selected;\r
+ USL_DrawItem(hiti,hitn);\r
+ VW_UpdateScreen();\r
+\r
+ while (TimeCount - lasttime < TickBase / 4)\r
+ ;\r
+ }\r
+\r
+ USL_DoHit(hiti,hitn);\r
+ }\r
+ }\r
+ else if (USL_CheckScan(&i,&n))\r
+ ;\r
+ else if (buttondown && inrect && USL_TrackItem(hiti,hitn))\r
+ USL_DoHit(hiti,hitn);\r
+\r
+ if (LastScan == sc_Escape)\r
+ {\r
+ IN_ClearKey(sc_Escape);\r
+ done = true;\r
+ }\r
+\r
+ if (QuitToDos)\r
+ done = true;\r
+\r
+ if ((lastx != CursorX) || (lasty != CursorY))\r
+ {\r
+ lastx = CursorX;\r
+ lasty = CursorY;\r
+ lasttime = TimeCount;\r
+ }\r
+ if (TimeCount - lasttime > TickBase * 10)\r
+ {\r
+ if (((TimeCount - lasttime) / TickBase) & 2)\r
+ fontcolor = F_SECONDCOLOR;\r
+ USL_ShowHelp("Press F1 for Help");\r
+ fontcolor = F_BLACK;\r
+ }\r
+ }\r
+\r
+ US_ShutCursor();\r
+\r
+ USL_TearDownCtlPanel();\r
+\r
+ if (restartgame && USL_ResetGame)\r
+ USL_ResetGame();\r
+\r
+ if (QuitToDos)\r
+ {\r
+ if (tedlevel)\r
+ TEDDeath();\r
+ else\r
+ {\r
+ US_CenterWindow(20,3);\r
+ fontcolor = F_SECONDCOLOR;\r
+ US_PrintCentered("Now Exiting to DOS...");\r
+ fontcolor = F_BLACK;\r
+ VW_UpdateScreen();\r
+ Quit(nil);\r
+ }\r
+ }\r
+\r
+ CA_DownLevel();\r
+}\r
+\r
+// High score routines\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_DisplayHighScores() - Assumes that double buffering has been started.\r
+// If passed a -1 will just display the high scores, but if passed\r
+// a non-negative number will display that entry in red and let the\r
+// user type in a name\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_DisplayHighScores(int which)\r
+{\r
+ char buffer[16],*str;\r
+ word i,\r
+ w,h,\r
+ x,y;\r
+ HighScore *s;\r
+\r
+ US_CenterWindow(30,MaxScores + (MaxScores / 2));\r
+\r
+ x = WindowX + (WindowW / 2);\r
+ US_Print(" Name");\r
+ PrintX = x + 20;\r
+ US_Print("Score");\r
+ PrintX = x + 60;\r
+ US_Print("Done\n\n");\r
+ PrintY -= 3;\r
+\r
+ for (i = WindowX;i < WindowX + WindowW;i += 8)\r
+ VWB_DrawTile8M(i,WindowY + 8,10);\r
+ VWB_DrawTile8M(WindowX - 8,WindowY + 8,9);\r
+ VWB_DrawTile8M(WindowX + WindowW,WindowY + 8,11);\r
+\r
+ for (i = 0,s = Scores;i < MaxScores;i++,s++)\r
+ {\r
+ fontcolor = (i == which)? F_SECONDCOLOR : F_BLACK;\r
+\r
+ if (i != which)\r
+ {\r
+ US_Print(" ");\r
+ if (strlen(s->name))\r
+ US_Print(s->name);\r
+ else\r
+ US_Print("-");\r
+ }\r
+ else\r
+ y = PrintY;\r
+\r
+ PrintX = x + (7 * 8);\r
+ ultoa(s->score,buffer,10);\r
+ for (str = buffer;*str;str++)\r
+ *str = *str + (129 - '0'); // Used fixed-width numbers (129...)\r
+ USL_MeasureString(buffer,&w,&h);\r
+ PrintX -= w;\r
+ US_Print(buffer);\r
+\r
+ PrintX = x + 60;\r
+ if (s->completed)\r
+ US_PrintUnsigned(s->completed);\r
+ else\r
+ US_Print("-");\r
+\r
+ US_Print("\n");\r
+ }\r
+\r
+ if (which != -1)\r
+ {\r
+ fontcolor = F_SECONDCOLOR;\r
+ PrintY = y;\r
+ PrintX = WindowX;\r
+ US_Print(" ");\r
+ strcpy(Scores[which].name,"");\r
+ US_LineInput(PrintX,PrintY,Scores[which].name,nil,true,MaxHighName,\r
+ (WindowW / 2) - 8);\r
+ }\r
+ fontcolor = F_BLACK;\r
+\r
+ VW_UpdateScreen();\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////\r
+//\r
+// US_CheckHighScore() - Checks gamestate to see if the just-ended game\r
+// should be entered in the high score list. If so, lets the user\r
+// enter their name\r
+//\r
+///////////////////////////////////////////////////////////////////////////\r
+void\r
+US_CheckHighScore(long score,word other)\r
+{\r
+ word i,j,\r
+ n;\r
+ HighScore myscore;\r
+\r
+ strcpy(myscore.name,"");\r
+ myscore.score = score;\r
+ myscore.completed = other;\r
+\r
+ for (i = 0,n = -1;i < MaxScores;i++)\r
+ {\r
+ if\r
+ (\r
+ (myscore.score > Scores[i].score)\r
+ || (\r
+ (myscore.score == Scores[i].score)\r
+ && (myscore.completed > Scores[i].completed)\r
+ )\r
+ )\r
+ {\r
+ for (j = MaxScores;--j > i;)\r
+ Scores[j] = Scores[j - 1];\r
+ Scores[i] = myscore;\r
+\r
+ n = i;\r
+ HighScoresDirty = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ VW_InitDoubleBuffer();\r
+ VWB_Bar(0,0,MaxX,MaxY,FIRSTCOLOR);\r
+\r
+ US_DisplayHighScores(n);\r
+ IN_UserInput(5 * TickBase,false);\r
+}\r