In previous versions of NetHack, setting -DUSE_TILES enabled the tile
support, while setting -DSUPPRESS_GRAPHICS produced a NetHack that
would write its TTY output to standard output, and rely on ANSI.SYS or
similar to do screen control. (USE_TILES is now TILES_IN_GLYPHMAP.)
This change ensures that the current NetHack can be built the same
ways.
One twist is that previous NetHacks would drop all support for graphical
modes when tiles were not supported. Thus sys/msdos/vid{vga,vesa}.c have
very disordered use of TILES_IN_GLYPHMAP. There was no need to check
this. But now, the graphical modes also support Unicode. A non-tiled
build should have the graphical modes, with only the text functions
present, provided that ENHANCED_SYMBOLS is defined.
Some unused and locally used symbols were cleaned up along the way.
523 lines
14 KiB
C
523 lines
14 KiB
C
/* NetHack 5.0 vidtxt.c $NHDT-Date: 1596498278 2020/08/03 23:44:38 $ $NHDT-Branch: NetHack-5.0 $:$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 <dos.h>
|
|
|
|
#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 <pc.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
void txt_gotoxy(int, int);
|
|
|
|
#if defined(SCREEN_BIOS) && !defined(PC9800)
|
|
static 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.
|
|
*/
|
|
static 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 */
|