523 lines
14 KiB
C
523 lines
14 KiB
C
/* 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 <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)
|
|
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 */
|