summaryrefslogtreecommitdiff
path: root/src/main-emx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main-emx.c')
-rw-r--r--src/main-emx.c1268
1 files changed, 1268 insertions, 0 deletions
diff --git a/src/main-emx.c b/src/main-emx.c
new file mode 100644
index 00000000..6d048e79
--- /dev/null
+++ b/src/main-emx.c
@@ -0,0 +1,1268 @@
+/* File: main-emx.c */
+
+/*
+ * Copyright (c) 1997 Ben Harrison, Ekkehard Kraemer, 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: Support for OS/2 EMX Angband */
+
+/* Author: ekraemer@pluto.camelot.de (Ekkehard Kraemer) */
+
+/* Current maintainer: silasd@psyber.com (Silas Dunsmore) */
+/* Unless somebody else wants it.... */
+
+#ifdef USE_EMX
+
+/*
+ * === Instructions for using Angband 2.7.X with OS/2 ===
+ *
+ * The patches (file "main-emx.c") to compile Angband 2.7.X under OS/2
+ * were written by ekraemer@pluto.camelot.de (Ekkehard Kraemer).
+ *
+ * TO COMPILE:
+ *
+ * - untar the archive into /angband (or /games/angband or whatever)
+ * - change directory to /angband/src
+ * - run "dmake -B -r -f makefile.emx" (not gmake or make)
+ *
+ * TO INSTALL:
+ *
+ * - change directory to /angband/src
+ * - run "dmake -B -r -f makefile.emx install" (not gmake or make)
+ * - copy your old savefile into ./lib/save and your old pref.prf into ./lib/user
+ * - start /angband/angband.exe for one single window
+ * - start /angband/startwnd.cmd for multiple windows
+ *
+ * TO REMOVE TEMPORARY FILES:
+ *
+ * - run 'dmake -B -r -f makefile.emx clean'
+ *
+ *
+ * I use EMX 0.9b, but every EMX compiler since 0.8g or so should work
+ * fine. EMX is available at ftp-os2.cdrom.com ("Hobbes"), as is dmake.
+ *
+ * dmake: ftp://ftp-os2.cdrom.com/all/program/dmake38X.zip
+ * EMX: ftp://ftp-os2.cdrom.com/2_x/unix/emx???/ (most probably)
+ *
+ * Old savefiles must be renamed to follow the new "savefile" naming
+ * conventions. Either rename the savefile to "PLAYER", or start the
+ * program with the "-uName" flag. See "main.c" for details. The
+ * savefiles are stores in "./lib/save" if you forgot the old names...
+ *
+ * Changes
+ * =======
+ *
+ * When By Version What
+ * -------------------------------------------------------------------
+ *
+ * 18.11.95 EK 2.7.8 Added window/pipe code
+ * Introduced __EMX__CLIENT__ hack
+ *
+ * 15.12.95 EK 2.7.9 Updated for 2.7.9
+ * beta Added third view
+ * Added number of line support in aclient
+ *
+ * 25.12.95 EK 2.7.9 Added 'install' target
+ * non-beta Updated installation hints
+ * Uploaded binary to export.andrew.cmu.edu
+ *
+ * 25.01.96 EK 2.7.9 Updated for 2.7.9v3
+ * v3 Removed (improved) keyboard hack
+ * Introduced pref-emx.prf
+ * Phew... Makefile.emx grows! (patches, export)
+ * Uploaded binary to export.andrew.cmu.edu
+ *
+ * 26.01.96 EK Added files.uue target
+ *
+ * 22.02.96 EK Added PM support
+ *
+ * 2.03.96 EK 2.7.9 Uploaded binaries to export.andrew.cmu.edu
+ * v4
+ *
+ * 9.03.96 EK 2.7.9 Adjustable background color (PM)
+ * v5 Added map window
+
+ * 3 Dec 97 SWD 282 Brought key-handling, macros in sync with DOS.
+ * Hacked on sub-window code -- it compiles, but
+ * doesn't link.
+ *
+ * 23 Jan 98 SWD 282 Hacked more on sub-windows. Now links, with
+ * warnings. Seems to work.
+ *
+ * 01 Nov 98 AGA 2.8.3 Adjusted for 2.8.3 sources, typos corrected
+ *
+ * 01 Nov 98 AGA Z214b Corrections for ZAngband 2.1.4 beta
+ *
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/kbdscan.h>
+#include <io.h>
+#define INCL_KBD 1
+#include <os2.h>
+#include <sys/video.h>
+
+#include "angband.h"
+
+
+/*
+ * Maximum windows
+ */
+#define MAX_TERM_DATA 8
+
+
+/*
+ * Keypress input modifier flags (copied from main-ibm.c)
+ *
+ * SWD: these could be changed to the definitions in <os2.h>, which are
+ * direct bitmasks instead of shift-counts.
+ */
+#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 */
+
+
+/*
+ * Prototypes!
+ */
+static errr Term_curs_emx(int x, int y);
+static errr Term_wipe_emx(int x, int y, int n);
+static errr Term_text_emx(int x, int y, int n, unsigned char a, cptr s);
+static void Term_init_emx(term *t);
+static void Term_nuke_emx(term *t);
+
+#ifndef EMXPM
+
+/*
+ * termPipe* is sometimes cast to term* and vice versa,
+ * so "term t;" must be the first line
+ */
+
+typedef struct
+{
+ term t;
+ FILE *out; /* used by the ..._pipe_emx stuff */
+}
+termPipe;
+
+/*
+ * Communication between server and client
+ */
+
+enum
+{
+ PIP_INIT,
+ PIP_NUKE,
+ PIP_XTRA,
+ PIP_CURS,
+ PIP_WIPE,
+ PIP_TEXT,
+};
+
+
+/*
+ * Current cursor "size"
+ */
+static int curs_start = 0;
+static int curs_end = 0;
+
+/*
+ * Angband color conversion table
+ *
+ * Note that "Light Green"/"Yellow"/"Red" are used for
+ * "good"/"fair"/"awful" stats and conditions.
+ *
+ * But "brown"/"light brown"/"orange" are really only used
+ * for "objects" (such as doors and spellbooks), and these
+ * values can in fact be re-defined.
+ *
+ * Future versions of Angband will probably allow the
+ * "use" of more that 16 colors, so "extra" entries can be
+ * made at the end of this table in preparation.
+ */
+static int colors[16] =
+{
+ F_BLACK, /* Black */
+ F_WHITE | INTENSITY, /* White */
+ F_WHITE, /* XXX Gray */
+ F_RED | INTENSITY, /* Orange */
+ F_RED, /* Red */
+ F_GREEN, /* Green */
+ F_BLUE, /* Blue */
+ F_BROWN, /* Brown */
+ F_BLACK | INTENSITY, /* Dark-grey */
+ F_WHITE, /* XXX Light gray */
+ F_MAGENTA, /* Purple */
+ F_YELLOW | INTENSITY, /* Yellow */
+ F_RED | INTENSITY, /* Light Red */
+ F_GREEN | INTENSITY, /* Light Green */
+ F_BLUE | INTENSITY, /* Light Blue */
+ F_BROWN | INTENSITY /* Light brown */
+};
+
+/*
+ * Display a cursor, on top of a given attr/char
+ */
+static errr Term_curs_emx(int x, int y)
+{
+ v_gotoxy(x, y);
+ v_ctype(curs_start, curs_end);
+
+ return (0);
+}
+
+/*
+ * Erase a grid of space (as if spaces were printed)
+ */
+static errr Term_wipe_emx(int x, int y, int n)
+{
+ v_gotoxy(x, y);
+ v_putn(' ', n);
+
+ return (0);
+}
+
+/*
+ * Draw some text, wiping behind it first
+ */
+static errr Term_text_emx(int x, int y, int n, unsigned char a, cptr s)
+{
+ /* Convert the color and put the text */
+ v_attrib(colors[a & 0x0F]);
+ v_gotoxy(x, y);
+ v_putm(s, n);
+
+ return (0);
+}
+
+/*
+ * EMX initialization
+ */
+static void Term_init_emx(term *t)
+{
+ struct _KBDINFO kbdinfo; /* see structure description ?somewhere? */
+
+ v_init();
+ v_getctype(&curs_start, &curs_end);
+ /* hide cursor (?) XXX XXX XXX */
+ v_clear();
+
+ /* the documentation I (SWD) have implies, in passing, that setting */
+ /* "binary mode" on the keyboard device will prevent the O/S from */
+ /* acting on keys such as ^S (pause) and ^P (printer echo). */
+
+ /* note also that "KbdSetStatus is ignored for a Vio-windowed application." */
+ /* so there may well be problems with running this in a window. Damnit. */
+
+ /* this is kind of a nasty structure, as you can't just flip a bit */
+ /* to change binary/ASCII mode, or echo on/off mode... nor can you */
+ /* clear the whole thing -- certain bits need to be preserved. */
+
+ KbdGetStatus(&kbdinfo, (HKBD)0);
+ kbdinfo.fsMask &= ~ (KEYBOARD_ECHO_ON | /* clear lowest four bits */
+ KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE | KEYBOARD_ASCII_MODE);
+ kbdinfo.fsMask |= (KEYBOARD_BINARY_MODE); /* set bit two */
+ KbdSetStatus(&kbdinfo, (HKBD)0);
+
+#if 1 /* turn off for debug */
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ /* signal(SIGILL,SIG_IGN); */
+ /* signal(SIGTRAP,SIG_IGN); */
+ /* signal(SIGABRT,SIG_IGN); */
+ /* signal(SIGEMT,SIG_IGN); */
+ /* signal(SIGFPE,SIG_IGN); */
+ /* signal(SIGBUS,SIG_IGN); */
+ /* signal(SIGSEGV,SIG_IGN); */
+ /* signal(SIGSYS,SIG_IGN); */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGALRM, SIG_IGN);
+ /* signal(SIGTERM,SIG_IGN); */
+ signal(SIGUSR1, SIG_IGN);
+ signal(SIGUSR2, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+ signal(SIGBREAK, SIG_IGN);
+#endif
+
+}
+
+/*
+ * EMX shutdown
+ */
+static void Term_nuke_emx(term *t)
+{
+ /* Move the cursor to bottom of screen */
+ v_gotoxy(0, 23);
+
+ /* Restore the cursor (not necessary) */
+ v_ctype(curs_start, curs_end);
+
+ /* Set attribute to gray on black */
+ v_attrib(F_WHITE);
+
+ /* Clear the screen */
+ v_clear();
+}
+
+
+#ifndef __EMX__CLIENT__
+
+/*
+ * Oh no, more prototypes!
+ */
+static errr CheckEvents(int returnImmediately);
+static errr Term_xtra_pipe_emx(int n, int v);
+static errr Term_curs_pipe_emx(int x, int y);
+static errr Term_wipe_pipe_emx(int x, int y, int n);
+static errr Term_text_pipe_emx(int x, int y, int n, unsigned char a, cptr s);
+static void Term_init_pipe_emx(term *t);
+static void Term_nuke_pipe_emx(term *t);
+static FILE *initPipe(const char *name);
+static void initPipeTerm(termPipe *pipe, const char *name, term **term);
+
+/*
+ * Main initialization function
+ */
+errr init_emx(void);
+
+/*
+ * The screens
+ */
+static termPipe term_screen_aga[MAX_TERM_DATA];
+
+
+/*
+ * Check for events -- called by "Term_scan_emx()"
+ *
+ * Note -- this is probably NOT the most efficient way
+ * to "wait" for a keypress (TERM_XTRA_EVENT).
+ *
+ *
+ * This code was ripped from "main-ibm.c" -- consult it to
+ * figure out what's going on.
+ *
+ * See "main-ibm.c" for more information about "macro encoding".
+ *
+ *
+ * The following documentation was cut&pasted from
+ * the OS/2 Programming Reference, PRCP.INF
+ * <ftp://hobbes.nmsu.edu/pub/os2/dev/16-bit/inf16bit.zip>
+-------------------------------------------------------------------------------
+
+
+ This call returns a character data record from the keyboard.
+
+ KbdCharIn (CharData, IOWait, KbdHandle)
+
+ CharData (PKBDKEYINFO) - output
+ Address of the character data structure:
+
+ asciicharcode (UCHAR)
+ ASCII character code. The scan code received from the keyboard is
+ translated to the ASCII character code.
+
+ scancode (UCHAR)
+ Code received from the keyboard. The scan code received from the
+ keyboard is translated to the ASCII character code.
+
+ status (UCHAR)
+ State of the keystroke event:
+
+ Bit Description
+
+ 7-6 00 = Undefined
+
+ 01 = Final character, interim character flag off
+
+ 10 = Interim character
+
+ 11 = Final character, interim character flag on.
+
+ 5 1 = Immediate conversion requested.
+
+ 4-2 Reserved.
+
+ 1 0 = Scan code is a character.
+
+ 1 = Scan code is not a character; is an extended key code
+ from the keyboard.
+
+ 0 1 = Shift status returned without character.
+
+ reserved (UCHAR)
+ NLS shift status. Reserved, set to zero.
+
+ shiftkeystat (USHORT)
+ Shift key status.
+
+ Bit Description
+ 15 SysReq key down
+ 14 CapsLock key down
+ 13 NumLock key down
+ 12 ScrollLock key down
+ 11 Right Alt key down
+ 10 Right Ctrl key down
+ 9 Left Alt key down
+ 8 Left Ctrl key down
+ 7 Insert on
+ 6 CapsLock on
+ 5 NumLock on
+ 4 ScrollLock on
+ 3 Either Alt key down
+ 2 Either Ctrl key down
+ 1 Left Shift key down
+ 0 Right Shift key down
+
+ time (ULONG)
+ Time stamp indicating when a key was pressed. It is specified in
+ milliseconds from the time the system was started.
+
+ IOWait (USHORT) - input
+ Wait if a character is not available.
+
+ Value Definition
+ 0 Requestor waits for a character if one is not available.
+ 1 Requestor gets an immediate return if no character is
+ available.
+
+ KbdHandle (HKBD) - input
+ Default keyboard or the logical keyboard.
+
+ rc (USHORT) - return
+ Return code descriptions are:
+
+ 0 NO_ERROR
+ 375 ERROR_KBD_INVALID_IOWAIT
+ 439 ERROR_KBD_INVALID_HANDLE
+ 445 ERROR_KBD_FOCUS_REQUIRED
+ 447 ERROR_KBD_KEYBOARD_BUSY
+ 464 ERROR_KBD_DETACHED
+ 504 ERROR_KBD_EXTENDED_SG
+
+ Remarks
+
+ On an enhanced keyboard, the secondary enter key returns the normal
+ character 0DH and a scan code of E0H.
+
+ Double-byte character codes (DBCS) require two function calls to obtain
+ the entire code.
+
+ If shift report is set with KbdSetStatus, the CharData record returned
+ reflects changed shift information only.
+
+ Extended ASCII codes are identified with the status byte, bit 1 on and the
+ ASCII character code being either 00H or E0H. Both conditions must be
+ satisfied for the character to be an extended keystroke. For extended
+ ASCII codes, the scan code byte returned is the second code (extended
+ code). Usually the extended ASCII code is the scan code of the primary
+ key that was pressed.
+
+ A thread in the foreground session that repeatedly polls the keyboard
+ with KbdCharIn (with no wait), can prevent all regular priority class
+ threads from executing. If polling must be used and a minimal amount of
+ other processing is being performed, the thread should periodically yield to
+ the CPU by issuing a DosSleep call for an interval of at least 5
+ milliseconds.
+
+
+ Family API Considerations
+
+ Some options operate differently in the DOS mode than in the OS /2 mode.
+ Therefore, the following restrictions apply to KbdCharIn when coding in
+ the DOS mode:
+
+ o The CharData structure includes everything except the time stamp.
+ o Interim character is not supported
+ o Status can be 0 or 40H
+ o KbdHandle is ignored.
+
+
+-------------------------------------------------------------------------------
+
+
+ typedef struct _KBDKEYINFO { / * kbci * /
+ UCHAR chChar; / * ASCII character code * /
+ UCHAR chScan; / * Scan Code * /
+ UCHAR fbStatus; / * State of the character * /
+ UCHAR bNlsShift; / * Reserved (set to zero) * /
+ USHORT fsState; / * State of the shift keys * /
+ ULONG time; / * Time stamp of keystroke (ms since ipl) * /
+ }KBDKEYINFO;
+
+ #define INCL_KBD
+
+ USHORT rc = KbdCharIn(CharData, IOWait, KbdHandle);
+
+ PKBDKEYINFO CharData; / * Buffer for data * /
+ USHORT IOWait; / * Indicate if wait * /
+ HKBD KbdHandle; / * Keyboard handle * /
+
+ USHORT rc; / * return code * /
+
+
+-------------------------------------------------------------------------------
+ *
+ */
+static errr CheckEvents(int returnImmediately)
+{
+ int i, k, s;
+
+ bool mc = FALSE;
+ bool ms = FALSE;
+ bool ma = FALSE;
+
+ /* start OS/2 specific section */
+
+ struct _KBDKEYINFO keyinfo; /* see structure description above */
+
+ /* Check (and possibly wait) for a keypress */
+ /* see function description above */
+ KbdCharIn( &keyinfo, returnImmediately, (HKBD)0 );
+
+#if 0
+ printf("AC:%x SC:%x ST:%x R1:%x SH:%x TI:%ld\n", /* OS/2 debug */
+ keyinfo.chChar,
+ keyinfo.chScan,
+ keyinfo.fbStatus,
+ keyinfo.bNlsShift,
+ keyinfo.fsState,
+ keyinfo.time );
+#endif
+
+ /* If there wasn't a key, leave now. */
+ if ((keyinfo.fbStatus & 0xC0) == 0) return (1);
+
+
+ /* by a set of lucky coincidences, the data maps directly over. */
+ k = keyinfo.chChar;
+ s = keyinfo.chScan;
+ i = (keyinfo.fsState & 0xFF);
+
+ /* end OS/2 specific section */
+
+
+ /* Process "normal" keys */
+ if ( k != 0 && ((s <= 58) || (s == 0xE0)) ) /* Tweak: allow for ALT-keys */
+ {
+ /* Enqueue it */
+ 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);
+}
+
+
+
+/*
+ * Do a special thing (beep, flush, etc)
+ */
+static errr Term_xtra_emx(int n, int v)
+{
+ switch (n)
+ {
+ case TERM_XTRA_SHAPE:
+ if (v)
+ {
+ v_ctype(curs_start, curs_end);
+ }
+ else
+ {
+ v_hidecursor();
+ }
+ return (0);
+
+ case TERM_XTRA_NOISE:
+ DosBeep(440, 50);
+ return (0);
+
+ case TERM_XTRA_FLUSH:
+ while (!CheckEvents(TRUE));
+ return 0;
+
+ case TERM_XTRA_EVENT:
+
+ /* Process an event */
+ return (CheckEvents(!v));
+
+ /* Success */
+ return (0);
+
+ case TERM_XTRA_CLEAR:
+ v_clear();
+ return (0);
+ }
+
+ return (1);
+}
+
+static errr Term_xtra_pipe_emx(int n, int v)
+{
+ termPipe *tp = (termPipe*)Term;
+
+ switch (n)
+ {
+ case TERM_XTRA_NOISE:
+ DosBeep(440, 50);
+ return (0);
+
+ case TERM_XTRA_SHAPE:
+ return (0);
+
+ case TERM_XTRA_EVENT:
+ return (CheckEvents(FALSE));
+
+ case TERM_XTRA_CLEAR:
+
+ if (!tp->out) return -1;
+
+ fputc(PIP_XTRA, tp->out);
+ fwrite(&n, sizeof(n), 1, tp->out);
+ fwrite(&v, sizeof(v), 1, tp->out);
+ fflush(tp->out);
+
+ return (0);
+ }
+
+ return (1);
+}
+
+static errr Term_curs_pipe_emx(int x, int y)
+{
+ termPipe *tp = (termPipe*)Term;
+
+ if (!tp->out) return -1;
+
+ fputc(PIP_CURS, tp->out);
+ fwrite(&x, sizeof(x), 1, tp->out);
+ fwrite(&y, sizeof(y), 1, tp->out);
+ fflush(tp->out);
+
+ return (0);
+}
+
+
+static errr Term_wipe_pipe_emx(int x, int y, int n)
+{
+ termPipe *tp = (termPipe*)Term;
+
+ if (!tp->out) return -1;
+
+ fputc(PIP_WIPE, tp->out);
+ fwrite(&x, sizeof(x), 1, tp->out);
+ fwrite(&y, sizeof(y), 1, tp->out);
+ fwrite(&n, sizeof(n), 1, tp->out);
+ fflush(tp->out);
+
+ return (0);
+}
+
+
+static errr Term_text_pipe_emx(int x, int y, int n, unsigned char a, cptr s)
+{
+ termPipe *tp = (termPipe*)Term;
+
+ if (!tp->out) return -1;
+
+ fputc(PIP_TEXT, tp->out);
+ fwrite(&x, sizeof(x), 1, tp->out);
+ fwrite(&y, sizeof(y), 1, tp->out);
+ fwrite(&n, sizeof(n), 1, tp->out);
+ fwrite(&a, sizeof(a), 1, tp->out);
+ fwrite(s, n, 1, tp->out);
+ fflush(tp->out);
+
+ return (0);
+}
+
+
+static void Term_init_pipe_emx(term *t)
+{
+ termPipe *tp = (termPipe*)t;
+
+ if (tp->out)
+ {
+ fputc(PIP_INIT, tp->out);
+ fflush(tp->out);
+ }
+}
+
+
+static void Term_nuke_pipe_emx(term *t)
+{
+ termPipe *tp = (termPipe*)t;
+
+ if (tp->out)
+ {
+ fputc(PIP_NUKE, tp->out); /* Terminate client */
+ fflush(tp->out);
+ fclose(tp->out); /* Close Pipe */
+ tp->out = NULL; /* Paranoia */
+ }
+}
+
+static void initPipeTerm(termPipe *pipe, const char *name, term **termTarget)
+{
+ term *t;
+
+ t = &pipe->t;
+
+ if ((pipe->out = initPipe(name)) != NULL)
+ {
+ /* Initialize the term */
+ term_init(t, 80, 24, 1);
+
+ /* Special hooks */
+ t->init_hook = Term_init_pipe_emx;
+ t->nuke_hook = Term_nuke_pipe_emx;
+
+ /* Add the hooks */
+ t->text_hook = Term_text_pipe_emx;
+ t->wipe_hook = Term_wipe_pipe_emx;
+ t->curs_hook = Term_curs_pipe_emx;
+ t->xtra_hook = Term_xtra_pipe_emx;
+
+ /* Save it */
+ *termTarget = t;
+
+ /* Activate it */
+ Term_activate(t);
+ }
+}
+
+/*
+ * Prepare "term.c" to use "USE_EMX" built-in video library
+ */
+errr init_emx(void)
+{
+ int i;
+
+ term *t;
+
+ /* Initialize the pipe windows */
+ for (i = MAX_TERM_DATA - 1; i > 0; --i)
+ {
+ const char *name = angband_term_name[i];
+ initPipeTerm(&term_screen_aga[i], name, &angband_term[i]);
+ }
+
+ /* Initialize main window */
+ t = &term_screen_aga[0].t;
+
+ /* Initialize the term -- big key buffer */
+ term_init(t, 80, 24, 1024);
+
+ /* Special hooks */
+ t->init_hook = Term_init_emx;
+ t->nuke_hook = Term_nuke_emx;
+
+ /* Add the hooks */
+ t->text_hook = Term_text_emx;
+ t->wipe_hook = Term_wipe_emx;
+ t->curs_hook = Term_curs_emx;
+ t->xtra_hook = Term_xtra_emx;
+
+ /* Save it */
+ angband_term[0] = t;
+
+ /* Activate it */
+ Term_activate(t);
+
+ /* Success */
+ return (0);
+}
+
+static FILE *initPipe(const char *name)
+{
+ char buf[256];
+ FILE *fi;
+
+ sprintf(buf, "\\pipe\\angband\\%s", name); /* Name of pipe */
+ fi = fopen(buf, "wb"); /* Look for server */
+ return fi;
+}
+
+#else /* __EMX__CLIENT__ */
+
+int main(int argc, char **argv)
+{
+ int c, end = 0, lines = 25;
+ int x, y, h, n, v;
+
+ FILE *in = NULL;
+ char a;
+ char buf[160];
+ HPIPE pipe;
+ APIRET rc;
+ char *target;
+
+ /* Check command line */
+ if (argc != 2 && argc != 3)
+ {
+ printf("Usage: %s Mirror|Recall|Choice|Term-4|...|Term-7 [number of lines]\n"
+ "Start this before angband.exe\n", argv[0]);
+ exit(1);
+ }
+
+ if (argc == 3) lines = atoi(argv[2]);
+ if (lines <= 0) lines = 25;
+
+ printf("Looking for Angband... press ^C to abort\n");
+
+ target = strdup(argv[1]);
+ for (c = 0; c < strlen(target); c++) target[c] = tolower(target[c]);
+
+ sprintf(buf, "\\pipe\\angband\\%s", target);
+
+ do
+ {
+ rc = DosCreateNPipe((PSZ)buf, /* Create pipe */
+ &pipe,
+ NP_ACCESS_INBOUND,
+ NP_WAIT | NP_TYPE_BYTE | NP_READMODE_BYTE | 1,
+ 1, /* No output buffer */
+ 1, /* No input buffer */
+ -1);
+
+ if (rc) /* Pipe not created */
+ {
+ printf("DosCreateNPipe: rc=%ld, pipe=%ld\n", (long)rc, (long)pipe);
+ break;
+ }
+
+ do
+ {
+ rc = DosConnectNPipe(pipe); /* Wait for angband to connect */
+ if (!rc) break;
+ _sleep2(500); /* Sleep for 0.5s */
+ }
+ while (_read_kbd(0, 0, 0) == -1); /* Until key pressed */
+
+ if (rc) break;
+
+ h = _imphandle(pipe); /* Register handle with io */
+ setmode(h, O_BINARY); /* Make it binary */
+ in = fdopen(h, "rb"); /* Register handle with stdio */
+
+ }
+ while (0); /* We don't need no stinking exception handling <g> */
+
+ if (!in)
+ {
+ printf("Sorry, the pipe connection to Angband could not be established.\n");
+ exit(1);
+ }
+
+ printf("Connected.\n");
+
+ sprintf(buf, "mode co80,%d", lines);
+ system(buf);
+
+ /* Infinite loop */
+ while (!end)
+ {
+ /* Get command */
+ c = fgetc(in);
+
+ switch (c)
+ {
+ case PIP_XTRA:
+ if (!fread(&n, sizeof(x), 1, in) ||
+ !fread(&v, sizeof(y), 1, in))
+ abort();
+
+ /* This hack prevents another hack */
+ switch (n)
+ {
+ case TERM_XTRA_CLEAR:
+ v_clear();
+ break;
+
+ default:
+ printf("Sorry, angband.exe and aclient.exe don't fit together.\n");
+ exit(1);
+ }
+
+ break;
+
+ case PIP_CURS:
+ if (!fread(&x, sizeof(x), 1, in) ||
+ !fread(&y, sizeof(y), 1, in))
+ abort();
+ Term_curs_emx(x, y);
+ break;
+
+ case PIP_WIPE:
+ if (!fread(&x, sizeof(x), 1, in) ||
+ !fread(&y, sizeof(y), 1, in) ||
+ !fread(&n, sizeof(n), 1, in))
+ abort();
+ Term_wipe_emx(x, y, n);
+ break;
+
+ case PIP_TEXT:
+ if (!fread(&x, sizeof(x), 1, in) ||
+ !fread(&y, sizeof(y), 1, in) ||
+ !fread(&n, sizeof(n), 1, in) ||
+ !fread(&a, sizeof(a), 1, in) || (n > 160) ||
+ !fread(buf, n, 1, in))
+ abort();
+ Term_text_emx(x, y, n, a, buf);
+ break;
+
+ case PIP_INIT:
+ Term_init_emx(NULL);
+ break;
+
+ case PIP_NUKE:
+ case EOF:
+ default:
+ Term_nuke_emx(NULL);
+ end = 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+#endif /* __EMX__CLIENT__ */
+
+#else /* EMXPM */
+
+void emx_endPM(const char *reason);
+int emx_options(char **ANGBAND_DIR_USER,
+ char **ANGBAND_DIR_SAVE,
+ char **ANGBAND_DIR_INFO,
+ char *arg_force_roguelike,
+ char *arg_force_original,
+ char *arg_fiddle,
+ char *arg_wizard,
+ char player_name[32]);
+
+void emx_init_window(void **instance, void *main_instance, int n);
+
+errr emx_curs(void *instance, int x, int y);
+errr emx_wipe(void *instance, int x, int y, int n);
+errr emx_text(void *instance, int x, int y, int n, unsigned char a, cptr s);
+void emx_init(void *instance);
+void emx_nuke(void *instance);
+int emx_read_kbd(void *instance, int wait);
+void emx_clear(void *instance);
+void emx_hidecursor(void *instance);
+void emx_showcursor(void *instance);
+
+/*
+* termWindow* is sometimes cast to term* and vice versa,
+* so "term t;" must be the first line
+*/
+
+typedef struct
+{
+ term t;
+ void *instance; /* Pointer to window */
+}
+termWindow;
+
+/*
+* Display a cursor, on top of a given attr/char
+*/
+static errr Term_curs_emx(int x, int y)
+{
+ return emx_curs(((termWindow*)Term)->instance, x, y);
+}
+
+/*
+* Erase a grid of space (as if spaces were printed)
+*/
+static errr Term_wipe_emx(int x, int y, int n)
+{
+ return emx_wipe(((termWindow*)Term)->instance, x, y, n);
+}
+
+/*
+* Draw some text, wiping behind it first
+*/
+static errr Term_text_emx(int x, int y, int n, unsigned char a, cptr s)
+{
+ return emx_text(((termWindow*)Term)->instance, x, y, n, a, s);
+}
+
+/*
+* EMX initialization
+*/
+static void Term_init_emx(term *t)
+{
+ return emx_init(((termWindow*)t)->instance);
+}
+
+/*
+* EMX shutdown
+*/
+static void Term_nuke_emx(term *t)
+{}
+
+/*
+* Oh no, more prototypes!
+*/
+static errr CheckEvents(int returnImmediately);
+
+/*
+* Main initialization function
+*/
+errr init_emx(void);
+
+/*
+* The screens
+*/
+static termWindow term_screen_aga[MAX_TERM_DATA];
+
+/*
+* Check for events -- called by "Term_scan_emx()"
+*/
+static errr CheckEvents(int returnImmediately)
+{
+ /* Get key - Macro triggers are generated by emx_read_kbd() */
+ int k = emx_read_kbd(((termWindow*)Term)->instance, returnImmediately ? 0 : 1);
+
+ /* Nothing ready */
+ if (k < 0) return (1);
+
+ /* Enqueue the key */
+ Term_keypress(k);
+
+ /* Success */
+ return (0);
+}
+
+/*
+* Do a special thing (beep, flush, etc)
+*/
+static errr Term_xtra_emx(int n, int v)
+{
+ void *instance = ((termWindow*)Term)->instance;
+
+ switch (n)
+ {
+ case TERM_XTRA_SHAPE:
+ if (v)
+ {
+ emx_showcursor(instance);
+ }
+ else
+ {
+ emx_hidecursor(instance);
+ }
+ return (0);
+
+ case TERM_XTRA_NOISE:
+ DosBeep(440, 50);
+ return (0);
+
+ case TERM_XTRA_FLUSH:
+ while (!CheckEvents(TRUE));
+ return 0;
+
+ case TERM_XTRA_EVENT:
+ return (CheckEvents(!v));
+
+ case TERM_XTRA_CLEAR:
+ emx_clear(instance);
+ return (0);
+
+ case TERM_XTRA_DELAY:
+ if (v > 0) _sleep2(v);
+ return (0);
+ }
+
+ return (1);
+}
+
+void emx_init_term(termWindow *t, void *main_instance, term **angTerm, int n)
+{
+ term *te = (term*)t;
+
+ /* Initialize window */
+ emx_init_window(&t->instance, main_instance, n);
+
+ *angTerm = te;
+
+ /* Initialize the term -- big key buffer */
+ term_init(te, 80, 24, 1024);
+
+ /* Special hooks */
+ te->init_hook = Term_init_emx;
+ te->nuke_hook = Term_nuke_emx;
+
+ /* Add the hooks */
+ te->text_hook = Term_text_emx;
+ te->wipe_hook = Term_wipe_emx;
+ te->curs_hook = Term_curs_emx;
+ te->xtra_hook = Term_xtra_emx;
+}
+
+/*
+* Prepare "term.c" to use "USE_EMX" built-in faked video library
+*/
+errr init_emx(void)
+{
+ int i;
+
+ /* Initialize the windows */
+ emx_init_term(&term_screen_aga[0], NULL, &angband_term[0], 0);
+
+ for (i = 1; i < MAX_TERM_DATA; ++i)
+ {
+ emx_init_term(&term_screen_aga[i], term_screen_aga[0].instance, &angband_term[i], i);
+ }
+
+ /* Activate main window */
+ Term_activate(angband_term[0]);
+
+ /* Success */
+ return (0);
+}
+
+static void init_stuff(void)
+{
+ char path[1024];
+ cptr tail;
+
+ /* Get the environment variable */
+ tail = getenv("ANGBAND_PATH");
+
+ /* Use the angband_path, or a default */
+ strcpy(path, tail ? tail : DEFAULT_PATH);
+
+ /* Hack -- Add a path separator (only if needed) */
+ if (!suffix(path, PATH_SEP)) strcat(path, PATH_SEP);
+
+ /* Initialize */
+ init_file_paths(path);
+}
+
+static void quit_hook(cptr s)
+{
+ int i;
+
+ for (i = MAX_TERM_DATA - 1; i >= 0; --i)
+ {
+ /* Shut down the term windows */
+ if (angband_term[i])
+ {
+ term_nuke(angband_term[i]);
+ emx_nuke(((termWindow*)angband_term[i])->instance);
+ }
+ }
+
+ /* Shut down window system - doesn't return */
+ emx_endPM(s);
+}
+
+
+void angbandThread(void *arg)
+{
+ bool new_game = FALSE;
+
+ int show_score = 0;
+
+ char player_name_aga[32];
+
+ /* Save the "program name" */
+ argv0 = (char*)arg;
+
+ /* Use the "main-emx.c" support */
+ init_emx();
+ ANGBAND_SYS = "ibm";
+
+ /* Get the file paths */
+ init_stuff();
+
+ if (!emx_options((char**)&ANGBAND_DIR_USER,
+ (char**)&ANGBAND_DIR_SAVE,
+ (char**)&ANGBAND_DIR_INFO,
+ &arg_force_roguelike,
+ &arg_force_original,
+ &arg_fiddle,
+ &arg_wizard,
+ player_name_aga)) quit(NULL);
+
+ /* XXX XXX XXX (?) */
+ strcpy(player_name, player_name_aga);
+
+ /* Process the player name */
+ process_player_name(TRUE);
+
+ /* Tell "quit()" to call "Term_nuke()" */
+ quit_aux = quit_hook;
+
+ /* If requested, display scores and quit */
+ if (show_score > 0) display_scores(0, show_score);
+
+ /* Catch nasty signals */
+ signals_init();
+
+ /* Initialize */
+ init_angband();
+
+ /* Wait for response */
+ pause_line(23);
+
+ /* Play the game */
+ play_game(new_game);
+
+ /* Quit */
+ quit(NULL);
+}
+
+#endif /* EMXPM */
+
+#endif /* USE_EMX */
+
+/*
+ * Local Variables:
+ * comment-column: 45
+ * End:
+ *
+ */
+