diff options
Diffstat (limited to 'src/main-ibm.c')
-rw-r--r-- | src/main-ibm.c | 1594 |
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, ®s); +} + +#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, ®s); /* 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, ®s); /* 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, ®s); /* 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 */ |