/* NetHack 3.7 vidtxt.c $NHDT-Date: 1596498278 2020/08/03 23:44:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * vidtxt.c - Textmode video hardware support (BIOS and DJGPPFAST) * *Edit History: * Initial Creation M. Allison 93/04/04 * Add djgpp support K. Smolkowski 93/04/26 * Add runtime monoadapter check M. Allison 93/05/09 */ #define VIDEO_TEXT #include "hack.h" #include "pcvideo.h" #include "wintty.h" #include #if defined(_MSC_VER) #if _MSC_VER >= 700 #pragma warning(disable : 4018) /* signed/unsigned mismatch */ #pragma warning(disable : 4127) /* conditional expression is constant */ /* #pragma warning(disable : 4131) */ /* old style declarator */ #pragma warning(disable : 4305) /* prevents complaints with MK_FP */ #pragma warning(disable : 4309) /* initializing */ #pragma warning(disable : 4759) /* prevents complaints with MK_FP */ #endif #endif /* void txt_xputc(char, int);*/ /* write out character (and attribute) */ extern int attrib_text_normal; /* text mode normal attribute */ extern int attrib_gr_normal; /* graphics mode normal attribute */ extern int attrib_text_intense; /* text mode intense attribute */ extern int attrib_gr_intense; /* graphics mode intense attribute */ #if defined(SCREEN_BIOS) && !defined(PC9800) static unsigned char cursor_info = 0, cursor_start_scanline = 6, cursor_end_scanline = 7; static void get_cursinfo(unsigned char *start, unsigned char *end, unsigned char *flg); #endif void txt_get_scr_size(void) { union REGS regs; if (!iflags.BIOS) { CO = 80; LI = 24; return; } #ifdef PC9800 regs.h.ah = SENSEMODE; (void) int86(CRT_BIOS, ®s, ®s); CO = (regs.h.al & 0x02) ? 40 : 80; LI = (regs.h.al & 0x01) ? 20 : 25; #else regs.x.ax = FONTINFO; regs.x.bx = 0; /* current ROM BIOS font */ regs.h.dl = 24; /* default row count */ /* in case no EGA/MCGA/VGA */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Font Information */ /* MDA/CGA/PCjr ignore INT 10h, Function 11h, but since we * cleverly loaded up DL with the default, everything's fine. * * Otherwise, DL now contains rows - 1. Also, CX contains the * points (bytes per character) and ES:BP points to the font * table. -3. */ regs.h.ah = GETMODE; (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Video Mode */ /* This goes back all the way to the original PC. Completely * safe. AH contains # of columns, AL contains display mode, * and BH contains the active display page. */ LI = regs.h.dl + 1; CO = regs.h.ah; #endif /* PC9800 */ } /* * -------------------------------------------------------------- * The rest of this file is only compiled if NO_TERMS is defined. * -------------------------------------------------------------- */ #ifdef NO_TERMS /* #include "wintty.h" */ #ifdef SCREEN_DJGPPFAST #include #include #endif void txt_gotoxy(int, int); #if defined(SCREEN_BIOS) && !defined(PC9800) void txt_get_cursor(int *, int *); #endif #ifdef SCREEN_DJGPPFAST #define txt_get_cursor(x, y) ScreenGetCursor(y, x) #endif extern int g_attribute; /* Current attribute to use */ extern int monoflag; /* 0 = not monochrome, else monochrome */ void txt_backsp(void) { #ifdef PC9800 union REGS regs; regs.h.dl = 0x01; /* one column */ regs.h.ah = CURSOR_LEFT; regs.h.cl = DIRECT_CON_IO; int86(DOS_EXT_FUNC, ®s, ®s); #else int col, row; txt_get_cursor(&col, &row); if (col > 0) col = col - 1; txt_gotoxy(col, row); #endif } void txt_nhbell(void) { union REGS regs; if (flags.silent) return; regs.h.dl = 0x07; /* bell */ regs.h.ah = 0x02; /* Character Output function */ (void) int86(DOSCALL, ®s, ®s); } void txt_clear_screen(void) /* djgpp provides ScreenClear(), but in version 1.09 it is broken * so for now we just use the BIOS Routines */ { union REGS regs; #ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x02; /* clear whole screen */ regs.h.ah = SCREEN_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else regs.h.dl = (char) (CO - 1); /* columns */ regs.h.dh = (char) (LI - 1); /* rows */ regs.x.cx = 0; /* CL,CH = x,y of upper left */ regs.x.ax = 0; regs.x.bx = 0; regs.h.bh = (char) attrib_text_normal; regs.h.ah = (char) SCROLL; /* DL,DH = x,y of lower rt */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Scroll or init window */ txt_gotoxy(0, 0); #endif } /* clear to end of line */ void txt_cl_end(int col, int row) { union REGS regs; #ifndef PC9800 int count; #endif #ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x00; /* clear to end of line */ regs.h.ah = LINE_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else count = CO - col; txt_gotoxy(col, row); regs.h.ah = PUTCHARATT; /* write attribute & character */ regs.h.al = ' '; /* character */ regs.h.bh = 0; /* display page */ /* BL = attribute */ regs.h.bl = (char) attrib_text_normal; regs.x.cx = count; if (count != 0) (void) int86(VIDEO_BIOS, ®s, ®s); /* write attribute & character */ #endif } void txt_cl_eos(void) /* clear to end of screen */ { union REGS regs; #ifndef PC9800 int col, row; #endif #ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x00; /* clear to end of screen */ regs.h.ah = SCREEN_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else txt_get_cursor(&col, &row); txt_cl_end(col, row); /* clear to end of line */ if (row < LI - 1) { txt_gotoxy(0, (row < (LI - 1) ? row + 1 : (LI - 1))); regs.h.dl = (char) (CO - 1); /* X of lower right */ regs.h.dh = (char) (LI - 1); /* Y of lower right */ regs.h.cl = 0; /* X of upper left */ /* Y (row) of upper left */ regs.h.ch = (char) (row < (LI - 1) ? row + 1 : (LI - 1)); regs.x.ax = 0; regs.x.bx = 0; regs.h.bh = (char) attrib_text_normal; regs.h.ah = SCROLL; (void) int86(VIDEO_BIOS, ®s, ®s); /* Scroll or initialize window */ } #endif } void txt_startup(int *wid, int *hgt) { txt_get_scr_size(); *wid = CO; *hgt = LI; attrib_gr_normal = attrib_text_normal; attrib_gr_intense = attrib_text_intense; g_attribute = attrib_text_normal; /* Give it a starting value */ get_cursinfo(&cursor_start_scanline, &cursor_end_scanline, &cursor_info); } /* * Screen output routines (these are heavily used). * * These are the 3 routines used to place information on the screen * in the NO_TERMS PC tty port of NetHack. These are the routines * that get called by routines in other NetHack source files (such * as those in win/tty). * * txt_xputs - Writes a c null terminated string at the current location. * Depending on compile options, this could just be a series * of repeated calls to xputc() for each character. * txt_xputc - Writes a single character at the current location. Since * various places in the code assume that control characters * can be used to control, we are forced to interpret some of * the more common ones, in order to keep things looking correct. * * NOTES: * wintty.h uses macros to redefine common output functions * such as puts, putc, putchar, so that they get steered into * either xputs (for strings) or xputc (for single characters). * References to puts, putc, and putchar in other source files * (that include wintty.h) are actually using these routines. */ void txt_xputs(const char *s, int col, int row) { char c; if (s != (char *) 0) { while (*s != '\0') { txt_gotoxy(col, row); c = *s++; txt_xputc(c, g_attribute); if (col < (CO - 1)) col++; txt_gotoxy(col, row); } } } /* write out character (and attribute) */ void txt_xputc(char ch, int attr) { #ifdef PC9800 union REGS regs; regs.h.dl = attr98[attr]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); if (ch == '\n') { regs.h.dl = '\r'; regs.h.ah = PUTCHAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); } regs.h.dl = ch; regs.h.ah = PUTCHAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); #else #ifdef SCREEN_BIOS union REGS regs; #endif int col, row; txt_get_cursor(&col, &row); switch (ch) { case '\n': #if 0 col = 0; ++row; #endif break; default: #ifdef SCREEN_DJGPPFAST ScreenPutChar((int) ch, attr, col, row); #endif #ifdef SCREEN_BIOS regs.h.ah = PUTCHARATT; /* write att & character */ regs.h.al = ch; /* character */ regs.h.bh = 0; /* display page */ regs.h.bl = (char) attr; /* BL = attribute */ regs.x.cx = 1; /* one character */ (void) int86(VIDEO_BIOS, ®s, ®s); #endif if (col < (CO - 1)) ++col; break; } /* end switch */ txt_gotoxy(col, row); #endif /* PC9800 */ } /* * This marks the end of the general screen output routines that are * called from other places in NetHack. * --------------------------------------------------------------------- */ /* * Cursor location manipulation, and location information fetching * routines. * These include: * * txt_get_cursor(x,y) - Returns the current location of the cursor. In * some implementations this is implemented as a * function (BIOS), and in others it is a macro * (DJGPPFAST). * * txt_gotoxy(x,y) - Moves the cursor on screen to the specified x and * y location. This routine moves the location where * screen writes will occur next, it does not change * the location of the player on the NetHack level. */ #if defined(SCREEN_BIOS) && !defined(PC9800) /* * get cursor position * * This is implemented as a macro under DJGPPFAST. */ void txt_get_cursor(int *x, int *y) { union REGS regs; regs.x.dx = 0; regs.h.ah = GETCURPOS; /* get cursor position */ regs.x.cx = 0; regs.x.bx = 0; (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Cursor Position */ *x = regs.h.dl; *y = regs.h.dh; if (!cursor_info) { cursor_start_scanline = regs.h.ch; cursor_end_scanline = regs.h.cl; cursor_info = 1; } } void txt_hide_cursor(void) { union REGS regs; regs.x.dx = 0; regs.h.ah = SETCURTYP; /* set cursor type */ regs.h.ch = 0x3F; /* starting scanline */ regs.h.cl = 0; /* ending scanline */ regs.x.bx = 0; (void) int86(VIDEO_BIOS, ®s, ®s); } void txt_show_cursor(void) { union REGS regs; regs.x.dx = 0; regs.h.ah = SETCURTYP; /* set cursor type */ if (cursor_info) { regs.h.ch = cursor_start_scanline; /* starting scanline */ regs.h.cl = cursor_end_scanline; /* ending scanline */ } else { regs.h.ch = 6; /* starting scanline */ regs.h.cl = 7; /* ending scanline */ } regs.x.bx = 0; (void) int86(VIDEO_BIOS, ®s, ®s); } static void get_cursinfo(uchar *start, uchar *end, uchar *flg) { union REGS regs; regs.x.dx = 0; regs.h.ah = GETCURPOS; /* get cursor position */ regs.x.cx = 0; regs.x.bx = 0; (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Cursor Position */ if (regs.h.ch != 0x3f) { *start = regs.h.ch; *end = regs.h.cl; } else { *start = 6; *end = 7; } *flg = 1; } #endif /* SCREEN_BIOS && !PC9800 */ void txt_gotoxy(int x, int y) { #ifdef SCREEN_BIOS union REGS regs; #ifdef PC9800 regs.h.dh = (char) y; /* row */ regs.h.dl = (char) x; /* column */ regs.h.ah = SETCURPOS; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); /* Set Cursor Position */ #else regs.h.ah = SETCURPOS; regs.h.bh = 0; /* display page */ regs.h.dh = (char) y; /* row */ regs.h.dl = (char) x; /* column */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Set Cursor Position */ #endif #endif #if defined(SCREEN_DJGPPFAST) ScreenSetCursor(y, x); #endif /* The above, too, goes back all the way to the original PC. If * we ever get so fancy as to swap display pages (i doubt it), * then we'll need to set BH appropriately. This function * returns nothing. -3. */ } /* * This marks the end of the cursor manipulation/information routines. * ------------------------------------------------------------------- */ #ifdef MONO_CHECK int txt_monoadapt_check(void) { union REGS regs; regs.h.al = 0; regs.h.ah = GETMODE; /* get video mode */ (void) int86(VIDEO_BIOS, ®s, ®s); return (regs.h.al == 7) ? 1 : 0; /* 7 means monochrome mode */ } #endif /* MONO_CHECK */ #endif /* NO_TERMS */ /* vidtxt.c */