summaryrefslogtreecommitdiff
path: root/src/main-ibm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main-ibm.c')
-rw-r--r--src/main-ibm.c1594
1 files changed, 1594 insertions, 0 deletions
diff --git a/src/main-ibm.c b/src/main-ibm.c
new file mode 100644
index 00000000..6201649c
--- /dev/null
+++ b/src/main-ibm.c
@@ -0,0 +1,1594 @@
+/* File: main-ibm.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, and others
+ *
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.
+ */
+
+/* Purpose: Visual Display Support for "term.c", for the IBM */
+
+/*
+ * Original code by "Billy Tanksley (wtanksle@ucsd.edu)"
+ * Use "Makefile.ibm" to compile Angband using this file.
+ *
+ * Support for DJGPP v2 by "Scott Egashira (egashira@u.washington.edu)"
+ *
+ * Extensive modifications by "Ben Harrison (benh@phial.com)",
+ * including "collation" of the Watcom C/C++ and DOS-286 patches.
+ *
+ * Watcom C/C++ changes by "David Boeren (akemi@netcom.com)"
+ * Use "Makefile.wat" to compile this file with Watcom C/C++, and
+ * be sure to define "USE_IBM" and "USE_WAT".
+ *
+ * DOS-286 (conio.h) changes by (Roland Jay Roberts (jay@map.com)
+ * Use "Makefile.286" (not ready) to compile this file for DOS-286,
+ * and be sure to define "USE_IBM", "USE_WAT", and "USE_286". Also,
+ * depending on your compiler, you may need to define "USE_CONIO".
+ *
+ * True color palette support by "Mike Marcelais (michmarc@microsoft.com)",
+ * with interface to the "color_table" array by Ben Harrison.
+ *
+ * Both "shift" keys are treated as "identical", and all the modifier keys
+ * (control, shift, alt) are ignored when used with "normal" keys, unless
+ * they modify the underlying "ascii" value of the key. You must use the
+ * new "user pref files" to be able to interact with the keypad and such.
+ *
+ * The "lib/user/pref-ibm.prf" file contains macro definitions and possible
+ * alternative color set definitions. The "lib/user/font-ibm.prf" contains
+ * attr/char mappings for walls and floors and such.
+ *
+ * Note the "Term_user_ibm()" function hook, which could allow the user
+ * to interact with the "main-ibm.c" visual system. Currently this hook
+ * is unused, but, for example, it could allow the user to toggle "sound"
+ * or "graphics" modes, or to select the number of screen rows, with the
+ * extra screen rows being used for the mirror window.
+ */
+
+
+#include "angband.h"
+
+
+#ifdef USE_IBM
+
+
+/*
+ * Use a "virtual" screen to "buffer" screen writes.
+ */
+#define USE_VIRTUAL
+
+#ifdef USE_DOSSOCK
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+#include <bios.h>
+#include <dos.h>
+#include <dir.h>
+
+#ifdef USE_WAT
+
+# include <conio.h>
+
+# ifdef USE_CONIO
+# else /* USE_CONIO */
+
+# include <graph.h>
+
+# define bioskey(C) _bios_keybrd(C)
+
+# endif /* USE_CONIO */
+
+# ifndef USE_286
+# define int86(a, b, c) int386(a, b, c)
+# endif
+
+# define inportb(x) inp(x)
+# define outportb(x, y) outp(x, y)
+
+#else /* USE_WAT */
+
+# if __DJGPP__ > 1
+
+# include <pc.h>
+# include <osfcn.h>
+
+# else /* __DJGPP__ > 1 */
+# ifdef __DJGPP__
+# error "Upgrade to version 2.0 of DJGPP"
+# endif /* __DJGPP__ */
+# endif /* __DJGPP__ > 1 */
+
+#endif /* USE_WAT */
+
+
+#ifdef USE_CONIO
+
+# include <conio.h>
+
+/*
+ * Hack -- write directly to video card
+ */
+extern int directvideo = 1;
+
+/*
+ * Hack -- no virtual screen
+ */
+# undef USE_VIRTUAL
+
+#endif /* USE_CONIO */
+
+
+/*
+ * Keypress input modifier flags (hard-coded by DOS)
+ */
+#define K_RSHIFT 0 /* Right shift key down */
+#define K_LSHIFT 1 /* Left shift key down */
+#define K_CTRL 2 /* Ctrl key down */
+#define K_ALT 3 /* Alt key down */
+#define K_SCROLL 4 /* Scroll lock on */
+#define K_NUM 5 /* Num lock on */
+#define K_CAPS 6 /* Caps lock on */
+#define K_INSERT 7 /* Insert on */
+
+
+/*
+ * Foreground color bits (hard-coded by DOS)
+ */
+#define VID_BLACK 0x00
+#define VID_BLUE 0x01
+#define VID_GREEN 0x02
+#define VID_CYAN 0x03
+#define VID_RED 0x04
+#define VID_MAGENTA 0x05
+#define VID_YELLOW 0x06
+#define VID_WHITE 0x07
+
+/*
+ * Bright text (hard-coded by DOS)
+ */
+#define VID_BRIGHT 0x08
+
+/*
+ * Background color bits (hard-coded by DOS)
+ */
+#define VUD_BLACK 0x00
+#define VUD_BLUE 0x10
+#define VUD_GREEN 0x20
+#define VUD_CYAN 0x30
+#define VUD_RED 0x40
+#define VUD_MAGENTA 0x50
+#define VUD_YELLOW 0x60
+#define VUD_WHITE 0x70
+
+/*
+ * Blinking text (hard-coded by DOS)
+ */
+#define VUD_BRIGHT 0x80
+
+
+/*
+ * Screen Size
+ */
+static int rows = 25;
+static int cols = 80;
+
+
+/*
+ * Physical Screen
+ */
+#ifdef USE_286
+# define PhysicalScreen ((byte *)MK_FP(0xB800, 0x0000))
+#else
+# define PhysicalScreen ((byte *)(0xB800 << 4))
+#endif
+
+
+#ifdef USE_VIRTUAL
+
+/*
+ * Virtual Screen Contents
+ */
+static byte *VirtualScreen;
+
+#else
+
+/*
+* Physical screen access
+*/
+#define VirtualScreen PhysicalScreen
+
+#endif
+
+
+/*
+ * Hack -- the cursor "visibility"
+ */
+static int saved_cur_v;
+static int saved_cur_high;
+static int saved_cur_low;
+
+
+#ifdef USE_CONIO
+#else /* USE_CONIO */
+
+/*
+* This array is used for "wiping" the screen
+*/
+static byte wiper[160];
+
+#endif /* USE_CONIO */
+
+
+/*
+ * The main screen (currently the only screen)
+ */
+static term term_screen_body;
+
+
+/*
+ * Choose between the "complex" and "simple" color methods
+ */
+static byte use_color_complex = FALSE;
+
+
+/*
+ * The "complex" color set
+ */
+static long ibm_color_complex[16];
+
+
+/*
+ * The "simple" color set
+ *
+ * This table is used by the "color" code to instantiate the "approximate"
+ * Angband colors using the only colors available on crappy monitors.
+ *
+ * The entries below are taken from the "color bits" defined above.
+ *
+ * Note that values from 16 to 255 are extremely ugly.
+ *
+ * The values below came from various sources, if you do not like them,
+ * get a better monitor, or edit "pref-ibm.prf" to use different codes.
+ *
+ * Note that many of the choices below suck, but so do crappy monitors.
+ */
+static byte ibm_color_simple[16] =
+{
+ VID_BLACK, /* Dark */
+ VID_WHITE, /* White */
+ VID_CYAN, /* Slate XXX */
+ VID_RED | VID_BRIGHT, /* Orange XXX */
+ VID_RED, /* Red */
+ VID_GREEN, /* Green */
+ VID_BLUE, /* Blue */
+ VID_YELLOW, /* Umber XXX */
+ VID_BLACK | VID_BRIGHT, /* Light Dark */
+ VID_CYAN | VID_BRIGHT, /* Light Slate XXX */
+ VID_MAGENTA, /* Violet */
+ VID_YELLOW | VID_BRIGHT, /* Yellow */
+ VID_MAGENTA | VID_BRIGHT, /* Light Red XXX */
+ VID_GREEN | VID_BRIGHT, /* Light Green */
+ VID_BLUE | VID_BRIGHT, /* Light Blue */
+ VID_YELLOW /* Light Umber XXX */
+};
+
+
+
+/*
+ * Activate the "ibm_color_complex" palette information.
+ *
+ * Code by Mike Marcelais, with help from "The programmer's guide
+ * to the EGA and VGA video cards" [Farraro].
+ *
+ * On VGA cards, colors go through a double-indirection when looking
+ * up the `real' color when in 16 color mode. The color value in the
+ * attribute is looked up in the EGA color registers. Then that value
+ * is looked up in the VGA color registers. Then the color is displayed.
+ * This is done for compatability. However, the EGA registers are
+ * initialized by default to 0..5, 14, 7, 38..3F and not 0..F which means
+ * that unless these are reset, the VGA setpalette function will not
+ * update the correct palette register!
+ *
+ * DJGPP's GrSetColor() does _not_ set the EGA palette list, only the
+ * VGA color list.
+ *
+ * Note that the "traditional" method, using "int86(0x10)", is very slow
+ * when called in protected mode, so we use a faster method using video
+ * ports instead.
+ *
+ * On Watcom machines, we could simply use the special "_remapallpalette()"
+ * function, which not only sets both palette lists (see below) but also
+ * checks for legality of the monitor mode, but, if we are doing bitmapped
+ * graphics, that function forgets to set the EGA registers for some reason.
+ */
+static void activate_color_complex(void)
+{
+ int i;
+ printf("%c%c%c%c", 8, 8, 8, 8);
+
+#if 1
+
+ /* Edit the EGA palette */
+ inportb(0x3da);
+
+ /* Edit the colors */
+ for (i = 0; i < 16; i++)
+ {
+ /* Set color "i" */
+ outportb(0x3c0, i);
+
+ /* To value "i" */
+ outportb(0x3c0, i);
+ }
+
+ /* Use that EGA palette */
+ outportb(0x3c0, 0x20);
+
+ /* Edit VGA palette, starting at color zero */
+ outportb(0x3c8, 0);
+
+ /* Send the colors */
+ for (i = 0; i < 16; i++)
+ {
+ /* Send the red, green, blue components */
+ outportb(0x3c9, ((ibm_color_complex[i]) & 0xFF));
+ outportb(0x3c9, ((ibm_color_complex[i] >> 8) & 0xFF));
+ outportb(0x3c9, ((ibm_color_complex[i] >> 16) & 0xFF));
+ }
+
+#else /* 1 */
+
+ /* Set the colors */
+ for (i = 0; i < 16; i++)
+ {
+ union REGS r;
+
+ /* Set EGA color */
+ r.h.ah = 0x10;
+ r.h.al = 0x00;
+
+ /* Set color "i" */
+ r.h.bl = i;
+
+ /* To value "i" */
+ r.h.bh = i;
+
+ /* Do it */
+ int86(0x10, &r, &r);
+
+ /* Set VGA color */
+ r.h.ah = 0x10;
+ r.h.al = 0x10;
+
+ /* Set color "i" */
+ r.h.bh = 0x00;
+ r.h.bl = i;
+
+ /* Use this "green" value */
+ r.h.ch = ((ibm_color_complex[i] >> 8) & 0xFF);
+
+ /* Use this "blue" value */
+ r.h.cl = ((ibm_color_complex[i] >> 16) & 0xFF);
+
+ /* Use this "red" value */
+ r.h.dh = ((ibm_color_complex[i]) & 0xFF);
+
+ /* Do it */
+ int86(0x10, &r, &r);
+ }
+
+#endif /* 1 */
+
+}
+
+
+#ifdef SUPPORT_GAMMA
+
+/*
+ * When set to TRUE, indicates that we can use gamma_table
+ */
+static bool gamma_table_ready = FALSE;
+
+
+/*
+ * Build gamma correction table if requested and applicable
+ */
+static void setup_gamma_table(void)
+{
+ static u16b old_gamma_val = 0;
+
+ /* (Re)build the table only when gamma value changes */
+ if (gamma_val == old_gamma_val) return;
+
+ /* Temporarily inactivate the table */
+ gamma_table_ready = FALSE;
+
+ /* Validate gamma_val */
+ if ((gamma_val <= 0) || (gamma_val >= 256))
+ {
+ /* Reset */
+ old_gamma_val = gamma_val = 0;
+
+ /* Leave it inactive */
+ return;
+ }
+
+ /* (Re)build the table */
+ build_gamma_table(gamma_val);
+
+ /* Remember gamma_val */
+ old_gamma_val = gamma_val;
+
+ /* Activate the table */
+ gamma_table_ready = TRUE;
+}
+
+#endif /* SUPPORT_GAMMA */
+
+
+/*
+ * Note the use of "(x >> 2)" to convert an 8 bit value to a 6 bit value
+ * without losing much precision.
+ */
+static int Term_xtra_ibm_react(void)
+{
+ int i;
+
+ /* Complex method */
+ if (use_color_complex)
+ {
+ long rv, gv, bv, code;
+
+ bool change = FALSE;
+
+#ifdef SUPPORT_GAMMA
+
+ /* Build gamma_table */
+ setup_gamma_table();
+
+#endif /* SUPPORT_GAMMA */
+
+ /* Save the default colors */
+ for (i = 0; i < 16; i++)
+ {
+ /* Extract desired values */
+ rv = angband_color_table[i][1];
+ gv = angband_color_table[i][2];
+ bv = angband_color_table[i][3];
+
+#ifdef SUPPORT_GAMMA
+
+ /* Hack - Gamma correction */
+ if (gamma_table_ready)
+ {
+ rv = gamma_table[rv];
+ gv = gamma_table[gv];
+ bv = gamma_table[bv];
+ }
+
+#endif /* SUPPORT_GAMMA */
+
+ /* 8 bit to 6 bit conversion */
+ rv = rv >> 2;
+ gv = gv >> 2;
+ bv = bv >> 2;
+
+ /* Extract a full color code */
+ code = ((rv) | (gv << 8) | (bv << 16));
+
+ /* Activate changes */
+ if (ibm_color_complex[i] != code)
+ {
+ /* Note the change */
+ change = TRUE;
+
+ /* Apply the desired color */
+ ibm_color_complex[i] = code;
+ }
+ }
+
+ /* Activate the palette if needed */
+ if (change) activate_color_complex();
+ }
+
+ /* Simple method */
+ else
+ {
+ /* Save the default colors */
+ for (i = 0; i < 16; i++)
+ {
+ /* Simply accept the desired colors */
+ ibm_color_simple[i] = angband_color_table[i][0];
+ }
+ }
+
+ /* Success */
+ return (0);
+}
+
+
+
+/*
+ * Hack -- set the cursor "visibility"
+ */
+static void curs_set(int v)
+{
+ /* If needed */
+ if (saved_cur_v != v)
+ {
+ union REGS r;
+
+ /* Set cursor */
+ r.h.ah = 1;
+
+ /* Visible */
+ if (v)
+ {
+ /* Use the saved values */
+ r.h.ch = saved_cur_high;
+ r.h.cl = saved_cur_low;
+ }
+
+ /* Invisible */
+ else
+ {
+ /* Make it invisible */
+ r.h.ch = 0x20;
+ r.h.cl = 0x00;
+ }
+
+ /* Make the call */
+ int86(0x10, &r, &r);
+
+ /* Save the cursor state */
+ saved_cur_v = v;
+ }
+}
+
+
+
+/*
+ * Process an event (check for a keypress)
+ *
+ * The keypress processing code is often the most system dependant part
+ * of Angband, since sometimes even the choice of compiler is important.
+ *
+ * For the IBM, we divide all keypresses into two categories, first, the
+ * "normal" keys, including all keys required to play Angband, and second,
+ * the "special" keys, such as keypad keys, function keys, and various keys
+ * used in combination with various modifier keys.
+ *
+ * To simplify this file, we use Angband's "macro processing" ability, in
+ * combination with a specialized "pref-ibm.prf" file, to handle most of the
+ * "special" keys, instead of attempting to fully analyze them here. This
+ * file only has to determine when a "special" key has been pressed, and
+ * translate it into a simple string which signals the use of a "special"
+ * key, the set of modifiers used, if any, and the hardware scan code of
+ * the actual key which was pressed. To simplify life for the user, we
+ * treat both "shift" keys as identical modifiers.
+ *
+ * The final encoding is "^_MMMxSS\r", where "MMM" encodes the modifiers
+ * ("C" for control, "S" for shift, "A" for alt, or any ordered combination),
+ * and "SS" encodes the keypress (as the two "digit" hexadecimal encoding of
+ * the scan code of the key that was pressed), and the "^_" and "x" and "\r"
+ * delimit the encoding for recognition by the macro processing code.
+ *
+ * Some important facts about scan codes follow. All "normal" keys use
+ * scan codes from 1-58. The "function" keys use 59-68 (and 133-134).
+ * The "keypad" keys use 69-83. Escape uses 1. Enter uses 28. Control
+ * uses 29. Left Shift uses 42. Right Shift uses 54. PrtScrn uses 55.
+ * Alt uses 56. Space uses 57. CapsLock uses 58. NumLock uses 69.
+ * ScrollLock uses 70. The "keypad" keys which use scan codes 71-83
+ * are ordered KP7,KP8,KP9,KP-,KP4,KP5,KP6,KP+,KP1,KP2,KP3,INS,DEL.
+ *
+ * Using "bioskey(0x10)" instead of "bioskey(0)" apparently provides more
+ * information, including better access to the keypad keys in combination
+ * with various modifiers, but only works on "PC's after 6/1/86", and there
+ * is no way to determine if the function is provided on a machine. I have
+ * been told that without it you cannot detect, for example, control-left.
+ * The basic scan code + ascii value pairs returned by the keypad follow,
+ * with values in parentheses only available to "bioskey(0x10)".
+ *
+ * / * - + 1 2 3 4
+ * Norm: 352f 372a 4a2d 4e2b 4f00 5000 5100 4b00
+ * Shft: 352f 372a 4a2d 4e2b 4f31 5032 5133 4b34
+ * Ctrl: (9500) (9600) (8e00) (9000) 7500 (9100) 7600 7300
+ *
+ * 5 6 7 8 9 0 . Enter
+ * Norm: (4c00) 4d00 4700 4800 4900 5200 5300 (e00d)
+ * Shft: 4c35 4d36 4737 4838 4939 5230 532e (e00d)
+ * Ctrl: (8f00) 7400 7700 (8d00) 8400 (9200) (9300) (e00a)
+ *
+ * See "pref-ibm.prf" for the "standard" macros for various keys.
+ *
+ * Certain "bizarre" keypad keys (such as "enter") return a "scan code"
+ * of "0xE0", and a "usable" ascii value. These keys should be treated
+ * like the normal keys, see below. XXX XXX XXX Note that these "special"
+ * keys could be prefixed with an optional "ctrl-^" which would allow them
+ * to be used in macros without hurting their use in normal situations.
+ */
+static errr Term_xtra_ibm_event(int v)
+{
+ int i, k, s;
+
+ bool mc = FALSE;
+ bool ms = FALSE;
+ bool ma = FALSE;
+
+
+ /* Hack -- Check for a keypress */
+ if (!v && !bioskey(1)) return (1);
+
+ /* Wait for a keypress */
+ k = bioskey(0x10);
+
+ /* Access the "modifiers" */
+ i = bioskey(2);
+
+ /* Extract the "scan code" */
+ s = ((k >> 8) & 0xFF);
+
+ /* Extract the "ascii value" */
+ k = (k & 0xFF);
+
+ /* Process "normal" keys */
+ if ((s <= 58) || (s == 0xE0))
+ {
+ /* Enqueue it */
+ if (k) Term_keypress(k);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Extract the modifier flags */
+ if (i & (1 << K_CTRL)) mc = TRUE;
+ if (i & (1 << K_LSHIFT)) ms = TRUE;
+ if (i & (1 << K_RSHIFT)) ms = TRUE;
+ if (i & (1 << K_ALT)) ma = TRUE;
+
+
+ /* Begin a "macro trigger" */
+ Term_keypress(31);
+
+ /* Hack -- Send the modifiers */
+ if (mc) Term_keypress('C');
+ if (ms) Term_keypress('S');
+ if (ma) Term_keypress('A');
+
+ /* Introduce the hexidecimal scan code */
+ Term_keypress('x');
+
+ /* Encode the hexidecimal scan code */
+ Term_keypress(hexsym[s / 16]);
+ Term_keypress(hexsym[s % 16]);
+
+ /* End the "macro trigger" */
+ Term_keypress(13);
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Handle a "special request"
+ *
+ * The given parameters are "valid".
+ */
+static errr Term_xtra_ibm(int n, int v)
+{
+ int i;
+
+ /* Analyze the request */
+ switch (n)
+ {
+ /* Make a "bell" noise */
+ case TERM_XTRA_NOISE:
+ {
+ /* Make a bell noise */
+ (void)write(1, "\007", 1);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Set the cursor shape */
+ case TERM_XTRA_SHAPE:
+ {
+ /* Set cursor shape */
+ curs_set(v);
+
+ /* Success */
+ return (0);
+ }
+
+ /* Flush one line of output */
+ case TERM_XTRA_FROSH:
+ {
+
+#ifdef USE_VIRTUAL
+
+# ifdef USE_WAT
+
+ /* Copy the virtual screen to the physical screen */
+ memcpy(PhysicalScreen + (v*160), VirtualScreen + (v*160), 160);
+
+# else /* USE_WAT */
+
+ /* Apply the virtual screen to the physical screen */
+ ScreenUpdateLine(VirtualScreen + ((v*cols) << 1), v);
+
+# endif /* USE_WAT */
+
+#endif /* USE_VIRTUAL */
+
+ /* Success */
+ return (0);
+ }
+
+ /* Clear the screen */
+ case TERM_XTRA_CLEAR:
+ {
+
+#ifdef USE_CONIO
+
+ /* Clear the screen */
+ clrscr();
+
+#else /* USE_CONIO */
+
+ /* Clear each line (virtual or physical) */
+ for (i = 0; i < rows; i++)
+ {
+ /* Clear the line */
+ memcpy((VirtualScreen + ((i*cols) << 1)), wiper, (cols << 1));
+ }
+
+# ifdef USE_VIRTUAL
+
+# ifdef USE_WAT
+
+ /* Copy the virtual screen to the physical screen */
+ memcpy(PhysicalScreen, VirtualScreen, 25*80*2);
+
+# else /* USE_WAT */
+
+ /* Erase the physical screen */
+ ScreenClear();
+
+# endif /* USE_WAT */
+
+# endif /* USE_VIRTUAL */
+
+#endif /* USE_CONIO */
+
+ /* Success */
+ return (0);
+ }
+
+ /* Process events */
+ case TERM_XTRA_EVENT:
+ {
+ irc_poll();
+
+ /* Process one event */
+ return (Term_xtra_ibm_event(v));
+ }
+
+ /* Flush events */
+ case TERM_XTRA_FLUSH:
+ {
+ /* Strip events */
+ while (!Term_xtra_ibm_event(FALSE)) /* loop */;
+
+ /* Success */
+ return (0);
+ }
+
+ /* React to global changes */
+ case TERM_XTRA_REACT:
+ {
+ /* React to "color_table" changes */
+ return (Term_xtra_ibm_react());
+ }
+
+ /* Delay for some milliseconds */
+ case TERM_XTRA_DELAY:
+ {
+ /* Delay if needed */
+ if (v > 0) delay(v);
+
+ /* Success */
+ return (0);
+ }
+
+ /*
+ * Scans for subdirectories in a directory "scansubdir_dir"
+ * and place teh result in "scansubdir_result/scansubdir_max"
+ */
+ case TERM_XTRA_SCANSUBDIR:
+ {
+ struct ffblk f;
+ int done;
+
+ done = findfirst(format("%s\\*", scansubdir_dir), &f, FA_DIREC);
+
+ scansubdir_max = 0;
+ while ((!done) && (scansubdir_max < 255))
+ {
+ if ((f.ff_attrib & FA_DIREC) && (strcmp(f.ff_name, ".")) && (strcmp(f.ff_name, "..")))
+ {
+ string_free(scansubdir_result[scansubdir_max]);
+ scansubdir_result[scansubdir_max] = string_make(f.ff_name);
+ scansubdir_max++;
+ }
+
+ done = findnext(&f);
+ }
+
+ return 0;
+ }
+ }
+
+ /* Unknown request */
+ return (1);
+}
+
+
+
+/*
+ * Move the cursor
+ *
+ * The given parameters are "valid".
+ */
+static errr Term_curs_ibm(int x, int y)
+{
+
+#ifdef USE_WAT
+
+# ifdef USE_CONIO
+
+ /* Place the cursor */
+ gotoxy(x + 1, y + 1);
+
+# else /* USE_CONIO */
+
+ union REGS r;
+
+ r.h.ah = 2;
+ r.h.bh = 0;
+ r.h.dl = x;
+ r.h.dh = y;
+
+ /* Place the cursor */
+ int86(0x10, &r, &r);
+
+# endif /* USE_CONIO */
+
+#else /* USE_WAT */
+
+ /* Move the cursor */
+ ScreenSetCursor(y, x);
+
+#endif /* USE_WAT */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Erase a block of the screen
+ *
+ * The given parameters are "valid".
+ */
+static errr Term_wipe_ibm(int x, int y, int n)
+{
+
+#ifdef USE_CONIO
+
+ /* Wipe the region */
+ window(x + 1, y + 1, x + n, y + 1);
+ clrscr();
+ window(1, 1, cols, rows);
+
+#else /* USE_CONIO */
+
+ /* Wipe part of the virtual (or physical) screen */
+ memcpy(VirtualScreen + ((cols*y + x) << 1), wiper, n << 1);
+
+#endif /* USE_CONIO */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Place some text on the screen using an attribute
+ *
+ * The given parameters are "valid". Be careful with "a".
+ *
+ * The string "cp" has length "n" and is NOT null-terminated.
+ */
+static errr Term_text_ibm(int x, int y, int n, byte a, const char *cp)
+{
+ register int i;
+ register byte attr;
+ register byte *dest;
+
+
+ /* Handle "complex" color */
+ if (use_color_complex)
+ {
+ /* Extract a color index */
+ attr = (a & 0x0F);
+ }
+
+ /* Handle "simple" color */
+ else
+ {
+ /* Extract a color value */
+ attr = ibm_color_simple[a & 0x0F];
+ }
+
+#ifdef USE_CONIO
+
+ /* Place the cursor */
+ gotoxy(x + 1, y + 1);
+
+ /* Set the attribute */
+ textattr(attr);
+
+ /* Dump the text */
+ for (i = 0; i < n; i++) putch(cp[i]);
+
+#else /* USE_CONIO */
+
+ /* Access the virtual (or physical) screen */
+ dest = VirtualScreen + (((cols * y) + x) << 1);
+
+ /* Save the data */
+ for (i = 0; i < n; i++)
+ {
+ /* Apply */
+ *dest++ = cp[i];
+ *dest++ = attr;
+ }
+
+#endif /* USE_CONIO */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Place some attr/char pairs on the screen
+ *
+ * The given parameters are "valid".
+ */
+#ifdef USE_TRANSPARENCY
+static errr Term_pict_ibm(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp)
+#else /* USE_TRANSPARENCY */
+static errr Term_pict_ibm(int x, int y, int n, const byte *ap, const char *cp)
+#endif /* USE_TRANSPARENCY */
+{
+ register int i;
+ register byte attr;
+ register byte *dest;
+
+
+#ifdef USE_CONIO
+
+ /* Place the cursor */
+ gotoxy(x + 1, y + 1);
+
+ /* Dump the text */
+ for (i = 0; i < n; i++)
+ {
+ /* Handle "complex" color */
+ if (use_color_complex)
+ {
+ /* Extract a color index */
+ attr = (ap[i] & 0x0F);
+ }
+
+ /* Handle "simple" color */
+ else
+ {
+ /* Extract a color value */
+ attr = ibm_color_simple[ap[i] & 0x0F];
+ }
+
+ /* Set the attribute */
+ textattr(attr);
+
+ /* Dump the char */
+ putch(cp[i]);
+ }
+
+#else /* USE_CONIO */
+
+ /* Access the virtual (or physical) screen */
+ dest = VirtualScreen + (((cols * y) + x) << 1);
+
+ /* Save the data */
+ for (i = 0; i < n; i++)
+ {
+ /* Handle "complex" color */
+ if (use_color_complex)
+ {
+ /* Extract a color index */
+ attr = (ap[i] & 0x0F);
+ }
+
+ /* Handle "simple" color */
+ else
+ {
+ /* Extract a color value */
+ attr = ibm_color_simple[ap[i] & 0x0F];
+ }
+
+ /* Apply */
+ *dest++ = cp[i];
+ *dest++ = attr;
+ }
+
+#endif /* USE_CONIO */
+
+ /* Success */
+ return (0);
+}
+
+
+/*
+ * Init a Term
+ */
+static void Term_init_ibm(term *t)
+{
+ /* XXX Nothing */
+}
+
+
+/*
+ * Nuke a Term
+ */
+static void Term_nuke_ibm(term *t)
+{
+
+#ifdef USE_WAT
+
+ /* Nothing */
+
+#else /* USE_WAT */
+
+ union REGS r;
+
+#endif /* USE_WAT */
+
+ /* Move the cursor to the bottom of the screen */
+ Term_curs_ibm(0, rows - 1);
+
+#ifdef USE_WAT
+
+ /* Restore the original video mode */
+ _setvideomode(_DEFAULTMODE);
+
+#else /* USE_WAT */
+
+ /* Restore the original video mode */
+ r.h.ah = 0x00;
+ r.h.al = 0x03;
+ int86(0x10, &r, &r);
+
+#endif /* USE_WAT */
+
+ /* Make the cursor visible */
+ curs_set(1);
+}
+
+
+
+#ifdef USE_GRAPHICS
+
+#ifdef USE_286
+
+/*
+ * In 286 mode we don't need to worry about translating from a 32bit
+ * pointer to a 16 bit pointer so we just call the interrupt function
+ *
+ * Note the use of "intr()" instead of "int86()" so we can pass
+ * segment registers.
+ */
+void enable_graphic_font(void *font)
+{
+ union REGPACK regs =
+ {0};
+
+ regs.h.ah = 0x11; /* Text font function */
+ regs.h.bh = 0x10; /* Size of a character -- 16 bytes */
+ regs.h.cl = 0xFF; /* Last character in font */
+ regs.x.es = FP_SEG(font); /* Pointer to font */
+ regs.x.bp = FP_OFF(font);
+ intr(0x10, &regs);
+}
+
+#else /* USE_286 */
+
+#ifdef USE_WAT
+
+/*
+* This structure is used by the DMPI function to hold registers when
+* doing a real mode interrupt call. (Stolen from the DJGPP <dpmi.h>
+ * header file).
+*/
+
+typedef union
+{
+ struct
+ {
+ unsigned long edi;
+ unsigned long esi;
+ unsigned long ebp;
+ unsigned long res;
+ unsigned long ebx;
+ unsigned long edx;
+ unsigned long ecx;
+ unsigned long eax;
+ }
+ d;
+ struct
+ {
+ unsigned short di, di_hi;
+ unsigned short si, si_hi;
+ unsigned short bp, bp_hi;
+ unsigned short res, res_hi;
+ unsigned short bx, bx_hi;
+ unsigned short dx, dx_hi;
+ unsigned short cx, cx_hi;
+ unsigned short ax, ax_hi;
+ unsigned short flags;
+ unsigned short es;
+ unsigned short ds;
+ unsigned short fs;
+ unsigned short gs;
+ unsigned short ip;
+ unsigned short cs;
+ unsigned short sp;
+ unsigned short ss;
+ }
+ x;
+ struct
+ {
+ unsigned char edi[4];
+ unsigned char esi[4];
+ unsigned char ebp[4];
+ unsigned char res[4];
+ unsigned char bl, bh, ebx_b2, ebx_b3;
+ unsigned char dl, dh, edx_b2, edx_b3;
+ unsigned char cl, ch, ecx_b2, ecx_b3;
+ unsigned char al, ah, eax_b2, eax_b3;
+ }
+ h;
+} __dpmi_regs;
+
+unsigned __dpmi_allocate_dos_memory(int size, unsigned *selector)
+{
+ union REGPACK regs =
+ {0};
+
+ regs.w.ax = 0x100; /* DPMI function -- allocate low memory */
+ regs.w.bx = size; /* Number of Paragraphs to allocate */
+ intr(0x31, &regs); /* DPMI interface */
+
+ *selector = regs.w.dx;
+ return (regs.w.ax);
+}
+
+void __dpmi_free_dos_memory(unsigned sel)
+{
+ union REGPACK regs =
+ {0};
+
+ regs.w.ax = 0x101; /* DPMI function -- free low memory */
+ regs.x.edx = sel; /* PM selector for memory block */
+ intr(0x31, &regs); /* DPMI interface */
+}
+
+void __dpmi_int(int intno, __dpmi_regs *dblock)
+{
+ union REGPACK regs =
+ {0};
+
+ regs.w.ax = 0x300; /* DPMI function -- real mode interrupt */
+ regs.h.bl = intno; /* interrupt 0x10 */
+ regs.x.edi = FP_OFF(dblock); /* Pointer to dblock (offset and segment) */
+ regs.x.es = FP_SEG(dblock);
+ intr(0x31, &regs); /* DPMI interface */
+}
+
+unsigned short __dpmi_sel = 0x0000;
+#define _farsetsel(x) __dpmi_sel=(x)
+extern void _farnspokeb(unsigned long offset, unsigned char value);
+#pragma aux _farnspokeb = \
+"push fs" \
+"mov fs,__dpmi_sel" \
+"mov fs:[eax],bl" \
+"pop fs" \
+parm [eax] [bl];
+
+#else /* USE_WAT */
+
+#include <dpmi.h>
+#include <go32.h>
+#include <sys/farptr.h>
+
+#endif /* USE_WAT */
+
+
+/*
+* Since you cannot send 32bit pointers to a 16bit interrupt handler
+* and the video BIOS wants a (16bit) pointer to the font, we have
+* to allocate a block of dos memory, copy the font into it, then
+* translate a 32bit pointer into a 16bit pointer to that block.
+*
+* DPMI - Dos Protected Mode Interface provides functions that let
+* us do that.
+*/
+void enable_graphic_font(const char *font)
+{
+ __dpmi_regs dblock = {{0}};
+
+ unsigned seg, sel, i;
+
+ /*
+ * Allocate a block of memory 4096 bytes big in `low memory' so a real
+ * mode interrupt can access it. Real mode pointer is returned as seg:0
+ * Protected mode pointer is sel:0.
+ */
+ seg = __dpmi_allocate_dos_memory(256, &sel);
+
+ /* Copy the information into low memory buffer, by copying one byte at
+ * a time. According to the info in <sys/farptr.h>, the functions
+ * _farsetsel() and _farnspokeb() will optimise away completely
+ */
+ _farsetsel(sel); /* Set the selector to write to */
+ for (i = 0; i < 4096; i++)
+ {
+ _farnspokeb(i, *font++); /* Copy 1 byte into low (far) memory */
+ }
+
+ /*
+ * Now we use DPMI as a jumper to call the real mode interrupt. This
+ * is needed because loading `es' while in protected mode with a real
+ * mode pointer will cause an Protection Fault and calling the interrupt
+ * directly using the protected mode pointer will result in garbage
+ * being received by the interrupt routine
+ */
+ dblock.d.eax = 0x1100; /* BIOS function -- set font */
+ dblock.d.ebx = 0x1000; /* bh = size of a letter; bl = 0 (reserved) */
+ dblock.d.ecx = 0x00FF; /* Last character in font */
+ dblock.x.es = seg; /* Pointer to font segment */
+ dblock.d.ebp = 0x0000; /* Pointer to font offset */
+
+ __dpmi_int(0x10, &dblock);
+
+ /* We're done with the low memory, free it */
+ __dpmi_free_dos_memory(sel);
+}
+
+#endif /* USE_286 */
+
+#endif /* ALLOW_GRAPH */
+
+#ifdef USE_DOSSOCK
+void *zsock_connect(char *hos, short port)
+{
+ struct hostent *host;
+ struct sockaddr_in sin;
+ int *client;
+
+ MAKE(client, int);
+ *client = socket(AF_INET, SOCK_STREAM, 0);
+
+ host = gethostbyname(hos);
+
+ memset(&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
+ sin.sin_port = htons(port);
+
+ if (connect(*client, (struct sockaddr*)&sin, sizeof sin) == -1)
+ {
+ /* could not connect to server */
+ return NULL;
+ }
+
+ return client;
+}
+
+bool zsock_can_read(void *client)
+{
+ struct timeval t;
+ fd_set rd;
+ int *c = client;
+
+ FD_ZERO(&rd);
+ FD_SET(*c, &rd);
+ t.tv_sec = 0;
+ t.tv_usec = 0;
+ select(*c + 1, &rd, NULL, NULL, &t);
+ if (FD_ISSET(*c, &rd)) return TRUE;
+ else return (FALSE);
+}
+
+bool zsock_wait(void *client)
+{
+ struct timeval t;
+ fd_set rd;
+ int *c = client;
+
+ t.tv_sec = 30;
+ t.tv_usec = 0;
+
+ FD_ZERO(&rd);
+ FD_SET(*c, &rd);
+ select(*c + 1, &rd, NULL, NULL, &t);
+ if (FD_ISSET(*c, &rd)) return TRUE;
+ else return (FALSE);
+}
+
+void zsock_disconnect(void *client)
+{
+ close(*(int*)client);
+ FREE(client, int);
+}
+
+void zsock_send(void *sock, char *str)
+{
+ send(*(int*)sock, str, strlen(str), 0);
+}
+
+void zsock_recv(void *sock, char *str, int len)
+{
+ char c;
+ int l = 0;
+
+ while ((l < len) && zsock_can_read(sock))
+ {
+ if (!recv(*(int*)sock, &c, 1, 0))
+ {
+ irc_disconnect();
+ break;
+ }
+ if (c == '\r') continue;
+ if (c == '\n') break;
+ str[l++] = c;
+ }
+ str[l] = '\0';
+}
+#endif
+
+
+/*
+ * Initialize the IBM "visual module"
+ *
+ * Hack -- we assume that "blank space" should be "white space"
+ * (and not "black space" which might make more sense).
+ *
+ * Note the use of "((x << 2) | (x >> 4))" to "expand" a 6 bit value
+ * into an 8 bit value, without losing much precision, by using the 2
+ * most significant bits as the least significant bits in the new value.
+ */
+errr init_ibm(void)
+{
+ int i;
+ int mode;
+
+ term *t = &term_screen_body;
+
+ union REGS r;
+
+ /* Check for "Windows" */
+ if (getenv("windir"))
+ {
+ r.h.ah = 0x16; /* Windows API Call -- Set device focus */
+ r.h.al = 0x8B; /* Causes Dos boxes to become fullscreen */
+ r.h.bh = r.h.bl = 0x00; /* 0x0000 = current Dos box */
+ int86(0x2F, &r, &r); /* Call the Windows API */
+ }
+
+ /* Initialize "color_table" */
+ for (i = 0; i < 16; i++)
+ {
+ long rv, gv, bv;
+
+ /* Extract desired values */
+ rv = angband_color_table[i][1] >> 2;
+ gv = angband_color_table[i][2] >> 2;
+ bv = angband_color_table[i][3] >> 2;
+
+ /* Extract the "complex" codes */
+ ibm_color_complex[i] = ((rv) | (gv << 8) | (bv << 16));
+
+ /* Save the "simple" codes */
+ angband_color_table[i][0] = ibm_color_simple[i];
+ }
+
+#ifdef USE_WAT
+
+ /* Set the video mode */
+ if (_setvideomode(_VRES16COLOR))
+ {
+ mode = 0x13;
+ }
+
+ /* Wimpy monitor */
+ else
+ {
+ mode = 0x03;
+ }
+
+ /* Force 25 line mode */
+ _setvideomode(_TEXTC80);
+ _settextrows(25);
+
+#else /* USE_WAT */
+
+ /* Set video mode */
+ r.h.ah = 0x00;
+ r.h.al = 0x13; /* VGA only mode */
+ int86(0x10, &r, &r);
+
+ /* Get video mode */
+ r.h.ah = 0x0F;
+ int86(0x10, &r, &r);
+ mode = r.h.al;
+
+ /* Set video mode */
+ r.h.ah = 0x00;
+ r.h.al = 0x03; /* Color text mode */
+ int86(0x10, &r, &r);
+
+#endif /* USE_WAT */
+
+ /* Check video mode */
+ if (mode == 0x13)
+ {
+ /* Remember the mode */
+ use_color_complex = TRUE;
+
+ /* Instantiate the color set */
+ activate_color_complex();
+ }
+
+#ifdef USE_GRAPHICS
+
+ /* Try to activate bitmap graphics */
+ if (arg_graphics && use_color_complex)
+ {
+ FILE *f;
+
+ char buf[4096];
+
+ /* Build the filename */
+ path_build(buf, 1024, ANGBAND_DIR_XTRA, "angband.fnt");
+
+ /* Open the file */
+ f = fopen(buf, "rb");
+
+ /* Okay */
+ if (f)
+ {
+ /* Load the bitmap data */
+ if (fread(buf, 1, 4096, f) != 4096)
+ {
+ quit("Corrupt 'angband.fnt' file");
+ }
+
+ /* Close the file */
+ fclose(f);
+
+ /* Enable graphics */
+ enable_graphic_font(buf);
+
+ /* Enable colors (again) */
+ activate_color_complex();
+
+ /* Use graphics */
+ use_graphics = TRUE;
+ }
+ }
+
+#endif
+
+#ifdef USE_CONIO
+#else /* USE_CONIO */
+
+ /* Build a "wiper line" */
+ for (i = 0; i < 80; i++)
+ {
+ /* Space */
+ wiper[2*i] = ' ';
+
+ /* Black */
+ wiper[2*i + 1] = TERM_WHITE;
+ }
+
+#endif /* USE_CONIO */
+
+
+#ifdef USE_VIRTUAL
+
+ /* Make the virtual screen */
+ C_MAKE(VirtualScreen, rows * cols * 2, byte);
+
+#endif /* USE_VIRTUAL */
+
+
+ /* Erase the screen */
+ Term_xtra_ibm(TERM_XTRA_CLEAR, 0);
+
+
+ /* Place the cursor */
+ Term_curs_ibm(0, 0);
+
+
+ /* Access the "default" cursor info */
+ r.h.ah = 3;
+ r.h.bh = 0;
+
+ /* Make the call */
+ int86(0x10, &r, &r);
+
+ /* Extract the standard cursor info */
+ saved_cur_v = 1;
+ saved_cur_high = r.h.ch;
+ saved_cur_low = r.h.cl;
+
+
+ /* Initialize the term */
+ term_init(t, 80, 24, 256);
+
+#ifdef USE_CONIO
+#else /* USE_CONIO */
+
+ /* Always use "Term_pict()" */
+ t->always_pict = TRUE;
+
+#endif /* USE_CONIO */
+
+ /* Use "white space" to erase */
+ t->attr_blank = TERM_WHITE;
+ t->char_blank = ' ';
+
+ /* Prepare the init/nuke hooks */
+ t->init_hook = Term_init_ibm;
+ t->nuke_hook = Term_nuke_ibm;
+
+ /* Connect the hooks */
+ t->xtra_hook = Term_xtra_ibm;
+ t->curs_hook = Term_curs_ibm;
+ t->wipe_hook = Term_wipe_ibm;
+ t->text_hook = Term_text_ibm;
+ t->pict_hook = Term_pict_ibm;
+
+ /* Save it */
+ term_screen = t;
+
+ /* Activate it */
+ Term_activate(term_screen);
+
+ /* Success */
+ return 0;
+}
+
+
+#endif /* USE_IBM */