From 6aa48afdd57d03314fdf4be6c9da911c32277c84 Mon Sep 17 00:00:00 2001 From: Bardur Arantsson Date: Fri, 8 Jan 2010 20:28:34 +0100 Subject: Import tome-2.3.5. --- src/main-mac.c | 5504 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5504 insertions(+) create mode 100644 src/main-mac.c (limited to 'src/main-mac.c') diff --git a/src/main-mac.c b/src/main-mac.c new file mode 100644 index 00000000..2de64abd --- /dev/null +++ b/src/main-mac.c @@ -0,0 +1,5504 @@ +/* File: main-mac.c */ + +/* + * Copyright (c) 1997 Ben Harrison, Keith Randall, 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. + */ + + +/* + * This file helps Angband work with Macintosh computers. + * + * To use this file, use an appropriate "Makefile" or "Project File", which + * should define "MACINTOSH". + * + * The official compilation uses the CodeWarrior Pro compiler. + * + * If you are never going to use "graphics" (especially if you are not + * compiling support for graphics anyway) then you can delete the "pict" + * resource with id "1001" with no dangerous side effects. + * + * + * By default, this file assumes that you will be using a 68020 or better + * machine, running System 7 and Color Quickdraw. In fact, the game will + * refuse to run unless these features are available. This allows the use + * of a variety of interesting features such as graphics and sound. + * + * To create a version which can be used on 68000 machines, or on machines + * which are not running System 7 or Color Quickdraw, simply activate the + * "ANGBAND_LITE_MAC" compilation flag in the proper header file. This + * will disable all "modern" features used in this file, including support + * for multiple sub-windows, color, graphics, and sound. + * + * When compiling with the "ANGBAND_LITE_MAC" flag, the "ANGBAND_LITE" + * flag will be automatically defined, which will disable many of the + * advanced features of the game itself, reducing the total memory usage. + * + * + * Note that the "preference" file is now a simple text file called + * "Angband Preferences", which contains a version stamp, so that + * obsolete preference files can be ignored. This should probably + * be replaced with a "structured" preference file of some kind. + * + * Note that "init1.c", "init2.c", "load1.c", "load2.c", and "birth.c" + * should probably be "unloaded" as soon as they are no longer needed, + * to save space, but I do not know how to do this. XXX XXX XXX + * + * Stange bug -- The first "ClipRect()" call crashes if the user closes + * all the windows, switches to another application, switches back, and + * re-opens the main window, for example, using "command-a". XXX XXX XXX + * + * + * Initial framework (and most code) by Ben Harrison (benh@phial.com). + * + * Some code adapted from "MacAngband 2.6.1" by Keith Randall + * + * Initial PowerMac port by Maarten Hazewinkel (mmhazewi@cs.ruu.nl). + * + * Most "USE_SFL_CODE" code provided by Steve Linberg (slinberg@crocker.com). + * + * Most of the graphics code is adapted from an extremely minimal subset of + * the "Sprite World II" package, an amazing (and free) animation package. + * + * + * Important Resources in the resource file: + * + * FREF 130 = ANGBAND_CREATOR / 'APPL' (application) + * FREF 129 = ANGBAND_CREATOR / 'SAVE' (save file) + * FREF 130 = ANGBAND_CREATOR / 'TEXT' (bone file, generic text file) + * FREF 131 = ANGBAND_CREATOR / 'DATA' (binary image file, score file) + * + * DLOG 128 = "About Angband..." + * + * ALRT 128 = unused (?) + * ALRT 129 = "Warning..." + * ALRT 130 = "Are you sure you want to quit without saving?" + * + * DITL 128 = body for DLOG 128 + * DITL 129 = body for ALRT 129 + * DITL 130 = body for ALRT 130 + * + * ICON 128 = "warning" icon + * + * MENU 128 = apple (about, -, ...) + * MENU 129 = File (new, open, close, save, -, score, exit, quit) + * In T.o.M.E. + * MENU 129 = File (close, save, -, score, exit, quit) + * MENU 130 = Edit (undo, -, cut, copy, paste, clear) + * MENU 131 = Font (bold, wide, -) + * MENU 132 = Size () + * MENU 133 = Windows () + * MENU 134 = Special (Sound, Graphics, TileWidth, TileHeight, -, Fiddle, Wizard) + * Graphics have following submenu attached: + * MENU 144 = Graphics (None, 8x8, 16x16) + * TileWidth and TileHeight submenus are filled in by this program + * MENU 145 = TileWidth () + * MENU 146 = TileHeight () + * + * PICT 1001 = Graphics tile set (8x8) + * PICT 1002 = Graphics tile set (16x16 images) + * + * Note: You can no longer use the exit menu unless you build the programme + * with an appropriate compile-time option. + * + * + * File name patterns: + * all 'APEX' files have a filename of the form "*:apex:*" (?) + * all 'BONE' files have a filename of the form "*:bone:*" (?) + * all 'DATA' files have a filename of the form "*:data:*" + * all 'SAVE' files have a filename of the form "*:save:*" + * all 'USER' files have a filename of the form "*:user:*" (?) + * + * Perhaps we should attempt to set the "_ftype" flag inside this file, + * to avoid nasty file type information being spread all through the + * rest of the code. (?) This might require adding hooks into the + * "fd_open()" and "my_fopen()" functions in "util.c". XXX XXX XXX + * + * + * Reasons for each header file: + * + * angband.h = Angband header file + * + * Types.h = (included anyway) + * Gestalt.h = gestalt code + * QuickDraw.h = (included anyway) + * OSUtils.h = (included anyway) + * Files.h = file code + * Fonts.h = font code + * Menus.h = menu code + * Dialogs.h = dialog code + * Windows.h = (included anyway) + * Palettes.h = palette code + * StandardFile.h = file dialog box + * DiskInit.h = disk initialization + * ToolUtils.h = HiWord() / LoWord() + * Desk.h = OpenDeskAcc() + * Devices.h = OpenDeskAcc() + * Events.h = event code + * Resources.h = resource code + * Controls.h = button code + * SegLoad.h = ExitToShell(), AppFile, etc + * Memory.h = SetApplLimit(), NewPtr(), etc + * QDOffscreen.h = GWorld code + * Sound.h = Sound code + * + * For backwards compatibility: + * Use GestaltEqu.h instead of Gestalt.h + * Add Desk.h to include simply includes Menus.h, Devices.h, Events.h + */ + + +#include "angband.h" + + +#ifdef MACINTOSH + +/* + * Variant-dependent features: + * + * #define ALLOW_BIG_SCREEN (V, Ey, O, T.o.M.E. and Z. + * Dr's big screen needs more work. New S one needs some thought) + * #define ANG281_RESET_VISUALS (Cth, Gum, T.o.M.E., Z) + * #define SAVEFILE_SCREEN (T.o.M.E.) + * #define USE_DOUBLE_TILES ("bigtile" patch, V and T.o.M.E. + * T requires #define TOME in addition to this) + * #define ZANG_AUTO_SAVE (O and Z) + * #define HAS_SCORE_MENU (V and T.o.M.E.) + * #define ANGBAND_PREFERENCES "_your_variant_name_ Preferences" + * #define ANGBAND_CREATOR four letter code for your variant, if any. + * or use the default one. + * + * In [Z], please replace inkey_flag with p_ptr->inkey_flag as well. + */ + +/* Some porting examples */ +#ifdef ANGBAND30X +# define USE_DOUBLE_TILES +# define ALLOW_BIG_SCREEN +# define HAS_SCORE_MENU +# define NEW_ZVIRT_HOOKS +/* I can't ditch this, yet, because there are many variants */ +# define USE_TRANSPARENCY +#endif /* ANGBAND30X */ + +#ifdef TOME +# define USE_DOUBLE_TILES +# define SAVEFILE_SCREEN +# define ANG281_RESET_VISUALS +# define ALLOW_BIG_SCREEN +# define HAS_SCORE_MENU +# define ANGBAND_CREATOR 'PrnA' +# define ANGBAND_PREFERENCES "T.o.M.E. Preferences" +#endif /* TOME */ + +/* Default creator signature */ +# ifndef ANGBAND_CREATOR +# define ANGBAND_CREATOR 'A271' +# endif + +/* Default preferences file name */ +# ifndef ANGBAND_PREFERENCES +# define ANGBAND_PREFERENCES "Angband Preferences" +# endif + + +/* + * To cope with pref file related problems + * + * Please note that some variants don't set them to "real" version number + * and uses other defines for that purpose. + * + * This is *very* important for Classic ports, because wrong pref file formats + * can crash the system. + */ +#ifndef PREF_VER_MAJOR +# define PREF_VER_MAJOR VERSION_MAJOR +#endif +#ifndef PREF_VER_MINOR +# define PREF_VER_MINOR VERSION_MINOR +#endif +#ifndef PREF_VER_PATCH +# define PREF_VER_PATCH VERSION_PATCH +#endif +#ifndef PREF_VER_EXTRA +# define PREF_VER_EXTRA VERSION_EXTRA +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Use "malloc()" instead of "NewPtr()" + */ +/* #define USE_MALLOC */ + + +#if defined(powerc) || defined(__powerc) + +/* + * Disable "LITE" version + */ +# undef ANGBAND_LITE_MAC + +#endif + + +#ifndef ANGBAND_LITE_MAC + +/* + * Activate some special code + */ +# define USE_SFL_CODE + +#endif /* ANGBAND_LITE_MAC */ + + + +#ifdef USE_SFL_CODE + +/* + * Include the necessary header files + */ +#include +#include +#include + +#endif + + +#ifdef ANGBAND_LITE_MAC + +/* + * Everything in drawn as white on black + */ + +#else /* ANGBAND_LITE_MAC */ + +/* +* Information about each of the 256 available colors +*/ +static RGBColor color_info[256]; + +#endif /* ANGBAND_LITE_MAC */ + + +/* + * Forward declare + */ +typedef struct term_data term_data; + +/* + * Extra "term" data + */ +struct term_data +{ + term *t; + + Rect r; + + WindowPtr w; + +#ifdef ANGBAND_LITE_MAC + + /* Nothing */ + +#else /* ANGBAND_LITE_MAC */ + + short padding; + + short pixelDepth; + + GWorldPtr theGWorld; + + GDHandle theGDH; + + GDHandle mainSWGDH; + +#endif /* ANGBAND_LITE_MAC */ + + Str15 title; + + s16b oops; + + s16b keys; + + s16b last; + + s16b mapped; + + s16b rows; + s16b cols; + + s16b font_id; + s16b font_size; + s16b font_face; + s16b font_mono; + + s16b font_o_x; + s16b font_o_y; + s16b font_wid; + s16b font_hgt; + + s16b tile_o_x; + s16b tile_o_y; + s16b tile_wid; + s16b tile_hgt; + + s16b size_wid; + s16b size_hgt; + + s16b size_ow1; + s16b size_oh1; + s16b size_ow2; + s16b size_oh2; +}; + + + + +#ifdef MAC_MPW + +/* + * MPW 68K compiler cannot process ToME's variable.c correctly... + * but support for it is here, for your reference. I have tried + * this with SC and MrC to compile Vanilla successfully. + */ +QDGlobals qd; + +/* + * File type assigner - declare them in externs.h as well. + * + * You still have to call + * fsetfileinfo(buf, _fcreator, _ftype); + * in fd_make() and my_fopen() to assign creator and type + * to a file. + */ +u32b _ftype; +u32b _fcreator; + +/* + * Since MPW's C library doesn't have stat or fstat, you have to + * disable CHECK_MODIFICATION_TIME in config.h + * + * Another source code change required for MPW compilation is + * to #define MACINTOSH and #undef __STDC__ + * This can be done conveniently in h-system.h + * + * You may have to cast some pointers to non-offending types e.g. (void *). + * This typically occurs when passing a const pointer to a library + * function whose prototype doesn't have const in corresponding + * parameter. + */ + +#endif /* MAC_MPW */ + + +/* + * Forward declare -- see below + */ +static bool CheckEvents(bool wait); + + +/* + * Hack -- location of the main directory + */ +static short app_vol; +static long app_dir; + + +/* + * Delay handling of double-clicked savefiles + */ +Boolean open_when_ready = FALSE; + +/* + * Delay handling of pre-emptive "quit" event + */ +Boolean quit_when_ready = FALSE; + + +/* + * Hack -- game in progress + */ +static int game_in_progress = 0; + + +/* + * Only do "SetPort()" when needed + */ +static WindowPtr active = NULL; + + +/* + * Maximum number of terms + */ +#define MAX_TERM_DATA 8 + + +/* + * An array of term_data's + */ +static term_data data[MAX_TERM_DATA]; + + + +/* + * Note when "open"/"new" become valid + */ +static bool initialized = FALSE; + + + +#ifdef ALLOW_NO_SAVE_QUITS + +/* + * CodeWarrior uses Universal Procedure Pointers + */ +static ModalFilterUPP ynfilterUPP; + +#endif /* ALLOW_NO_SAVE_QUITS */ + + + +#ifdef USE_SFL_CODE + +/* + * Apple Event Hooks + */ +AEEventHandlerUPP AEH_Start_UPP; +AEEventHandlerUPP AEH_Quit_UPP; +AEEventHandlerUPP AEH_Print_UPP; +AEEventHandlerUPP AEH_Open_UPP; + +#endif + + + +/* + * Convert a C string to a pascal string in place + * + * This function may be defined elsewhere, but since it is so + * small, it is not worth finding the proper function name for + * all the different platforms. + */ +static void ctopstr(StringPtr src) +{ + int i; + byte len; + + /* Hack -- pointer */ + char *s = (char*)(src); + + len = strlen(s); + + /* Hack -- convert the string */ + for (i = len; i > 1; i--) s[i] = s[i - 1]; + + /* Hack -- terminate the string */ + s[0] = len; +} + + +/* + * Convert refnum+vrefnum+fname into a full file name + * Store this filename in 'buf' (make sure it is long enough) + * Note that 'fname' looks to be a "pascal" string + */ +static void refnum_to_name(char *buf, long refnum, short vrefnum, char *fname) +{ + DirInfo pb; + Str255 name; + int err; + int i, j; + + char res[1000]; + + i = 999; + + res[i] = 0; + i--; + for (j = 1; j <= fname[0]; j++) + { + res[i - fname[0] + j] = fname[j]; + } + i -= fname[0]; + + pb.ioCompletion = NULL; + pb.ioNamePtr = name; + pb.ioVRefNum = vrefnum; + pb.ioDrParID = refnum; + pb.ioFDirIndex = -1; + + while (1) + { + pb.ioDrDirID = pb.ioDrParID; + err = PBGetCatInfoSync((CInfoPBPtr) & pb); + res[i] = ':'; + i--; + for (j = 1; j <= name[0]; j++) + { + res[i - name[0] + j] = name[j]; + } + i -= name[0]; + + if (pb.ioDrDirID == fsRtDirID) break; + } + + /* Extract the result */ + for (j = 0, i++; res[i]; j++, i++) buf[j] = res[i]; + buf[j] = 0; +} + + +#if 0 + +/* + * XXX XXX XXX Allow the system to ask us for a filename + */ +static bool askfor_file(char *buf, int len) +{ + SFReply reply; + Str255 dflt; + Point topleft; + short vrefnum; + long drefnum, junk; + + /* Default file name */ + strnfmt((char*)dflt + 1, 255, "%s's description", buf); + dflt[0] = strlen((char*)dflt + 1); + + /* Ask for a file name */ + topleft.h = (qd.screenBits.bounds.left + qd.screenBits.bounds.right) / 2 - 344 / 2; + topleft.v = (2 * qd.screenBits.bounds.top + qd.screenBits.bounds.bottom) / 3 - 188 / 2; + SFPutFile(topleft, "\pSelect a filename:", dflt, NULL, &reply); + /* StandardPutFile("\pSelect a filename:", dflt, &reply); */ + + /* Process */ + if (reply.good) + { + int fc; + + /* Get info */ + GetWDInfo(reply.vRefNum, &vrefnum, &drefnum, &junk); + + /* Extract the name */ + refnum_to_name(buf, drefnum, vrefnum, (char*)reply.fName); + + /* Success */ + return (TRUE); + } + + /* Failure */ + return (FALSE); +} + +#endif + + + +/* + * Center a rectangle inside another rectangle + */ +static void center_rect(Rect *r, Rect *s) +{ + int centerx = (s->left + s->right) / 2; + int centery = (2 * s->top + s->bottom) / 3; + int dx = centerx - (r->right - r->left) / 2 - r->left; + int dy = centery - (r->bottom - r->top) / 2 - r->top; + r->left += dx; + r->right += dx; + r->top += dy; + r->bottom += dy; +} + + +/* + * Convert a pascal string in place + * + * This function may be defined elsewhere, but since it is so + * small, it is not worth finding the proper function name for + * all the different platforms. + */ +static void ptocstr(StringPtr src) +{ + int i; + + /* Hack -- pointer */ + char *s = (char*)(src); + + /* Hack -- convert the string */ + for (i = s[0]; i; i--, s++) s[0] = s[1]; + + /* Hack -- terminate the string */ + s[0] = '\0'; +} + + +#if defined(USE_SFL_CODE) + + +/* + * The following three routines (pstrcat, pstrinsert, and PathNameFromDirID) + * were taken from the Think Reference section called "Getting a Full Pathname" + * (under the File Manager section). We need PathNameFromDirID to get the + * full pathname of the opened savefile, making no assumptions about where it + * is. + * + * I had to hack PathNameFromDirID a little for MetroWerks, but it's awfully + * nice. + */ +static void pstrcat(StringPtr dst, StringPtr src) +{ + /* copy string in */ + BlockMove(src + 1, dst + *dst + 1, *src); + + /* adjust length byte */ + *dst += *src; +} + +/* + * pstrinsert - insert string 'src' at beginning of string 'dst' + */ +static void pstrinsert(StringPtr dst, StringPtr src) +{ + /* make room for new string */ + BlockMove(dst + 1, dst + *src + 1, *dst); + + /* copy new string in */ + BlockMove(src + 1, dst + 1, *src); + + /* adjust length byte */ + *dst += *src; +} + +static void PathNameFromDirID(long dirID, short vRefNum, StringPtr fullPathName) +{ + CInfoPBRec block; + Str255 directoryName; + OSErr err; + + fullPathName[0] = '\0'; + + block.dirInfo.ioDrParID = dirID; + block.dirInfo.ioNamePtr = directoryName; + + while (1) + { + block.dirInfo.ioVRefNum = vRefNum; + block.dirInfo.ioFDirIndex = -1; + block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID; + err = PBGetCatInfoSync(&block); + pstrcat(directoryName, (StringPtr)"\p:"); + pstrinsert(fullPathName, directoryName); + if (block.dirInfo.ioDrDirID == 2) break; + } +} + +#endif + + + +/* + * Activate a given window, if necessary + */ +static void activate(WindowPtr w) +{ + /* Activate */ + if (active != w) + { + /* Activate */ + if (w) SetPort(w); + + /* Remember */ + active = w; + } +} + + +/* + * Display a warning message + */ +static void mac_warning(cptr warning) +{ + Str255 text; + int len, i; + + /* Limit of 250 chars */ + len = strlen(warning); + if (len > 250) len = 250; + + /* Make a "Pascal" string */ + text[0] = len; + for (i = 0; i < len; i++) text[i + 1] = warning[i]; + + /* Prepare the dialog box values */ + ParamText(text, "\p", "\p", "\p"); + + /* Display the Alert, wait for Okay */ + Alert(129, 0L); +} + + + +/*** Some generic functions ***/ + + +#ifdef ANGBAND_LITE_MAC + +/* + * Hack -- activate a color (0 to 255) + */ +#define term_data_color(TD,A) /* Nothing */ + +#else /* ANGBAND_LITE_MAC */ + +/* +* Hack -- activate a color (0 to 255) +*/ +static void term_data_color(term_data *td, int a) +{ + /* Activate the color */ + if (td->last != a) + { + /* Activate the color */ + RGBForeColor(&color_info[a]); + + /* Memorize color */ + td->last = a; + } +} + +#endif /* ANGBAND_LITE_MAC */ + + +/* + * Hack -- Apply and Verify the "font" info + * + * This should usually be followed by "term_data_check_size()" + * + * XXX XXX To force (re)initialisation of td->tile_wid and td->tile_hgt + * you have to reset them to zero before this function is called. + * XXX XXX This is automatic when the program starts because the term_data + * array is WIPE'd by term_data_hack, but isn't in the other cases, i.e. + * font, font style and size changes. + */ +static void term_data_check_font(term_data *td) +{ + int i; + + FontInfo info; + + WindowPtr old = active; + + + /* Activate */ + activate(td->w); + + /* Instantiate font */ + TextFont(td->font_id); + TextSize(td->font_size); + TextFace(td->font_face); + + /* Extract the font info */ + GetFontInfo(&info); + + /* Assume monospaced */ + td->font_mono = TRUE; + + /* Extract the font sizing values XXX XXX XXX */ + td->font_wid = CharWidth('@'); /* info.widMax; */ + td->font_hgt = info.ascent + info.descent; + td->font_o_x = 0; + td->font_o_y = info.ascent; + + /* Check important characters */ + for (i = 33; i < 127; i++) + { + /* Hack -- notice non-mono-space */ + if (td->font_wid != CharWidth(i)) td->font_mono = FALSE; + + /* Hack -- collect largest width */ + if (td->font_wid < CharWidth(i)) td->font_wid = CharWidth(i); + } + + /* Set default offsets */ + td->tile_o_x = td->font_o_x; + td->tile_o_y = td->font_o_y; + + /* Set default tile size */ + if (td->tile_wid == 0) td->tile_wid = td->font_wid; + if (td->tile_hgt == 0) td->tile_hgt = td->font_hgt; + + /* Re-activate the old window */ + activate(old); +} + + +/* + * Hack -- Apply and Verify the "size" info + */ +static void term_data_check_size(term_data *td) +{ + /* Minimal window size for the Angband window */ + if (td == &data[0]) + { +#ifdef ALLOW_BIG_SCREEN + + /* Enforce minimal size */ + if (td->cols < 80) td->cols = 80; + if (td->rows < 24) td->rows = 24; + +#else + + /* Enforce the traditional size */ + if (td->cols != 80) td->cols = 80; + if (td->rows != 24) td->rows = 24; + +#endif /* ALLOW_BIG_SCREEN */ + } + + /* Allow small windows for the rest */ + else + { + if (td->cols < 1) td->cols = 1; + if (td->rows < 1) td->rows = 1; + } + + /* Enforce maximal sizes */ + if (td->cols > 255) td->cols = 255; + if (td->rows > 255) td->rows = 255; + + /* Minimal tile size */ + if (td->tile_wid < td->font_wid) td->tile_wid = td->font_wid; + if (td->tile_hgt < td->font_hgt) td->tile_hgt = td->font_hgt; + + /* Default tile offsets */ + td->tile_o_x = (td->tile_wid - td->font_wid) / 2; + td->tile_o_y = (td->tile_hgt - td->font_hgt) / 2; + + /* Minimal tile offsets */ + if (td->tile_o_x < 0) td->tile_o_x = 0; + if (td->tile_o_y < 0) td->tile_o_y = 0; + + /* Apply font offsets */ + td->tile_o_x += td->font_o_x; + td->tile_o_y += td->font_o_y; + + /* Calculate full window size */ + td->size_wid = td->cols * td->tile_wid + td->size_ow1 + td->size_ow2; + td->size_hgt = td->rows * td->tile_hgt + td->size_oh1 + td->size_oh2; + + /* Verify the top */ + if (td->r.top > qd.screenBits.bounds.bottom - td->size_hgt) + { + td->r.top = qd.screenBits.bounds.bottom - td->size_hgt; + } + + /* Verify the top */ + if (td->r.top < qd.screenBits.bounds.top + 30) + { + td->r.top = qd.screenBits.bounds.top + 30; + } + + /* Verify the left */ + if (td->r.left > qd.screenBits.bounds.right - td->size_wid) + { + td->r.left = qd.screenBits.bounds.right - td->size_wid; + } + + /* Verify the left */ + if (td->r.left < qd.screenBits.bounds.left) + { + td->r.left = qd.screenBits.bounds.left; + } + + /* Calculate bottom right corner */ + td->r.right = td->r.left + td->size_wid; + td->r.bottom = td->r.top + td->size_hgt; + + /* Assume no graphics */ + td->t->higher_pict = FALSE; + td->t->always_pict = FALSE; + +#ifdef ANGBAND_LITE_MAC + + /* No graphics */ + +#else /* ANGBAND_LITE_MAC */ + + /* Handle graphics */ + if (use_graphics) + { + /* Use higher_pict whenever possible */ + if (td->font_mono) td->t->higher_pict = TRUE; + + /* Use always_pict only when necessary */ + else td->t->always_pict = TRUE; + } + +#endif /* ANGBAND_LITE_MAC */ + + /* Fake mono-space */ + if (!td->font_mono || + (td->font_wid != td->tile_wid) || + (td->font_hgt != td->tile_hgt)) + { + /* Handle fake monospace -- this is SLOW */ + if (td->t->higher_pict) td->t->higher_pict = FALSE; + td->t->always_pict = TRUE; + } +} + + +/* + * Hack -- resize a term_data + * + * This should normally be followed by "term_data_resize()" + */ +static void term_data_resize(term_data *td) +{ + /* Actually resize the window */ + SizeWindow(td->w, td->size_wid, td->size_hgt, 0); +} + + + +/* + * Hack -- redraw a term_data + * + * Note that "Term_redraw()" calls "TERM_XTRA_CLEAR" + */ +static void term_data_redraw(term_data *td) +{ + term *old = Term; + + /* Activate the term */ + Term_activate(td->t); + + /* Redraw the contents */ + Term_redraw(); + + /* Flush the output */ + Term_fresh(); + + /* Restore the old term */ + Term_activate(old); + + /* No need to redraw */ + ValidRect(&td->w->portRect); +} + + + + +#ifdef ANGBAND_LITE_MAC + +/* No graphics */ + +#else /* ANGBAND_LITE_MAC */ + + +/* +* Graphics support +*/ + +/* Set by Term_xtra_mac_react */ +static int pictID; /* PICT id of image tiles */ + +static int grafWidth; /* Width of a tile in pixels */ +static int grafHeight; /* Height of a tile in pixels */ + +/* Calculated by PICT loading code */ +static int pictCols; /* Number of columns in tiles */ +static int pictRows; /* Number of rows in tiles */ + +/* Available graphics modes */ +#define GRAF_MODE_NONE 0 /* plain ASCII */ +#define GRAF_MODE_8X8 1 /* 8x8 tiles, no transparency effect */ +#define GRAF_MODE_16X16 2 /* 16x16 tiles, transparency effect */ +/* This doesn't work... */ +#define GRAF_MODE_32X32 3 /* 32x32 tiles, transparency effect */ + +static int graf_mode = GRAF_MODE_NONE; /* current graphics mode */ +static int graf_mode_req = GRAF_MODE_NONE; /* requested graphics mode */ + +#define TR_NONE 0 /* No transparency effect */ +#define TR_OVER 1 /* Overwriting with transparent black pixels */ +static int transparency_mode = TR_NONE; + + +/* +* Forward Declare +*/ +typedef struct FrameRec FrameRec; + +/* +* Frame +* +* - GWorld for the frame image +* - Handle to pix map (saved for unlocking/locking) +* - Pointer to color pix map (valid only while locked) +*/ +struct FrameRec +{ + GWorldPtr framePort; + PixMapHandle framePixHndl; + PixMapPtr framePix; +}; + + +/* +* The global picture data +*/ +static FrameRec *frameP = NULL; + + +/* +* Lock a frame +*/ +static void BenSWLockFrame(FrameRec *srcFrameP) +{ + PixMapHandle pixMapH; + + pixMapH = GetGWorldPixMap(srcFrameP->framePort); + (void)LockPixels(pixMapH); + HLockHi((Handle)pixMapH); + srcFrameP->framePixHndl = pixMapH; + srcFrameP->framePix = (PixMapPtr)StripAddress(*(Handle)pixMapH); +} + + +/* +* Unlock a frame +*/ +static void BenSWUnlockFrame(FrameRec *srcFrameP) +{ + if (srcFrameP->framePort != NULL) + { + HUnlock((Handle)srcFrameP->framePixHndl); + UnlockPixels(srcFrameP->framePixHndl); + } + + srcFrameP->framePix = NULL; +} + + + +static OSErr BenSWCreateGWorldFromPict( + GWorldPtr *pictGWorld, PicHandle pictH) +{ + OSErr err; + GWorldPtr saveGWorld; + GDHandle saveGDevice; + GWorldPtr tempGWorld; + Rect pictRect; + short depth; + GDHandle theGDH; + + tempGWorld = NULL; + + /* Reset */ + *pictGWorld = NULL; + + /* Get depth */ + depth = data[0].pixelDepth; + + /* Get GDH */ + theGDH = data[0].theGDH; + + /* Obtain size rectangle */ + pictRect = (**pictH).picFrame; + OffsetRect(&pictRect, -pictRect.left, -pictRect.top); + + /* Calculate and set numbers of rows and columns */ + pictRows = pictRect.bottom / grafHeight; + pictCols = pictRect.right / grafWidth; + + /* Create a GWorld */ + err = NewGWorld(&tempGWorld, depth, &pictRect, nil, theGDH, noNewDevice); + + /* Error */ + if (err != noErr) return (err); + + /* Save pointer */ + *pictGWorld = tempGWorld; + + /* Save GWorld */ + GetGWorld(&saveGWorld, &saveGDevice); + + /* Activate */ + SetGWorld(tempGWorld, nil); + + /* Dump the pict into the GWorld */ + (void)LockPixels(GetGWorldPixMap(tempGWorld)); + EraseRect(&pictRect); + DrawPicture(pictH, &pictRect); + UnlockPixels(GetGWorldPixMap(tempGWorld)); + + /* Restore GWorld */ + SetGWorld(saveGWorld, saveGDevice); + + /* Success */ + return (0); +} + + +/* +* Init the global "frameP" +*/ +static OSErr globe_init(void) +{ + OSErr err; + + GWorldPtr tempPictGWorldP; + + PicHandle newPictH; + + + /* Use window XXX XXX XXX */ + SetPort(data[0].w); + + + /* Get the pict resource */ + newPictH = GetPicture(pictID); + + /* Error */ + if (newPictH == NULL) return ( -1); + + /* Create GWorld */ + err = BenSWCreateGWorldFromPict(&tempPictGWorldP, newPictH); + + /* Release resource */ + ReleaseResource((Handle)newPictH); + + /* Error */ + if (err != noErr) return (err); + + /* Create the frame */ + frameP = (FrameRec*)NewPtrClear((Size)sizeof(FrameRec)); + + /* Error */ + if (frameP == NULL) return ( -1); + + /* Save GWorld */ + frameP->framePort = tempPictGWorldP; + + /* Lock it */ + BenSWLockFrame(frameP); + + /* Success */ + return (noErr); +} + + +/* +* Nuke the global "frameP" +*/ +static errr globe_nuke(void) +{ + /* Dispose */ + if (frameP) + { + /* Unlock */ + BenSWUnlockFrame(frameP); + + /* Dispose of the GWorld */ + DisposeGWorld(frameP->framePort); + + /* Dispose of the memory */ + DisposePtr((Ptr)frameP); + + /* Forget */ + frameP = NULL; + } + + /* Flush events */ + FlushEvents(everyEvent, 0); + + /* Success */ + return (0); +} + + +#endif /* ANGBAND_LITE_MAC */ + + + + +#ifdef USE_ASYNC_SOUND + +/* + * Asynchronous sound player - completely revised (beta) + */ + +/* + * Number of channels in the channel pool + */ +#define MAX_CHANNELS 4 + +/* + * A pool of sound channels + */ +static SndChannelPtr channels[MAX_CHANNELS]; + +/* + * Status of the channel pool + */ +static Boolean channel_initialised = FALSE; + +/* + * Data handles containing sound samples + */ +static SndListHandle samples[SOUND_MAX]; + +/* + * Reference counts of sound samples + */ +static SInt16 sample_refs[SOUND_MAX]; + +#define SOUND_VOLUME_MIN 0 /* Default minimum sound volume */ +#define SOUND_VOLUME_MAX 255 /* Default maximum sound volume */ +#define VOLUME_MIN 0 /* Minimum sound volume in % */ +#define VOLUME_MAX 100 /* Maximum sound volume in % */ +#define VOLUME_INC 5 /* Increment sound volume in % */ + +/* I'm just too lazy to write a panel for this XXX XXX */ +static int sound_volume = SOUND_VOLUME_MAX; + +/* + * Return a handle of 'snd ' resource given Angband sound event number, + * or NULL if it isn't found. + * + * Globals referenced: angband_sound_name[] (variable.c) + */ +static SndListHandle find_sound(int num) +{ + Str255 sound; + + /* Get the proper sound name */ + strnfmt((char*)sound + 1, 255, "%.16s.wav", angband_sound_name[num]); + sound[0] = strlen((char*)sound + 1); + + /* Obtain resource XXX XXX XXX */ + return ((SndListHandle)GetNamedResource('snd ', sound)); +} + + +/* + * Clean up sound support - to be called when the game exits. + * + * Globals referenced: channels[], samples[], sample_refs[]. + */ +static void cleanup_sound(void) +{ + int i; + + /* No need to clean it up */ + if (!channel_initialised) return; + + /* Dispose channels */ + for (i = 0; i < MAX_CHANNELS; i++) + { + /* Drain sound commands and free the channel */ + SndDisposeChannel(channels[i], TRUE); + } + + /* Free sound data */ + for (i = 1; i < SOUND_MAX; i++) + { + /* Still locked */ + if ((sample_refs[i] > 0) && (samples[i] != NULL)) + { + /* Unlock it */ + HUnlock((Handle)samples[i]); + } + + /* Release it */ + if (samples[i]) ReleaseResource((Handle)samples[i]); + } +} + + +/* + * Play sound effects asynchronously -- pelpel + * + * I don't believe those who first started using the previous implementations + * imagined this is *much* more complicated as it may seem. Anyway, + * introduced round-robin scheduling of channels and made it much more + * paranoid about HLock/HUnlock. + * + * XXX XXX de-refcounting, HUnlock and ReleaseResource should be done + * using channel's callback procedures, which set global flags, and + * a procedure hooked into CheckEvents does housekeeping. On the other + * hand, this lazy reclaiming strategy keeps things simple (no interrupt + * time code) and provides a sort of cache for sound data. + * + * Globals referenced: channel_initialised, channels[], samples[], + * sample_refs[]. + * Globals updated: ditto. + */ +static void play_sound(int num, int vol) +{ + OSErr err; + int i; + int prev_num; + SndListHandle h; + SndChannelPtr chan; + SCStatus status; + + static int next_chan; + static SInt16 channel_occupants[MAX_CHANNELS]; + static SndCommand volume_cmd, quiet_cmd; + + + /* Initialise sound channels */ + if (!channel_initialised) + { + for (i = 0; i < MAX_CHANNELS; i++) + { + /* Paranoia - Clear occupant table */ + /* channel_occupants[i] = 0; */ + + /* Create sound channel for all sounds to play from */ + err = SndNewChannel(&channels[i], sampledSynth, initMono, 0L); + + /* Error */ + if (err != noErr) + { + /* Free channels */ + while (--i >= 0) + { + SndDisposeChannel(channels[i], TRUE); + } + + /* Notify error */ + plog("Cannot initialise sound channels!"); + + /* Cancel request */ + use_sound = arg_sound = FALSE; + + /* Failure */ + return; + } + } + + /* First channel to use */ + next_chan = 0; + + /* Prepare volume command */ + volume_cmd.cmd = volumeCmd; + volume_cmd.param1 = 0; + volume_cmd.param2 = 0; + + /* Prepare quiet command */ + quiet_cmd.cmd = quietCmd; + quiet_cmd.param1 = 0; + quiet_cmd.param2 = 0; + + /* Initialisation complete */ + channel_initialised = TRUE; + } + + /* Paranoia */ + if ((num <= 0) || (num >= SOUND_MAX)) return; + + /* Prepare volume command */ + volume_cmd.param2 = (SInt16)((vol << 4) | vol); + + /* Channel to use (round robin) */ + chan = channels[next_chan]; + + /* See if the resource is already in use */ + if (sample_refs[num] > 0) + { + /* Resource in use */ + h = samples[num]; + + /* Increase the refcount */ + sample_refs[num]++; + } + + /* Sound is not currently in use */ + else + { + /* Get handle for the sound */ + h = find_sound(num); + + /* Sample not available */ + if (h == NULL) return; + + /* Load resource */ + LoadResource((Handle)h); + + /* Lock the handle */ + HLock((Handle)h); + + /* Remember it */ + samples[num] = h; + + /* Initialise refcount */ + sample_refs[num] = 1; + } + + /* Poll the channel */ + err = SndChannelStatus(chan, sizeof(SCStatus), &status); + + /* It isn't available */ + if ((err != noErr) || status.scChannelBusy) + { + /* Shut it down */ + SndDoImmediate(chan, &quiet_cmd); + } + + /* Previously played sound on this channel */ + prev_num = channel_occupants[next_chan]; + + /* Process previously played sound */ + if (prev_num != 0) + { + /* Decrease refcount */ + sample_refs[prev_num]--; + + /* We can free it now */ + if (sample_refs[prev_num] <= 0) + { + /* Unlock */ + HUnlock((Handle)samples[prev_num]); + + /* Release */ + ReleaseResource((Handle)samples[prev_num]); + + /* Forget handle */ + samples[prev_num] = NULL; + + /* Paranoia */ + sample_refs[prev_num] = 0; + } + } + + /* Remember this sound as the current occupant of the channel */ + channel_occupants[next_chan] = num; + + /* Set up volume for channel */ + SndDoImmediate(chan, &volume_cmd); + + /* Play new sound asynchronously */ + SndPlay(chan, h, TRUE); + + /* Schedule next channel (round robin) */ + next_chan++; + if (next_chan >= MAX_CHANNELS) next_chan = 0; +} + +#endif /* USE_ASYNC_SOUND */ + + +/*** Support for the "z-term.c" package ***/ + + +/* + * Initialize a new Term + * + * Note also the "window type" called "noGrowDocProc", which might be more + * appropriate for the main "screen" window. + * + * Note the use of "srcCopy" mode for optimized screen writes. + */ +static void Term_init_mac(term *t) +{ + term_data *td = (term_data*)(t->data); + + static RGBColor black = {0x0000, 0x0000, 0x0000}; + static RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; + +#ifdef ANGBAND_LITE_MAC + + /* Make the window */ + td->w = NewWindow(0, &td->r, td->title, 0, noGrowDocProc, (WindowPtr) - 1, 1, 0L); + +#else /* ANGBAND_LITE_MAC */ + + /* Make the window */ + td->w = NewCWindow(0, &td->r, td->title, 0, documentProc, (WindowPtr) - 1, 1, 0L); + +#endif /* ANGBAND_LITE_MAC */ + + /* Activate the window */ + activate(td->w); + + /* Erase behind words */ + TextMode(srcCopy); + + /* Apply and Verify */ + term_data_check_font(td); + term_data_check_size(td); + + /* Resize the window */ + term_data_resize(td); + +#ifdef ANGBAND_LITE_MAC + + /* Prepare the colors (base colors) */ + BackColor(blackColor); + ForeColor(whiteColor); + +#else /* ANGBAND_LITE_MAC */ + + /* Prepare the colors (real colors) */ + RGBBackColor(&black); + RGBForeColor(&white); + + /* Block */ + { + Rect tempRect; + Rect globalRect; + GDHandle mainGDH; + GDHandle currentGDH; + GWorldPtr windowGWorld; + PixMapHandle basePixMap; + + /* Obtain the rect */ + tempRect = td->w->portRect; + + /* Obtain the global rect */ + globalRect = tempRect; + LocalToGlobal((Point*)&globalRect.top); + LocalToGlobal((Point*)&globalRect.bottom); + + /* Obtain the proper GDH */ + mainGDH = GetMaxDevice(&globalRect); + + /* Extract GWorld and GDH */ + GetGWorld(&windowGWorld, ¤tGDH); + + /* Obtain base pixmap */ + basePixMap = (**mainGDH).gdPMap; + + /* Save pixel depth */ + td->pixelDepth = (**basePixMap).pixelSize; + + /* Save Window GWorld */ + td->theGWorld = windowGWorld; + + /* Save Window GDH */ + td->theGDH = currentGDH; + + /* Save main GDH */ + td->mainSWGDH = mainGDH; + } + +#endif /* ANGBAND_LITE_MAC */ + + /* Clip to the window */ + ClipRect(&td->w->portRect); + + /* Erase the window */ + EraseRect(&td->w->portRect); + + /* Invalidate the window */ + InvalRect(&td->w->portRect); + + /* Display the window if needed */ + if (td->mapped) ShowWindow(td->w); + + /* Hack -- set "mapped" flag */ + t->mapped_flag = td->mapped; + + /* Forget color */ + td->last = -1; +} + + + +/* + * Nuke an old Term + */ +static void Term_nuke_mac(term *t) +{ + +#pragma unused (t) + + /* XXX */ +} + + + +/* + * Unused + */ +static errr Term_user_mac(int n) +{ + +#pragma unused (n) + + /* Success */ + return (0); +} + + + +/* + * React to changes + */ +static errr Term_xtra_mac_react(void) +{ + term_data *td = (term_data*)(Term->data); + + int i; + + +#ifdef ANGBAND_LITE_MAC + + /* Nothing */ + +#else /* ANGBAND_LITE_MAC */ + + /* Reset color */ + td->last = -1; + + /* Update colors */ + for (i = 0; i < 256; i++) + { + u16b rv, gv, bv; + + /* Extract the R,G,B data */ + rv = angband_color_table[i][1]; + gv = angband_color_table[i][2]; + bv = angband_color_table[i][3]; + + /* Save the actual color */ + color_info[i].red = (rv | (rv << 8)); + color_info[i].green = (gv | (gv << 8)); + color_info[i].blue = (bv | (bv << 8)); + } + + /* Handle sound */ + if (use_sound != arg_sound) + { + /* Apply request */ + use_sound = arg_sound; + } + + /* Handle graphics */ + if (graf_mode_req != graf_mode) + { + /* dispose old GWorld's if present */ + globe_nuke(); + + /* Setup parameters according to request */ + switch (graf_mode_req) + { + /* ASCII - no graphics whatsoever */ + case GRAF_MODE_NONE: + { +#ifndef ZANGBAND + use_graphics = arg_graphics = FALSE; +#else +use_graphics = arg_graphics = GRAPHICS_NONE; +#endif /* !ZANGBAND */ + transparency_mode = TR_NONE; + break; + } + + /* + * 8x8 tiles (PICT id 1001) + * no transparency effect + * "old" graphics definitions + */ + case GRAF_MODE_8X8: + { +#ifndef ZANGBAND + use_graphics = arg_graphics = TRUE; + ANGBAND_GRAF = "old"; +#else + use_graphics = arg_graphics = GRAPHICS_ORIGINAL; +#endif /* !ZANGBAND */ + pictID = 1001; + transparency_mode = TR_NONE; + grafWidth = grafHeight = 8; + break; + } + + /* + * 16x16 tiles (images: PICT id 1002) + * with transparency effect + * "new" graphics definitions + */ + case GRAF_MODE_16X16: + { +#ifndef ZANGBAND + use_graphics = arg_graphics = TRUE; + ANGBAND_GRAF = "new"; +#else + use_graphics = arg_graphics = GRAPHICS_ADAM_BOLT; +#endif /* !ZANGBAND */ + pictID = 1002; + transparency_mode = TR_OVER; + grafWidth = grafHeight = 16; + break; + } + +#if 0 /* Good Lord! It doesn't work... Is it too large? */ + + /* + * 32x32 tiles (images: PICT id 1004) + * no transparency effect + * "david" graphics definitions + */ + case GRAF_MODE_32X32: + { + use_graphics = arg_graphics = TRUE; + ANGBAND_GRAF = "david"; + pictID = 1004; + transparency_mode = TR_OVER; + grafWidth = grafHeight = 32; + break; + } + +#endif /* sigh */ + } + + /* load tiles and setup GWorlds if tiles are requested */ + if ((graf_mode_req != GRAF_MODE_NONE) && (globe_init() != 0)) + { + /* Oops */ + plog("Cannot initialize graphics!"); + + /* reject request */ + graf_mode_req = GRAF_MODE_NONE; + + /* reset graphics flags */ + use_graphics = arg_graphics = FALSE; + + /* reset transparency mode */ + transparency_mode = TR_NONE; + } + + /* update current graphics mode */ + graf_mode = graf_mode_req; + + /* Apply and Verify */ + term_data_check_size(td); + + /* Resize the window */ + term_data_resize(td); + + /* Reset visuals */ +#ifndef ANG281_RESET_VISUALS + reset_visuals(TRUE); +#else +reset_visuals(); +#endif /* !ANG281_RESET_VISUALS */ + } + +#endif /* ANGBAND_LITE_MAC */ + + /* Success */ + return (0); +} + + +/* + * Do a "special thing" + */ +static errr Term_xtra_mac(int n, int v) +{ + term_data *td = (term_data*)(Term->data); + + Rect r; + + /* Analyze */ + switch (n) + { + /* Make a noise */ + case TERM_XTRA_NOISE: + { + /* Make a noise */ + SysBeep(1); + + /* Success */ + return (0); + } + +#ifdef ANGBAND_LITE_MAC + + /* Nothing */ + +#else /* ANGBAND_LITE_MAC */ + + /* Make a sound */ + case TERM_XTRA_SOUND: + { +#ifndef USE_ASYNC_SOUND + + /* + * This may not be your choice, but much safer and much less + * resource hungry. Existing implementations can quite easily + * crash, by starting asynchronous playing and immediately + * unlocking and releasing the sound data just started playing... + * -- pelpel + */ + Handle handle; + Str255 sound; + + /* Get the proper sound name */ + strnfmt((char*)sound + 1, 255, "%.16s.wav", angband_sound_name[v]); + sound[0] = strlen((char*)sound + 1); + + /* Obtain resource XXX XXX XXX */ + handle = GetNamedResource('snd ', sound); + + /* Oops -- it is a failure, but we return 0 anyway */ + if (handle == NULL) return (0); + + /* Load and Lock */ + LoadResource(handle); + HLock(handle); + + /* Play sound (wait for completion) */ + SndPlay(nil, (SndListHandle)handle, false); + + /* Unlock and release */ + HUnlock(handle); + ReleaseResource(handle); + +#else /* !USE_ASYNC_SOUND */ + + /* If you really want async player, please try this one */ + play_sound(v, sound_volume); + +#endif /* !USE_ASYNC_SOUND */ + + /* Success */ + return (0); + } + +#endif /* ANGBAND_LITE_MAC */ + + /* Process random events */ + case TERM_XTRA_BORED: + { + /* Process an event */ + (void)CheckEvents(FALSE); + + /* Success */ + return (0); + } + + /* Process pending events */ + case TERM_XTRA_EVENT: + { + /* Process an event */ + (void)CheckEvents(v); + + /* Success */ + return (0); + } + + /* Flush all pending events (if any) */ + case TERM_XTRA_FLUSH: + { + /* Hack -- flush all events */ + while (CheckEvents(TRUE)) /* loop */; + + /* Success */ + return (0); + } + + /* Hack -- Change the "soft level" */ + case TERM_XTRA_LEVEL: + { + /* Activate if requested */ + if (v) activate(td->w); + + /* Success */ + return (0); + } + + /* Clear the screen */ + case TERM_XTRA_CLEAR: + { + /* No clipping XXX XXX XXX */ + ClipRect(&td->w->portRect); + + /* Erase the window */ + EraseRect(&td->w->portRect); + + /* Set the color */ + term_data_color(td, TERM_WHITE); + + /* Frame the window in white */ + MoveTo(0, 0); + LineTo(0, td->size_hgt - 1); + LineTo(td->size_wid - 1, td->size_hgt - 1); + LineTo(td->size_wid - 1, 0); + + /* Clip to the new size */ + r.left = td->w->portRect.left + td->size_ow1; + r.top = td->w->portRect.top + td->size_oh1; + r.right = td->w->portRect.right - td->size_ow2; + r.bottom = td->w->portRect.bottom - td->size_oh2; + ClipRect(&r); + + /* Success */ + return (0); + } + + /* React to changes */ + case TERM_XTRA_REACT: + { + /* React to changes */ + return (Term_xtra_mac_react()); + } + + /* Delay (milliseconds) */ + case TERM_XTRA_DELAY: + { + /* If needed */ + if (v > 0) + { + long m = TickCount() + (v * 60L) / 1000; + + /* Wait for it */ + while (TickCount() < m) /* loop */; + } + + /* Success */ + return (0); + } + + /* Rename main window */ + case TERM_XTRA_RENAME_MAIN_WIN: + { + char *s = strdup(angband_term_name[0]); + + ctopstr((StringPtr)s); + SetWTitle(data[0].w, (StringPtr)s); + + free(s); + return (0); + } + } + + /* Oops */ + return (1); +} + + + +/* + * Low level graphics (Assumes valid input). + * Draw a "cursor" at (x,y), using a "yellow box". + * We are allowed to use "Term_what()" to determine + * the current screen contents (for inverting, etc). + */ +static errr Term_curs_mac(int x, int y) +{ + Rect r; + + term_data *td = (term_data*)(Term->data); + + /* Set the color */ + term_data_color(td, TERM_YELLOW); + + /* Frame the grid */ + r.left = x * td->tile_wid + td->size_ow1; + r.right = r.left + td->tile_wid; + r.top = y * td->tile_hgt + td->size_oh1; + r.bottom = r.top + td->tile_hgt; + +#ifdef USE_DOUBLE_TILES + + /* Mogami's double width tile patch */ + if (use_bigtile && + (x + 1 < Term->wid) && + (Term->old->a[y][x + 1] == 255)) + { + r.right += td->tile_wid; + } + +#endif /* USE_DOUBLE_TILES */ + + FrameRect(&r); + + /* Success */ + return (0); +} + + +/* + * Low level graphics (Assumes valid input) + * + * Erase "n" characters starting at (x,y) + */ +static errr Term_wipe_mac(int x, int y, int n) +{ + Rect r; + + term_data *td = (term_data*)(Term->data); + + /* Erase the block of characters */ + r.left = x * td->tile_wid + td->size_ow1; + r.right = r.left + n * td->tile_wid; + r.top = y * td->tile_hgt + td->size_oh1; + r.bottom = r.top + td->tile_hgt; + EraseRect(&r); + + /* Success */ + return (0); +} + + +/* + * Low level graphics. Assumes valid input. + * + * Draw several ("n") chars, with an attr, at a given location. + */ +static errr Term_text_mac(int x, int y, int n, byte a, const char *cp) +{ + int xp, yp; + + term_data *td = (term_data*)(Term->data); + + /* Set the color */ + term_data_color(td, a); + + /* Starting pixel */ + xp = x * td->tile_wid + td->tile_o_x + td->size_ow1; + yp = y * td->tile_hgt + td->tile_o_y + td->size_oh1; + + /* Move to the correct location */ + MoveTo(xp, yp); + + /* Draw the character */ + if (n == 1) DrawChar(*cp); + + /* Draw the string */ + else DrawText(cp, 0, n); + + /* Success */ + return (0); +} + + +/* + * Low level graphics (Assumes valid input) + * + * Erase "n" characters starting at (x,y) + */ +#ifdef USE_TRANSPARENCY +# ifdef USE_EGO_GRAPHICS +static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp, + const byte *tap, const char *tcp, + const byte *eap, const char *ecp) +# else /* USE_EGO_GRAPHICS */ +static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp, + const byte *tap, const char *tcp) +# endif /* USE_EGO_GRAPHICS */ +#else /* USE_TRANSPARENCY */ +static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp) +#endif /* USE_TRANSPARENCY */ +{ + int i; + Rect dst_r; + static RGBColor black = {0x0000, 0x0000, 0x0000}; + static RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; + term_data *td = (term_data*)(Term->data); + + /* Destination rectangle */ + dst_r.left = x * td->tile_wid + td->size_ow1; +#ifndef USE_DOUBLE_TILES + dst_r.right = dst_r.left + td->tile_wid; +#endif /* !USE_DOUBLE_TILES */ + dst_r.top = y * td->tile_hgt + td->size_oh1; + dst_r.bottom = dst_r.top + td->tile_hgt; + + /* Scan the input */ + for (i = 0; i < n; i++) + { + byte a = *ap++; + char c = *cp++; + +#ifdef USE_TRANSPARENCY + byte ta = *tap++; + char tc = *tcp++; +# ifdef USE_EGO_GRAPHICS + byte ea = *eap++; + char ec = *ecp++; + bool has_overlay = (ea && ec); +# endif /* USE_EGO_GRAPHICS */ +#endif /* USE_TRANSPARENCY */ + +#ifdef USE_DOUBLE_TILES + + /* Second byte of bigtile */ + if (use_bigtile && (a == 255)) + { + /* Advance */ + dst_r.left += td->tile_wid; + + /* Ignore it */ + continue; + } + + /* Prepare right side of rectangle */ + dst_r.right = dst_r.left + td->tile_wid; + +#endif /* USE_DOUBLE_TILES */ + +#ifdef ANGBAND_LITE_MAC + + /* Nothing */ + +#else /* ANGBAND_LITE_MAC */ + + /* Graphics -- if Available and Needed */ + if (use_graphics && ((byte)a & 0x80) && ((byte)c & 0x80)) + { +#ifdef USE_TRANSPARENCY + int t_col, t_row; + Rect terrain_r; +# ifdef USE_EGO_GRAPHICS + int e_col, e_row; + Rect ego_r; +# endif /* USE_EGO_GRAPHICS */ +#endif /* USE_TRANSPARENCY */ + + int col, row; + Rect src_r; + + /* Row and Col */ + row = ((byte)a & 0x7F) % pictRows; + col = ((byte)c & 0x7F) % pictCols; + + /* Source rectangle */ + src_r.left = col * grafWidth; + src_r.top = row * grafHeight; + src_r.right = src_r.left + grafWidth; + src_r.bottom = src_r.top + grafHeight; + +#ifdef USE_TRANSPARENCY + + /* Terrain Row and Col */ + t_row = ((byte)ta & 0x7F) % pictRows; + t_col = ((byte)tc & 0x7F) % pictCols; + + /* Terrain Source rectangle */ + terrain_r.left = t_col * grafWidth; + terrain_r.top = t_row * grafHeight; + terrain_r.right = terrain_r.left + grafWidth; + terrain_r.bottom = terrain_r.top + grafHeight; + +# ifdef USE_EGO_GRAPHICS + + /* If and only if there's overlay */ + if (has_overlay) + { + /* Overlay Row and Col */ + e_row = ((byte)ea & 0x7F) % pictRows; + e_col = ((byte)ec & 0x7F) % pictCols; + + /* Overlay Source rectangle */ + ego_r.left = e_col * grafWidth; + ego_r.top = e_row * grafHeight; + ego_r.right = ego_r.left + grafWidth; + ego_r.bottom = ego_r.top + grafHeight; + } + +# endif /* USE_EGO_GRAPHICS */ + +#endif /* USE_TRANSPARENCY */ + + /* Hardwire CopyBits */ + RGBBackColor(&white); + RGBForeColor(&black); + +#ifdef USE_DOUBLE_TILES + + /* Double width tiles */ + if (use_bigtile) dst_r.right += td->tile_wid; + +#endif /* USE_DOUBLE_TILES */ + +#ifdef USE_TRANSPARENCY + + /* Transparency effect */ + switch (transparency_mode) + { + /* No transparency effect */ + case TR_NONE: + default: + { + /* Draw the picture */ + CopyBits((BitMap*)frameP->framePix, + &(td->w->portBits), + &src_r, &dst_r, srcCopy, NULL); + + break; + } + + /* Overwriting with transparent black pixels */ + case TR_OVER: + { + /* Draw the terrain */ + CopyBits((BitMap*)frameP->framePix, + &(td->w->portBits), + &terrain_r, &dst_r, srcCopy, NULL); + + /* Make black pixels transparent */ + RGBBackColor(&black); + + /* Draw mon/obj if there's one */ + if ((row != t_row) || (col != t_col)) + CopyBits((BitMap*)frameP->framePix, + &(td->w->portBits), + &src_r, &dst_r, transparent, NULL); + +# ifdef USE_EGO_GRAPHICS + + /* Draw overlay if there's one */ + if (has_overlay) + CopyBits((BitMap*)frameP->framePix, + &(td->w->portBits), + &ego_r, &dst_r, transparent, NULL); + +# endif /* USE_EGO_GRAPHICS */ + + break; + } + } + +#else /* USE_TRANSPARENCY */ + +/* Draw the picture */ + CopyBits((BitMap*)frameP->framePix, + &(td->w->portBits), + &src_r, &dst_r, srcCopy, NULL); + +#endif /* USE_TRANSPARENCY */ + + /* Restore colors */ + RGBBackColor(&black); + RGBForeColor(&white); + + /* Forget color */ + td->last = -1; + } + +#endif /* ANGBAND_LITE_MAC */ + + /* Normal */ + else + { + int xp, yp; + + /* Erase */ + EraseRect(&dst_r); + + /* Set the color */ + term_data_color(td, a); + + /* Starting pixel */ + xp = dst_r.left + td->tile_o_x; + yp = dst_r.top + td->tile_o_y; + + /* Move to the correct location */ + MoveTo(xp, yp); + + /* Draw the character */ + DrawChar(c); + } + + /* Advance */ + dst_r.left += td->tile_wid; +#ifndef USE_DOUBLE_TILES + dst_r.right += td->tile_wid; +#endif /* USE_DOUBLE_TILES */ + } + + /* Success */ + return (0); +} + + + + + +/* + * Create and initialize window number "i" + */ +static void term_data_link(int i) +{ + term *old = Term; + + term_data *td = &data[i]; + + /* Only once */ + if (td->t) return; + + /* Require mapped */ + if (!td->mapped) return; + + /* Allocate */ + MAKE(td->t, term); + + /* Initialize the term */ + term_init(td->t, td->cols, td->rows, td->keys); + + /* Use a "software" cursor */ + td->t->soft_cursor = TRUE; + + /* Erase with "white space" */ + td->t->attr_blank = TERM_WHITE; + td->t->char_blank = ' '; + + /* Prepare the init/nuke hooks */ + td->t->init_hook = Term_init_mac; + td->t->nuke_hook = Term_nuke_mac; + + /* Prepare the function hooks */ + td->t->user_hook = Term_user_mac; + td->t->xtra_hook = Term_xtra_mac; + td->t->wipe_hook = Term_wipe_mac; + td->t->curs_hook = Term_curs_mac; + td->t->text_hook = Term_text_mac; + td->t->pict_hook = Term_pict_mac; + + /* Link the local structure */ + td->t->data = (void *)(td); + + /* Activate it */ + Term_activate(td->t); + + /* Global pointer */ + angband_term[i] = td->t; + + /* Activate old */ + Term_activate(old); +} + + + + +/* + * Set the "current working directory" (also known as the "default" + * volume/directory) to the location of the current application. + * + * Code by: Maarten Hazewinkel (mmhazewi@cs.ruu.nl) + * + * This function does not appear to work correctly with System 6. + */ +static void SetupAppDir(void) +{ + FCBPBRec fcbBlock; + OSErr err = noErr; + char errString[100]; + + /* Get the location of the Angband executable */ + fcbBlock.ioCompletion = NULL; + fcbBlock.ioNamePtr = NULL; + fcbBlock.ioVRefNum = 0; + fcbBlock.ioRefNum = CurResFile(); + fcbBlock.ioFCBIndx = 0; + err = PBGetFCBInfoSync(&fcbBlock); + if (err != noErr) + { + strnfmt(errString, 100, "Fatal PBGetFCBInfo Error #%d.\r Exiting.", err); + mac_warning(errString); + ExitToShell(); + } + + /* Extract the Vol and Dir */ + app_vol = fcbBlock.ioFCBVRefNum; + app_dir = fcbBlock.ioFCBParID; + + /* Set the current working directory to that location */ + err = HSetVol(NULL, app_vol, app_dir); + if (err != noErr) + { + strnfmt(errString, 100, "Fatal HSetVol Error #%d.\r Exiting.", err); + mac_warning(errString); + ExitToShell(); + } +} + + + + +/* + * Global "preference" file pointer + */ +static FILE *fff; + +/* + * Read a "short" from the file + */ +static int getshort(void) +{ + int x = 0; + char buf[256]; + if (0 == my_fgets(fff, buf, 256)) x = atoi(buf); + return (x); +} + +/* + * Dump a "short" to the file + */ +static void putshort(int x) +{ + fprintf(fff, "%d\n", x); +} + + + +/* + * Write the "preference" data to the current "file" + */ +static void save_prefs(void) +{ + int i; + + term_data *td; + + + /*** The current version ***/ + + putshort(PREF_VER_MAJOR); + putshort(PREF_VER_MINOR); + putshort(PREF_VER_PATCH); + putshort(PREF_VER_EXTRA); + + /* Gfx settings */ + putshort(arg_sound); + putshort(graf_mode); +#ifdef USE_DOUBLE_TILES + putshort(use_bigtile); +#endif /* USE_DOUBLE_TILES */ + + /* Dump */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + /* Access */ + td = &data[i]; + + putshort(td->mapped); + + putshort(td->font_id); + putshort(td->font_size); + putshort(td->font_face); + + putshort(td->tile_wid); + putshort(td->tile_hgt); + + putshort(td->cols); + putshort(td->rows); + + putshort(td->r.left); + putshort(td->r.top); + } +} + + +/* + * Load the preferences from the current "file" + * + * XXX XXX XXX Being able to undefine various windows is + * slightly bizarre, and may cause problems. + */ +static void load_prefs(void) +{ + int i; + + int old_major, old_minor, old_patch, old_extra; + + term_data *td; + + + /*** Version information ***/ + + /* Preferences version */ + old_major = getshort(); + old_minor = getshort(); + old_patch = getshort(); + old_extra = getshort(); + + /* Hack -- Verify or ignore */ + if ((old_major != PREF_VER_MAJOR) || + (old_minor != PREF_VER_MINOR) || + (old_patch != PREF_VER_PATCH) || + (old_extra != PREF_VER_EXTRA)) + { + /* Message */ + mac_warning("Ignoring old preferences."); + + /* Ignore */ + return; + } + + /* Gfx mode */ + arg_sound = getshort(); + graf_mode_req = getshort(); +#ifdef USE_DOUBLE_TILES + use_bigtile = getshort(); +#endif /* USE_DOUBLE_TILES */ + + /* Windows */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + /* Access */ + td = &data[i]; + + td->mapped = getshort(); + + td->font_id = getshort(); + td->font_size = getshort(); + td->font_face = getshort(); + + td->tile_wid = getshort(); + td->tile_hgt = getshort(); + + td->cols = getshort(); + td->rows = getshort(); + + td->r.left = getshort(); + td->r.top = getshort(); + + /* Done */ + if (feof(fff)) break; + } +} + + + + +/* + * Hack -- default data for a window + */ +static void term_data_hack(term_data *td) +{ + short fid; + + /* Default to Monaco font */ + GetFNum("\pmonaco", &fid); + + /* Wipe it */ + WIPE(td, term_data); + + /* No color */ + td->last = -1; + + /* Default borders */ + td->size_ow1 = 2; + td->size_ow2 = 2; + td->size_oh2 = 2; + + /* Start hidden */ + td->mapped = FALSE; + + /* Default font */ + td->font_id = fid; + + /* Default font size */ + td->font_size = 12; + + /* Default font face */ + td->font_face = 0; + + /* Default size */ + td->rows = 24; + td->cols = 80; + + /* Default position */ + td->r.left = 10; + td->r.top = 40; + + /* Minimal keys */ + td->keys = 16; +} + + +/* + * Read the preference file, Create the windows. + * + * We attempt to use "FindFolder()" to track down the preference file, + * but if this fails, for any reason, we will try the "SysEnvirons()" + * method, which may work better with System 6. + */ +static void init_windows(void) +{ + int i, b = 0; + + term_data *td; + + bool oops; + + + /*** Default values ***/ + + /* Initialize (backwards) */ + for (i = MAX_TERM_DATA; i-- > 0; ) + { + int n; + + cptr s; + + /* Obtain */ + td = &data[i]; + + /* Defaults */ + term_data_hack(td); + + /* Obtain title */ + s = angband_term_name[i]; + + /* Get length */ + n = strlen(s); + + /* Maximal length */ + if (n > 15) n = 15; + + /* Copy the title */ + strncpy((char*)(td->title) + 1, s, n); + + /* Save the length */ + td->title[0] = n; + + /* Tile the windows */ + td->r.left += (b * 30); + td->r.top += (b * 30); + + /* Tile */ + b++; + } + + + /*** Load preferences ***/ + + /* Assume failure */ + oops = TRUE; + + /* Assume failure */ + fff = NULL; + +#ifdef USE_SFL_CODE + + /* Block */ + if (TRUE) + { + OSErr err; + short vref; + long dirID; + char foo[128]; + + /* Find the folder */ + err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, + &vref, &dirID); + + /* Success */ + if (!err) + { + /* Extract a path name */ + PathNameFromDirID(dirID, vref, (StringPtr)foo); + + /* Convert the string */ + ptocstr((StringPtr)foo); + + /* Append the preference file name */ + strcat(foo, ANGBAND_PREFERENCES); + + /* Open the preference file */ + fff = fopen(foo, "r"); + + /* Success */ + oops = FALSE; + } + } + +#endif /* USE_SFL_CODE */ + +#if 0 /* SysEnvirons? SetVol? I'd say no */ + + /* Oops */ + if (oops) + { + SysEnvRec env; + short savev; + long saved; + + /* Save */ + HGetVol(0, &savev, &saved); + + /* Go to the "system" folder */ + SysEnvirons(curSysEnvVers, &env); + SetVol(0, env.sysVRefNum); + + /* Open the file */ + fff = fopen(":Preferences:" ANGBAND_PREFERENCES, "r"); + if (!fff) fff = fopen(":" ANGBAND_PREFERENCES, "r"); + + /* Restore */ + HSetVol(0, savev, saved); + } + +#endif /* relic */ + + /* Load preferences */ + if (fff) + { + /* Load a real preference file */ + load_prefs(); + + /* Close the file */ + my_fclose(fff); + } + + + /*** Instantiate ***/ + + /* Main window */ + td = &data[0]; + + /* Many keys */ + td->keys = 1024; + + /* Start visible */ + td->mapped = TRUE; + + /* Link (backwards, for stacking order) */ + for (i = MAX_TERM_DATA; i-- > 0; ) + { + term_data_link(i); + } + + /* Main window */ + td = &data[0]; + + /* Main window */ + Term_activate(td->t); +} + + +/* + * Exit the program + */ +static void save_pref_file(void) +{ + bool oops; + + + /* Assume failure */ + oops = TRUE; + + /* Assume failure */ + fff = NULL; + + /* Text file */ + _ftype = 'TEXT'; + + +#ifdef USE_SFL_CODE + + /* Block */ + if (TRUE) + { + OSErr err; + short vref; + long dirID; + char foo[128]; + + /* Find the folder */ + err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, + &vref, &dirID); + + /* Success */ + if (!err) + { + /* Extract a path name */ + PathNameFromDirID(dirID, vref, (StringPtr)foo); + + /* Convert the string */ + ptocstr((StringPtr)foo); + + /* Append the preference file name */ + strcat(foo, ANGBAND_PREFERENCES); + + /* Open the preference file */ + fff = fopen(foo, "w"); + + /* Success */ + oops = FALSE; + } + } + +#endif /* USE_SFL_CODE */ + +#if 0 /* I don't believe we need SysEnvirons any longer */ + + /* Oops */ + if (oops) + { + SysEnvRec env; + short savev; + long saved; + + /* Save */ + HGetVol(0, &savev, &saved); + + /* Go to "system" folder */ + SysEnvirons(curSysEnvVers, &env); + SetVol(0, env.sysVRefNum); + + /* Open the preference file */ + fff = fopen(":Preferences:" ANGBAND_PREFERENCES, "w"); + if (!fff) fff = fopen(":" ANGBAND_PREFERENCES, "w"); + + /* Restore */ + HSetVol(0, savev, saved); + } + +#endif /* relic */ + + /* Save preferences */ + if (fff) + { + /* Write the preferences */ + save_prefs(); + + /* Close it */ + my_fclose(fff); + } +} + + + +#ifdef ALLOW_NO_SAVE_QUITS + +/* + * A simple "Yes/No" filter to parse "key press" events in dialog windows + */ +static pascal Boolean ynfilter(DialogPtr dialog, EventRecord *event, short *ip) +{ + /* Parse key press events */ + if (event->what == keyDown) + { + int i = 0; + char c; + + /* Extract the pressed key */ + c = (event->message & charCodeMask); + + /* Accept "no" and and */ + if ((c == 'n') || (c == 'N') || (c == 13) || (c == 3)) i = 1; + + /* Accept "yes" */ + else if ((c == 'y') || (c == 'Y')) i = 2; + + /* Handle "yes" or "no" */ + if (i) + { + short type; + ControlHandle control; + Rect r; + + /* Get the button */ + GetDialogItem(dialog, i, &type, (Handle*)&control, &r); + + /* Blink button for 1/10 second */ + HiliteControl(control, 1); + Term_xtra_mac(TERM_XTRA_DELAY, 100); + HiliteControl(control, 0); + + /* Result */ + *ip = i; + return (1); + } + } + + /* Ignore */ + return (0); +} + +#endif /* ALLOW_NO_SAVE_QUITS */ + + + +#ifndef SAVEFILE_SCREEN + +/* + * Handle menu: "File" + "New" + */ +static void do_menu_file_new(void) +{ + /* Hack */ + HiliteMenu(0); + + /* Game is in progress */ + game_in_progress = 1; + + /* Flush input */ + Term_flush(); + + /* Play a game */ + play_game(TRUE); + + /* Hack -- quit */ + quit(NULL); +} + +/* + * Handle menu: "File" + "Open" + */ +static void do_menu_file_open(bool all) +{ + int err; + short vrefnum; + long drefnum; + long junk; + DirInfo pb; + SFTypeList types; + SFReply reply; + Point topleft; + + + /* XXX XXX XXX */ + + /* vrefnum = GetSFCurVol(); */ + vrefnum = -*((short*)0x214); + + /* drefnum = GetSFCurDir(); */ + drefnum = *((long*)0x398); + + /* Descend into "lib" folder */ + pb.ioCompletion = NULL; + pb.ioNamePtr = "\plib"; + pb.ioVRefNum = vrefnum; + pb.ioDrDirID = drefnum; + pb.ioFDirIndex = 0; + + /* Check for errors */ + err = PBGetCatInfoSync((CInfoPBPtr) & pb); + + /* Success */ + if ((err == noErr) && (pb.ioFlAttrib & 0x10)) + { + /* Descend into "lib/save" folder */ + pb.ioCompletion = NULL; + pb.ioNamePtr = "\psave"; + pb.ioVRefNum = vrefnum; + pb.ioDrDirID = pb.ioDrDirID; + pb.ioFDirIndex = 0; + + /* Check for errors */ + err = PBGetCatInfoSync((CInfoPBPtr) & pb); + + /* Success */ + if ((err == noErr) && (pb.ioFlAttrib & 0x10)) + { + /* SetSFCurDir(pb.ioDrDirID); */ + *((long*)0x398) = pb.ioDrDirID; + } + } + + /* Window location */ + topleft.h = (qd.screenBits.bounds.left + qd.screenBits.bounds.right) / 2 - 344 / 2; + topleft.v = (2 * qd.screenBits.bounds.top + qd.screenBits.bounds.bottom) / 3 - 188 / 2; + + /* Allow "all" files */ + if (all) + { + /* Get any file */ + SFGetFile(topleft, "\p", NULL, -1, types, NULL, &reply); + } + + /* Allow "save" files */ + else + { + /* Legal types */ + types[0] = 'SAVE'; + + /* Get a file */ + SFGetFile(topleft, "\p", NULL, 1, types, NULL, &reply); + } + + /* Allow cancel */ + if (!reply.good) return; + + /* Extract textual file name for save file */ + GetWDInfo(reply.vRefNum, &vrefnum, &drefnum, &junk); + refnum_to_name(savefile, drefnum, vrefnum, (char*)reply.fName); + + /* Hack */ + HiliteMenu(0); + + /* Game is in progress */ + game_in_progress = 1; + + /* Flush input */ + flush(); + + /* Play a game */ + play_game(FALSE); + + /* Hack -- quit */ + quit(NULL); +} + +#endif /* !SAVEFILE_SCREEN */ + + +/* + * Handle the "open_when_ready" flag + */ +static void handle_open_when_ready(void) +{ + /* Check the flag XXX XXX XXX make a function for this */ + if (open_when_ready && initialized && !game_in_progress) + { + /* Forget */ + open_when_ready = FALSE; + + /* Game is in progress */ + game_in_progress = 1; + + /* Wait for it */ + pause_line(23); + + /* Flush input */ + flush(); + +#ifdef SAVEFILE_SCREEN + + /* User double-clicked savefile; no savefile screen */ + no_begin_screen = TRUE; + +#endif /* SAVEFILE_SCREEN */ + + /* Play a game */ + play_game(FALSE); + + /* Quit */ + quit(NULL); + } +} + + + +/* + * The standard menus are: + * + * Apple (128) = { About, -, ... } + * File (129) = { New,Open,Import,Close,Save,-,Score,Exit,Quit } + * In ToME, this becomes + * File (129) = { Close,Save,-,Score,Exit,Quit } + * Edit (130) = { Cut, Copy, Paste, Clear } (?) + * Font (131) = { Bold, Extend, -, Monaco, ..., -, ... } + * Size (132) = { ... } + * Window (133) = { Angband, Term-1/Mirror, Term-2/Recall, Term-3/Choice, + * Term-4, Term-5, Term-6, Term-7 } + * Special (134) = { Sound, Graphics, TileWidth, TileHeight, -, + * Fiddle, Wizard } + */ + +/* Apple menu */ +#define MENU_APPLE 128 +#define ITEM_ABOUT 1 + +/* File menu */ +#define MENU_FILE 129 +#ifndef SAVEFILE_SCREEN +# define ITEM_NEW 1 +# define ITEM_OPEN 2 +# define ITEM_IMPORT 3 +# define ITEM_CLOSE 4 +# define ITEM_SAVE 5 +# ifdef HAS_SCORE_MENU +# define ITEM_SCORE 7 +# define ITEM_EXIT 8 +# define ITEM_QUIT 9 +# else +# define ITEM_EXIT 7 +# define ITEM_QUIT 8 +# endif /* HAS_SCORE_MENU */ +#else /* !SAVEFILE_SCREEN - in-game savefile menu */ +# define ITEM_CLOSE 1 +# define ITEM_SAVE 2 +# ifdef HAS_SCORE_MENU +# define ITEM_SCORE 4 +# define ITEM_EXIT 5 +# define ITEM_QUIT 6 +# else +# define ITEM_EXIT 4 +# define ITEM_QUIT 5 +# endif /* HAS_SCORE_MENU */ +#endif /* !SAVEFILE_SCREEN */ + +/* Edit menu */ +#define MENU_EDIT 130 +#define ITEM_UNDO 1 +#define ITEM_CUT 3 +#define ITEM_COPY 4 +#define ITEM_PASTE 5 +#define ITEM_CLEAR 6 + +/* Font menu */ +#define MENU_FONT 131 +#define ITEM_BOLD 1 +#define ITEM_WIDE 2 + +/* Size menu */ +#define MENU_SIZE 132 + +/* Windows menu */ +#define MENU_WINDOWS 133 + +/* Special menu */ +#define MENU_SPECIAL 134 +#define ITEM_SOUND 1 +#define ITEM_GRAPH 2 +#define ITEM_TILEWIDTH 3 +#define ITEM_TILEHEIGHT 4 +#define ITEM_FIDDLE 6 +#define ITEM_WIZARD 7 + +/* Graphics submenu */ +#define SUBMENU_GRAPH 144 +#define ITEM_NONE 1 +#define ITEM_8X8 2 +#define ITEM_16X16 3 +#define ITEM_BIGTILE 5 + +/* TileWidth submenu */ +#define SUBMENU_TILEWIDTH 145 + +/* TileHeight submenu */ +#define SUBMENU_TILEHEIGHT 146 + + +/* + * Initialize the menus + */ +static void init_menubar(void) +{ + int i, n; + + Rect r; + + WindowPtr tmpw; + + MenuHandle m; + + Handle mbar; + + + /* Load menubar from resources */ + mbar = GetNewMBar(128); + + /* Whoops! */ + if (mbar == nil) quit("Cannot find menubar('MBAR') id 128!"); + + /* Insert them into the current menu list */ + SetMenuBar(mbar); + + /* Free handle */ + DisposeHandle(mbar); + + + /* Apple menu (id 128) */ + m = GetMenuHandle(MENU_APPLE); + + /* Add the DA's to the "apple" menu */ + AppendResMenu(m, 'DRVR'); + + + /* File menu (id 129) - we don't have to do anything */ + + + /* Edit menu (id 130) - we don't have to do anything */ + + + /* + * Font menu (id 131) - append names of mono-spaced fonts + * followed by all available ones + */ + m = GetMenuHandle(MENU_FONT); + + /* Fake window */ + r.left = r.right = r.top = r.bottom = 0; + + /* Make the fake window so that we can retrive font info */ + tmpw = NewWindow(0, &r, "\p", false, documentProc, 0, 0, 0); + + /* Activate the "fake" window */ + SetPort(tmpw); + + /* Default mode */ + TextMode(0); + + /* Default size */ + TextSize(12); + + /* Add the fonts to the menu */ + AppendResMenu(m, 'FONT'); + + /* Size of menu */ + n = CountMItems(m); + + /* Scan the menu */ + for (i = n; i >= 4; i--) + { + Str255 tmpName; + short fontNum; + + /* Acquire the font name */ + GetMenuItemText(m, i, tmpName); + + /* Acquire the font index */ + GetFNum(tmpName, &fontNum); + + /* Apply the font index */ + TextFont(fontNum); + + /* Remove non-mono-spaced fonts */ + if ((CharWidth('i') != CharWidth('W')) || (CharWidth('W') == 0)) + { + /* Delete the menu item */ + DeleteMenuItem(m, i); + } + } + + /* Destroy the old window */ + DisposeWindow(tmpw); + + /* Add a separator */ + AppendMenu(m, "\p-"); + + /* Add the fonts to the menu */ + AppendResMenu(m, 'FONT'); + + + /* Size menu (id 132) */ + m = GetMenuHandle(MENU_SIZE); + + /* Add some sizes (stagger choices) */ + for (i = 8; i <= 32; i += ((i / 16) + 1)) + { + Str15 buf; + + /* Textual size */ + strnfmt((char*)buf + 1, 15, "%d", i); + buf[0] = strlen((char*)buf + 1); + + /* Add the item */ + AppendMenu(m, buf); + } + + + /* Windows menu (id 133) */ + m = GetMenuHandle(MENU_WINDOWS); + + /* Default choices */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + Str15 buf; + + /* Describe the item */ + strnfmt((char*)buf + 1, 15, "%.15s", angband_term_name[i]); + buf[0] = strlen((char*)buf + 1); + + /* Add the item */ + AppendMenu(m, buf); + + /* Command-Key shortcuts */ + if (i < 8) SetItemCmd(m, i + 1, I2D(i)); + } + + + /* Special menu (id 134) */ + + /* Get graphics (sub)menu (id 144) */ + m = GetMenu(SUBMENU_GRAPH); + + /* Insert it as a submenu */ + InsertMenu(m, hierMenu); + + + /* Get TileWidth (sub)menu (id 145) */ + m = GetMenu(SUBMENU_TILEWIDTH); + + /* Add some sizes */ + for (i = 4; i <= 32; i++) + { + Str15 buf; + + /* Textual size */ + strnfmt((char*)buf + 1, 15, "%d", i); + buf[0] = strlen((char*)buf + 1); + + /* Append item */ + AppendMenu(m, buf); + } + + /* Insert it as a submenu */ + InsertMenu(m, hierMenu); + + /* Get TileHeight (sub)menu (id 146) */ + m = GetMenu(SUBMENU_TILEHEIGHT); + + /* Add some sizes */ + for (i = 4; i <= 32; i++) + { + Str15 buf; + + /* Textual size */ + strnfmt((char*)buf + 1, 15, "%d", i); + buf[0] = strlen((char*)buf + 1); + + /* Append item */ + AppendMenu(m, buf); + } + + /* Insert it as a submenu */ + InsertMenu(m, hierMenu); + + + /* Update the menu bar */ + DrawMenuBar(); +} + + +/* + * Prepare the menus + * + * It is very important that the player not be allowed to "save" the game + * unless the "inkey_flag" variable is set, indicating that the game is + * waiting for a new command. XXX XXX XXX + */ +static void setup_menus(void) +{ + int i, n; + + short value; + + Str255 s; + + MenuHandle m; + + term_data *td = NULL; + + + /* Relevant "term_data" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + /* Unused */ + if (!data[i].t) continue; + + /* Notice the matching window */ + if (data[i].w == FrontWindow()) td = &data[i]; + } + + + /* File menu */ + m = GetMenuHandle(MENU_FILE); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + CheckItem(m, i, FALSE); + } + +#ifndef SAVEFILE_SCREEN + + /* Enable "new"/"open..."/"import..." */ + if (initialized && !game_in_progress) + { + EnableItem(m, ITEM_NEW); + EnableItem(m, ITEM_OPEN); + EnableItem(m, ITEM_IMPORT); + } + +#endif /* !SAVEFILE_SCREEN */ + + /* Enable "close" */ + if (initialized) + { + EnableItem(m, ITEM_CLOSE); + } + + /* Enable "save" */ + if (initialized && character_generated && inkey_flag) + { + EnableItem(m, ITEM_SAVE); + } + +#ifdef HAS_SCORE_MENU + + /* Enable "score" */ + if (initialized && character_generated && !character_icky) + { + EnableItem(m, ITEM_SCORE); + } + +#endif /* HAS_SCORE_MENU */ + +#ifdef ALLOW_NO_SAVE_QUITS + + /* Enable "exit" */ + if (TRUE) + { + EnableItem(m, ITEM_EXIT); + } + +#endif /* ALLOW_NO_SAVE_QUITS */ + + /* Enable "quit" */ + if (!initialized || !character_generated || inkey_flag) + { + EnableItem(m, ITEM_QUIT); + } + + + /* Edit menu */ + m = GetMenuHandle(MENU_EDIT); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + CheckItem(m, i, FALSE); + } + + /* Enable "edit" options if "needed" */ + if (!td) + { + EnableItem(m, ITEM_UNDO); + EnableItem(m, ITEM_CUT); + EnableItem(m, ITEM_COPY); + EnableItem(m, ITEM_PASTE); + EnableItem(m, ITEM_CLEAR); + } + + + /* Font menu */ + m = GetMenuHandle(MENU_FONT); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + CheckItem(m, i, FALSE); + } + + /* Hack -- look cute XXX XXX */ + /* SetItemStyle(m, ITEM_BOLD, bold); */ + + /* Hack -- look cute XXX XXX */ + /* SetItemStyle(m, ITEM_WIDE, extend); */ + + /* Active window */ + if (initialized && td) + { + /* Enable "bold" */ + EnableItem(m, ITEM_BOLD); + + /* Enable "extend" */ + EnableItem(m, ITEM_WIDE); + + /* Check the appropriate "bold-ness" */ + if (td->font_face & bold) CheckItem(m, ITEM_BOLD, TRUE); + + /* Check the appropriate "wide-ness" */ + if (td->font_face & extend) CheckItem(m, ITEM_WIDE, TRUE); + + /* Analyze fonts */ + for (i = 4; i <= n; i++) + { + /* Enable it */ + EnableItem(m, i); + + /* Analyze font */ + GetMenuItemText(m, i, s); + GetFNum(s, &value); + + /* Check active font */ + if (td->font_id == value) CheckItem(m, i, TRUE); + } + } + + + /* Size menu */ + m = GetMenuHandle(MENU_SIZE); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + CheckItem(m, i, FALSE); + } + + /* Active window */ + if (initialized && td) + { + /* Analyze sizes */ + for (i = 1; i <= n; i++) + { + /* Analyze size */ + GetMenuItemText(m, i, s); + s[s[0] + 1] = '\0'; + value = atoi((char*)(s + 1)); + + /* Enable the "real" sizes */ + if (RealFont(td->font_id, value)) EnableItem(m, i); + + /* Check the current size */ + if (td->font_size == value) CheckItem(m, i, TRUE); + } + } + + + /* Windows menu */ + m = GetMenuHandle(MENU_WINDOWS); + + /* Get menu size */ + n = CountMItems(m); + + /* Check active windows */ + for (i = 1; i <= n; i++) + { + /* Check if needed */ + CheckItem(m, i, data[i - 1].mapped); + } + + + /* Special menu */ + m = GetMenuHandle(MENU_SPECIAL); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + + /* XXX Oh no, this removes submenu... */ + if ((i != ITEM_GRAPH) && + (i != ITEM_TILEWIDTH) && + (i != ITEM_TILEHEIGHT)) CheckItem(m, i, FALSE); + } + + /* Item "Sound" */ + EnableItem(m, ITEM_SOUND); + CheckItem(m, ITEM_SOUND, arg_sound); + + /* Item "Graphics" */ + EnableItem(m, ITEM_GRAPH); + + /* Item "TileWidth" */ + EnableItem(m, ITEM_TILEWIDTH); + + /* Item "TileHeight" */ + EnableItem(m, ITEM_TILEHEIGHT); + + /* Item "Fiddle" */ + EnableItem(m, ITEM_FIDDLE); + CheckItem(m, ITEM_FIDDLE, arg_fiddle); + + /* Item "Wizard" */ + EnableItem(m, ITEM_WIZARD); + CheckItem(m, ITEM_WIZARD, arg_wizard); + + /* Graphics submenu */ + m = GetMenuHandle(SUBMENU_GRAPH); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + CheckItem(m, i, FALSE); + } + + /* Item "None" */ + EnableItem(m, ITEM_NONE); + CheckItem(m, ITEM_NONE, (graf_mode == GRAF_MODE_NONE)); + + /* Item "8x8" */ + EnableItem(m, ITEM_8X8); + CheckItem(m, ITEM_8X8, (graf_mode == GRAF_MODE_8X8)); + + /* Item "16x16" */ + EnableItem(m, ITEM_16X16); + CheckItem(m, ITEM_16X16, (graf_mode == GRAF_MODE_16X16)); + +#ifdef USE_DOUBLE_TILES + + /* Item "Bigtile" */ + if (inkey_flag) EnableItem(m, ITEM_BIGTILE); + CheckItem(m, ITEM_BIGTILE, use_bigtile); + +#endif /* USE_DOUBLE_TILES */ + + + /* TIleWidth submenu */ + m = GetMenuHandle(SUBMENU_TILEWIDTH); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + CheckItem(m, i, FALSE); + } + + /* Active window */ + if (initialized && td) + { + /* Analyze sizes */ + for (i = 1; i <= n; i++) + { + /* Analyze size */ + GetMenuItemText(m, i, s); + s[s[0] + 1] = '\0'; + value = atoi((char*)(s + 1)); + + /* Enable */ + if (value >= td->font_wid) EnableItem(m, i); + + /* Check the current size */ + if (td->tile_wid == value) CheckItem(m, i, TRUE); + } + } + + + /* TileHeight submenu */ + m = GetMenuHandle(SUBMENU_TILEHEIGHT); + + /* Get menu size */ + n = CountMItems(m); + + /* Reset menu */ + for (i = 1; i <= n; i++) + { + /* Reset */ + DisableItem(m, i); + CheckItem(m, i, FALSE); + } + + /* Active window */ + if (initialized && td) + { + /* Analyze sizes */ + for (i = 1; i <= n; i++) + { + /* Analyze size */ + GetMenuItemText(m, i, s); + s[s[0] + 1] = '\0'; + value = atoi((char*)(s + 1)); + + /* Enable */ + if (value >= td->font_hgt) EnableItem(m, i); + + /* Check the current size */ + if (td->tile_hgt == value) CheckItem(m, i, TRUE); + } + } +} + + +/* + * Process a menu selection (see above) + * + * Hack -- assume that invalid menu selections are disabled above, + * which I have been informed may not be reliable. XXX XXX XXX + */ +static void menu(long mc) +{ + int i; + + int menuid, selection; + + static unsigned char s[1000]; + + short fid; + + term_data *td = NULL; + + WindowPtr old_win; + + + /* Analyze the menu command */ + menuid = HiWord(mc); + selection = LoWord(mc); + + + /* Find the window */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + /* Skip dead windows */ + if (!data[i].t) continue; + + /* Notice matches */ + if (data[i].w == FrontWindow()) td = &data[i]; + } + + + /* Branch on the menu */ + switch (menuid) + { + /* Apple Menu */ + case MENU_APPLE: + { + /* About Angband... */ + if (selection == ITEM_ABOUT) + { + DialogPtr dialog; + Rect r; + short item_hit; + + dialog = GetNewDialog(128, 0, (WindowPtr) - 1); + + r = dialog->portRect; + center_rect(&r, &qd.screenBits.bounds); + MoveWindow(dialog, r.left, r.top, 1); + ShowWindow(dialog); + ModalDialog(0, &item_hit); + DisposeDialog(dialog); + break; + } + + /* Desk accessory */ + GetMenuItemText(GetMenuHandle(MENU_APPLE), selection, s); + OpenDeskAcc(s); + break; + } + + + /* File Menu */ + case MENU_FILE: + { + switch (selection) + { +#ifndef SAVEFILE_SCREEN + + /* New */ + case ITEM_NEW: + { + do_menu_file_new(); + break; + } + + /* Open... */ + case ITEM_OPEN: + { + do_menu_file_open(FALSE); + break; + } + + /* Import... */ + case ITEM_IMPORT: + { + do_menu_file_open(TRUE); + break; + } + +#endif /* !SAVEFILE_SCREEN */ + + /* Close */ + case ITEM_CLOSE: + { + /* No window */ + if (!td) break; + + /* Not Mapped */ + td->mapped = FALSE; + + /* Not Mapped */ + td->t->mapped_flag = FALSE; + + /* Hide the window */ + HideWindow(td->w); + + break; + } + + /* Save */ + case ITEM_SAVE: + { + /* Hack -- Forget messages */ + msg_flag = FALSE; + + /* Hack -- Save the game */ +#ifndef ZANG_AUTO_SAVE + do_cmd_save_game(); +#else +do_cmd_save_game(FALSE); +#endif /* !ZANG_AUTO_SAVE */ + + break; + } + +#ifdef HAS_SCORE_MENU + + /* Show score */ + case ITEM_SCORE: + { + char buf[1024]; + + /* Paranoia */ + if (!initialized || character_icky || + !game_in_progress || !character_generated) + { + /* Can't happen but just in case */ + plog("You may not do that right now."); + + break; + } + + /* Build the pathname of the score file */ + path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, + "scores.raw"); + + /* Hack - open the score file for reading */ + highscore_fd = fd_open(buf, O_RDONLY); + + /* Paranoia - No score file */ + if (highscore_fd < 0) + { + msg_print("Score file is not available."); + + break; + } + + /* Mega-Hack - prevent various functions XXX XXX XXX */ + initialized = FALSE; + + /* Save screen */ + screen_save(); + + /* Clear screen */ + Term_clear(); + + /* Prepare scores */ + if (game_in_progress && character_generated) + { + predict_score(); + } + +#if 0 /* I don't like this - pelpel */ + + /* Mega-Hack - No current player XXX XXX XXX XXX */ + else + { + display_scores_aux(0, MAX_HISCORES, -1, NULL); + } + +#endif + + /* Close the high score file */ + (void)fd_close(highscore_fd); + + /* Forget the fd */ + highscore_fd = -1; + + /* Restore screen */ + screen_load(); + + /* Hack - Flush it */ + Term_fresh(); + + /* Mega-Hack - We are ready again */ + initialized = TRUE; + + /* Done */ + break; + } + +#endif /* HAS_SCORE_MENU */ + +#ifdef ALLOW_NO_SAVE_QUITS + + /* Exit (without save) */ + case ITEM_EXIT: + { + /* Allow user to cancel "dangerous" exit */ + if (game_in_progress && character_generated) + { + AlertTHndl alert; + short item_hit; + + /* Get the "alert" info */ + alert = (AlertTHndl)GetResource('ALRT', 130); + + /* Center the "alert" rectangle */ + center_rect(&(*alert)->boundsRect, + &qd.screenBits.bounds); + + /* Display the Alert, get "No" or "Yes" */ + item_hit = Alert(130, ynfilterUPP); + + /* Require "yes" button */ + if (item_hit != 2) break; + } + + /* Quit */ + quit(NULL); + break; + } + +#endif /* ALLOW_NO_SAVE_QUITS */ + + /* Quit (with save) */ + case ITEM_QUIT: + { + /* Save the game (if necessary) */ + if (game_in_progress && character_generated) + { + /* Hack -- Forget messages */ + msg_flag = FALSE; + + /* Save the game */ +#ifndef ZANG_AUTO_SAVE + do_cmd_save_game(); +#else + do_cmd_save_game(FALSE); +#endif /* !ZANG_AUTO_SAVE */ + } + + /* Quit */ + quit(NULL); + break; + } + } + + break; + } + + + /* Edit menu */ + case MENU_EDIT: + { + /* Unused */ + break; + } + + + /* Font menu */ + case MENU_FONT: + { + /* Require a window */ + if (!td) break; + + /* Memorize old */ + old_win = active; + + /* Activate */ + activate(td->w); + + /* Toggle the "bold" setting */ + if (selection == ITEM_BOLD) + { + /* Toggle the setting */ + if (td->font_face & bold) + { + td->font_face &= ~bold; + } + else + { + td->font_face |= bold; + } + + /* Hack - clear tile size info XXX XXX */ + td->tile_wid = td->tile_hgt = 0; + + /* Apply and Verify */ + term_data_check_font(td); + term_data_check_size(td); + + /* Resize and Redraw */ + term_data_resize(td); + term_data_redraw(td); + + break; + } + + /* Toggle the "wide" setting */ + if (selection == ITEM_WIDE) + { + /* Toggle the setting */ + if (td->font_face & extend) + { + td->font_face &= ~extend; + } + else + { + td->font_face |= extend; + } + + /* Hack - clear tile size info XXX XXX */ + td->tile_wid = td->tile_hgt = 0; + + /* Apply and Verify */ + term_data_check_font(td); + term_data_check_size(td); + + /* Resize and Redraw */ + term_data_resize(td); + term_data_redraw(td); + + break; + } + + /* Get a new font name */ + GetMenuItemText(GetMenuHandle(MENU_FONT), selection, s); + GetFNum(s, &fid); + + /* Save the new font id */ + td->font_id = fid; + + /* Current size is bad for new font */ + if (!RealFont(td->font_id, td->font_size)) + { + /* Find similar size */ + for (i = 1; i <= 32; i++) + { + /* Adjust smaller */ + if (td->font_size - i >= 8) + { + if (RealFont(td->font_id, td->font_size - i)) + { + td->font_size -= i; + break; + } + } + + /* Adjust larger */ + if (td->font_size + i <= 128) + { + if (RealFont(td->font_id, td->font_size + i)) + { + td->font_size += i; + break; + } + } + } + } + + /* Hack - clear tile size info XXX XXX */ + td->tile_wid = td->tile_hgt = 0; + + /* Apply and Verify */ + term_data_check_font(td); + term_data_check_size(td); + + /* Resize and Redraw */ + term_data_resize(td); + term_data_redraw(td); + + /* Restore the window */ + activate(old_win); + + break; + } + + /* Size menu */ + case MENU_SIZE: + { + if (!td) break; + + /* Save old */ + old_win = active; + + /* Activate */ + activate(td->w); + + GetMenuItemText(GetMenuHandle(MENU_SIZE), selection, s); + s[s[0] + 1] = 0; + td->font_size = atoi((char*)(s + 1)); + + /* Hack - clear tile size info XXX XXX */ + td->tile_wid = td->tile_hgt = 0; + + /* Apply and Verify */ + term_data_check_font(td); + term_data_check_size(td); + + /* Resize and Redraw */ + term_data_resize(td); + term_data_redraw(td); + + /* Restore */ + activate(old_win); + + break; + } + + /* Window menu */ + case MENU_WINDOWS: + { + /* Parse */ + i = selection - 1; + + /* Check legality of choice */ + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + /* Obtain the window */ + td = &data[i]; + + /* Mapped */ + td->mapped = TRUE; + + /* Link */ + term_data_link(i); + + /* Mapped (?) */ + td->t->mapped_flag = TRUE; + + /* Show the window */ + ShowWindow(td->w); + + /* Bring to the front */ + SelectWindow(td->w); + + break; + } + + /* Special menu */ + case MENU_SPECIAL: + { + switch (selection) + { + case ITEM_SOUND: + { + /* Toggle arg_sound */ + arg_sound = !arg_sound; + + /* React to changes */ + Term_xtra(TERM_XTRA_REACT, 0); + + break; + } + + case ITEM_FIDDLE: + { + arg_fiddle = !arg_fiddle; + break; + } + + case ITEM_WIZARD: + { + arg_wizard = !arg_wizard; + break; + } + } + + break; + } + + + /* Graphics submenu */ + case SUBMENU_GRAPH: + { + switch (selection) + { + case ITEM_NONE: + { + graf_mode_req = GRAF_MODE_NONE; + + break; + } + + case ITEM_8X8: + { + graf_mode_req = GRAF_MODE_8X8; + + break; + } + + case ITEM_16X16: + { + graf_mode_req = GRAF_MODE_16X16; + + break; + } + +#ifdef USE_DOUBLE_TILES + + case ITEM_BIGTILE: + { + term *old = Term; + term_data *td = &data[0]; + + /* Toggle "arg_bigtile" */ + use_bigtile = !use_bigtile; +# ifdef TOME + arg_bigtile = use_bigtile; +# endif /* TOME */ + + /* Activate */ + Term_activate(td->t); + + /* Resize the term */ + Term_resize(td->cols, td->rows); + + /* Activate old */ + Term_activate(old); + + break; + } + +#endif /* USE_DOUBLE_TILES */ + + } + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + + break; + } + + + /* TileWidth submenu */ + case SUBMENU_TILEWIDTH: + { + if (!td) break; + + /* Save old */ + old_win = active; + + /* Activate */ + activate(td->w); + + GetMenuItemText(GetMenuHandle(SUBMENU_TILEWIDTH), selection, s); + s[s[0] + 1] = 0; + td->tile_wid = atoi((char*)(s + 1)); + + /* Apply and Verify */ + term_data_check_size(td); + + /* Resize and Redraw */ + term_data_resize(td); + term_data_redraw(td); + + /* Restore */ + activate(old_win); + + break; + } + + + /* TileHeight submenu */ + case SUBMENU_TILEHEIGHT: + { + if (!td) break; + + /* Save old */ + old_win = active; + + /* Activate */ + activate(td->w); + + GetMenuItemText(GetMenuHandle(SUBMENU_TILEHEIGHT), selection, s); + s[s[0] + 1] = 0; + td->tile_hgt = atoi((char*)(s + 1)); + + /* Apply and Verify */ + term_data_check_size(td); + + /* Resize and Redraw */ + term_data_resize(td); + term_data_redraw(td); + + /* Restore */ + activate(old_win); + + break; + } + } + + + /* Clean the menu */ + HiliteMenu(0); +} + + +#ifdef USE_SFL_CODE + + +/* + * Check for extra required parameters -- From "Maarten Hazewinkel" + */ +static OSErr CheckRequiredAEParams(const AppleEvent *theAppleEvent) +{ + OSErr aeError; + DescType returnedType; + Size actualSize; + + aeError = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard, + &returnedType, NULL, 0, &actualSize); + + if (aeError == errAEDescNotFound) return (noErr); + + if (aeError == noErr) return (errAEParamMissed); + + return (aeError); +} + + +/* + * Apple Event Handler -- Open Application + */ +static OSErr AEH_Start(const AppleEvent *theAppleEvent, + AppleEvent *reply, long handlerRefCon) +{ +#pragma unused(reply, handlerRefCon) + + return (CheckRequiredAEParams(theAppleEvent)); +} + + +/* + * Apple Event Handler -- Quit Application + */ +static OSErr AEH_Quit(const AppleEvent *theAppleEvent, + AppleEvent *reply, long handlerRefCon) +{ +#pragma unused(reply, handlerRefCon) + + /* Quit later */ + quit_when_ready = TRUE; + + /* Check arguments */ + return (CheckRequiredAEParams(theAppleEvent)); +} + + +/* + * Apple Event Handler -- Print Documents + */ +static OSErr AEH_Print(const AppleEvent *theAppleEvent, + AppleEvent *reply, long handlerRefCon) +{ +#pragma unused(theAppleEvent, reply, handlerRefCon) + + return (errAEEventNotHandled); +} + + +/* + * Apple Event Handler by Steve Linberg (slinberg@crocker.com). + * + * The old method of opening savefiles from the finder does not work + * on the Power Macintosh, because CountAppFiles and GetAppFiles, + * used to return information about the selected document files when + * an application is launched, are part of the Segment Loader, which + * is not present in the RISC OS due to the new memory architecture. + * + * The "correct" way to do this is with AppleEvents. The following + * code is modeled on the "Getting Files Selected from the Finder" + * snippet from Think Reference 2.0. (The prior sentence could read + * "shamelessly swiped & hacked") + */ +static OSErr AEH_Open(AppleEvent *theAppleEvent, + AppleEvent* reply, long handlerRefCon) +{ +#pragma unused(reply, handlerRefCon) + + FSSpec myFSS; + AEDescList docList; + OSErr err; + Size actualSize; + AEKeyword keywd; + DescType returnedType; + char msg[128]; + FInfo myFileInfo; + + /* Put the direct parameter (a descriptor list) into a docList */ + err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList); + if (err) return err; + + /* + * We ignore the validity check, because we trust the FInder, and we only + * allow one savefile to be opened, so we ignore the depth of the list. + */ + + err = AEGetNthPtr(&docList, 1L, typeFSS, &keywd, + &returnedType, (Ptr) & myFSS, sizeof(myFSS), &actualSize); + if (err) return err; + + /* Only needed to check savefile type below */ + err = FSpGetFInfo(&myFSS, &myFileInfo); + if (err) + { + strnfmt(msg, 128, "Argh! FSpGetFInfo failed with code %d", err); + mac_warning(msg); + return err; + } + + /* Ignore non 'SAVE' files */ + if (myFileInfo.fdType != 'SAVE') return noErr; + + /* XXX XXX XXX Extract a file name */ + PathNameFromDirID(myFSS.parID, myFSS.vRefNum, (StringPtr)savefile); + pstrcat((StringPtr)savefile, (StringPtr)&myFSS.name); + + /* Convert the string */ + ptocstr((StringPtr)savefile); + + /* Delay actual open */ + open_when_ready = TRUE; + + /* Dispose */ + err = AEDisposeDesc(&docList); + + /* Success */ + return noErr; +} + + +#endif + + + +/* + * Macintosh modifiers (event.modifier & ccc): + * cmdKey, optionKey, shiftKey, alphaLock, controlKey + * + * + * Macintosh Keycodes (0-63 normal, 64-95 keypad, 96-127 extra): + * + * Return:36 + * Delete:51 + * + * Period:65 + * Star:67 + * Plus:69 + * Clear:71 + * Slash:75 + * Enter:76 + * Minus:78 + * Equal:81 + * 0-7:82-89 + * 8-9:91-92 + * + * backslash/vertical bar (Japanese keyboard):93 + * + * F5: 96 + * F6: 97 + * F7: 98 + * F3:99 + * F8:100 + * F10:101 + * F11:103 + * F13:105 + * F14:107 + * F9:109 + * F12:111 + * F15:113 + * Help:114 + * Home:115 + * PgUp:116 + * Del:117 + * F4: 118 + * End:119 + * F2:120 + * PgDn:121 + * F1:122 + * Lt:123 + * Rt:124 + * Dn:125 + * Up:126 + */ + + +/* + * Optimize non-blocking calls to "CheckEvents()" + * Idea from "Maarten Hazewinkel " + */ +#define EVENT_TICKS 6 + + +/* + * Check for Events, return TRUE if we process any + * + * Hack -- Handle AppleEvents if appropriate (ignore result code). + */ +static bool CheckEvents(bool wait) +{ + EventRecord event; + + WindowPtr w; + + Rect r; + + long newsize; + + int ch, ck; + + int mc, ms, mo, mx; + + int i; + + term_data *td = NULL; + + UInt32 curTicks; + + static UInt32 lastTicks = 0L; + + + /* Access the clock */ + curTicks = TickCount(); + + /* Hack -- Allow efficient checking for non-pending events */ + if (!wait && (curTicks < lastTicks + EVENT_TICKS)) return (FALSE); + + /* Timestamp last check */ + lastTicks = curTicks; + + /* Let the "system" run */ + SystemTask(); + + /* Get an event (or null) */ + WaitNextEvent(everyEvent, &event, 0L, nil); + + /* Hack -- Nothing is ready yet */ + if (event.what == nullEvent) return (FALSE); + + + /* Analyze the event */ + switch (event.what) + { + +#if 0 + + case activateEvt: + { + w = (WindowPtr)event.message; + + activate(w); + + break; + } + +#endif + + case updateEvt: + { + /* Extract the window */ + w = (WindowPtr)event.message; + + /* Find the window */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + /* Skip dead windows */ + if (!data[i].t) continue; + + /* Notice matches */ + if (data[i].w == w) td = &data[i]; + } + + /* Hack XXX XXX XXX */ + BeginUpdate(w); + EndUpdate(w); + + /* Redraw the window */ + if (td) term_data_redraw(td); + + break; + } + + case keyDown: + case autoKey: + { + /* Extract some modifiers */ + mc = (event.modifiers & controlKey) ? TRUE : FALSE; + ms = (event.modifiers & shiftKey) ? TRUE : FALSE; + mo = (event.modifiers & optionKey) ? TRUE : FALSE; + mx = (event.modifiers & cmdKey) ? TRUE : FALSE; + + /* Keypress: (only "valid" if ck < 96) */ + ch = (event.message & charCodeMask) & 255; + + /* Keycode: see table above */ + ck = ((event.message & keyCodeMask) >> 8) & 255; + + /* Command + "normal key" -> menu action */ + if (mx && (ck < 64)) + { + /* Hack -- Prepare the menus */ + setup_menus(); + + /* Mega-Hack -- allow easy exit if nothing to save */ + /* if (!character_generated && (ch=='Q' || ch=='q')) ch = 'e'; */ + + /* Run the Menu-Handler */ + menu(MenuKey(ch)); + + /* Turn off the menus */ + HiliteMenu(0); + + /* Done */ + break; + } + + + /* Hide the mouse pointer */ + ObscureCursor(); + + /* Normal key -> simple keypress */ + if ((ck < 64) || (ck == 93)) + { + /* Enqueue the keypress */ + Term_keypress(ch); + } + + /* Keypad keys -> trigger plus simple keypress */ + else if (!mc && !ms && !mo && !mx && (ck < 96)) + { + /* Hack -- "enter" is confused */ + if (ck == 76) ch = '\n'; + + /* Begin special trigger */ + Term_keypress(31); + + /* Send the "keypad" modifier */ + Term_keypress('K'); + + /* Send the "ascii" keypress */ + Term_keypress(ch); + + /* Terminate the trigger */ + Term_keypress(13); + } + + /* Bizarre key -> encoded keypress */ + else if (ck <= 127) + { + /* Begin special trigger */ + Term_keypress(31); + + /* Send some modifier keys */ + if (mc) Term_keypress('C'); + if (ms) Term_keypress('S'); + if (mo) Term_keypress('O'); + if (mx) Term_keypress('X'); + + /* Downshift and encode the keycode */ + Term_keypress(I2D((ck - 64) / 10)); + Term_keypress(I2D((ck - 64) % 10)); + + /* Terminate the trigger */ + Term_keypress(13); + } + + break; + } + + case mouseDown: + { + int code; + + /* Analyze click location */ + code = FindWindow(event.where, &w); + + /* Find the window */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + /* Skip dead windows */ + if (!data[i].t) continue; + + /* Notice matches */ + if (data[i].w == w) td = &data[i]; + } + + /* Analyze */ + switch (code) + { + case inMenuBar: + { + setup_menus(); + menu(MenuSelect(event.where)); + HiliteMenu(0); + break; + } + + case inSysWindow: + { + SystemClick(&event, w); + break; + } + + case inDrag: + { + Point p; + + WindowPtr old_win; + + r = qd.screenBits.bounds; + r.top += 20; /* GetMBarHeight() XXX XXX XXX */ + InsetRect(&r, 4, 4); + DragWindow(w, event.where, &r); + + /* Oops */ + if (!td) break; + + /* Save */ + old_win = active; + + /* Activate */ + activate(td->w); + + /* Analyze */ + p.h = td->w->portRect.left; + p.v = td->w->portRect.top; + LocalToGlobal(&p); + td->r.left = p.h; + td->r.top = p.v; + + /* Restore */ + activate(old_win); + + /* Apply and Verify */ + term_data_check_size(td); + + break; + } + + case inGoAway: + { + /* Oops */ + if (!td) break; + + /* Track the go-away box */ + if (TrackGoAway(w, event.where)) + { + /* Not Mapped */ + td->mapped = FALSE; + + /* Not Mapped */ + td->t->mapped_flag = FALSE; + + /* Hide the window */ + HideWindow(td->w); + } + + break; + } + + case inGrow: + { + int x, y; + + term *old = Term; + + /* Oops */ + if (!td) break; + +#ifndef ALLOW_BIG_SCREEN + + /* Fake rectangle */ + r.left = 20 * td->tile_wid + td->size_ow1; + r.right = 80 * td->tile_wid + td->size_ow1 + td->size_ow2 + 1; + r.top = 1 * td->tile_hgt + td->size_oh1; + r.bottom = 24 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1; + +#else /* ALLOW_BIG_SCREEN */ + + /* Fake rectangle */ + r.left = 20 * td->tile_wid + td->size_ow1; + r.right = qd.screenBits.bounds.right; + r.top = 1 * td->tile_hgt + td->size_oh1; + r.bottom = qd.screenBits.bounds.bottom; + +#endif /* ALLOW_BIG_SCREEN */ + + /* Grow the rectangle */ + newsize = GrowWindow(w, event.where, &r); + + /* Handle abort */ + if (!newsize) break; + + /* Extract the new size in pixels */ + y = HiWord(newsize) - td->size_oh1 - td->size_oh2; + x = LoWord(newsize) - td->size_ow1 - td->size_ow2; + + /* Extract a "close" approximation */ + td->rows = y / td->tile_hgt; + td->cols = x / td->tile_wid; + + /* Apply and Verify */ + term_data_check_size(td); + + /* Activate */ + Term_activate(td->t); + + /* Hack -- Resize the term */ + Term_resize(td->cols, td->rows); + + /* Resize and Redraw */ + term_data_resize(td); + term_data_redraw(td); + + /* Restore */ + Term_activate(old); + + break; + } + + case inContent: + { + SelectWindow(w); + + break; + } + } + + break; + } + + /* Disk Event -- From "Maarten Hazewinkel" */ + case diskEvt: + { + /* check for error when mounting the disk */ + if (HiWord(event.message) != noErr) + { + Point p = + {120, 120}; + + DILoad(); + DIBadMount(p, event.message); + DIUnload(); + } + + break; + } + + /* OS Event -- From "Maarten Hazewinkel" */ + case osEvt: + { + switch ((event.message >> 24) & 0x000000FF) + { + case suspendResumeMessage: + + /* Resuming: activate the front window */ + if (event.message & resumeFlag) + { + SetPort(FrontWindow()); + SetCursor(&qd.arrow); + } + + /* Suspend: deactivate the front window */ + else + { + /* Nothing */ + } + + break; + } + + break; + } + +#ifdef USE_SFL_CODE + + /* From "Steve Linberg" and "Maarten Hazewinkel" */ + case kHighLevelEvent: + { + /* Process apple events */ + if (AEProcessAppleEvent(&event) != noErr) + { + plog("Error in Apple Event Handler!"); + } + + /* Handle "quit_when_ready" */ + if (quit_when_ready) + { + /* Forget */ + quit_when_ready = FALSE; + + /* Do the menu key */ + menu(MenuKey('q')); + + /* Turn off the menus */ + HiliteMenu(0); + } + + /* Handle "open_when_ready" */ + handle_open_when_ready(); + + break; + } + +#endif + + } + + + /* Something happened */ + return (TRUE); +} + + + + +/*** Some Hooks for various routines ***/ + + +/* + * Mega-Hack -- emergency lifeboat + */ +static void *lifeboat = NULL; + + +/* + * Hook to "release" memory + */ +#ifdef NEW_ZVIRT_HOOKS /* [V] removed the unused 'size' argument. */ +static void *hook_rnfree(void *v) +#else +static void *hook_rnfree(void *v, size_t size) +#endif /* NEW_ZVIRT_HOOKS */ +{ + +#ifndef NEW_ZVIRT_HOOKS /* Oh, no. */ +#pragma unused (size) +#endif + +#ifdef USE_MALLOC + + /* Alternative method */ + free(v); + +#else + + /* Dispose */ + DisposePtr(v); + +#endif + + /* Success */ + return (NULL); +} + +/* + * Hook to "allocate" memory + */ +static void *hook_ralloc(size_t size) +{ + +#ifdef USE_MALLOC + + /* Make a new pointer */ + return (malloc(size)); + +#else + + /* Make a new pointer */ + return (NewPtr(size)); + +#endif + +} + +/* + * Hook to handle "out of memory" errors + */ +static void *hook_rpanic(size_t size) +{ + +#pragma unused (size) + + /* void *mem = NULL; */ + + /* Free the lifeboat */ + if (lifeboat) + { + /* Free the lifeboat */ + DisposePtr(lifeboat); + + /* Forget the lifeboat */ + lifeboat = NULL; + + /* Mega-Hack -- Warning */ + mac_warning("Running out of Memory!\rAbort this process now!"); + + /* Mega-Hack -- Never leave this function */ + while (TRUE) CheckEvents(TRUE); + } + + /* Mega-Hack -- Crash */ + return (NULL); +} + + +/* + * Hook to tell the user something important + */ +static void hook_plog(cptr str) +{ + /* Warning message */ + mac_warning(str); +} + + +/* + * Hook to tell the user something, and then quit + */ +static void hook_quit(cptr str) +{ + /* Warning if needed */ + if (str) mac_warning(str); + +#ifdef USE_ASYNC_SOUND + + /* Cleanup sound player */ + cleanup_sound(); + +#endif /* USE_ASYNC_SOUND */ + + /* Dispose of graphic tiles */ + if (frameP) + { + /* Unlock */ + BenSWUnlockFrame(frameP); + + /* Dispose of the GWorld */ + DisposeGWorld(frameP->framePort); + + /* Dispose of the memory */ + DisposePtr((Ptr)frameP); + } + + /* Write a preference file */ + save_pref_file(); + + /* All done */ + ExitToShell(); +} + + +/* + * Hook to tell the user something, and then crash + */ +static void hook_core(cptr str) +{ + /* XXX Use the debugger */ + /* DebugStr(str); */ + + /* Warning */ + if (str) mac_warning(str); + + /* Warn, then save player */ + mac_warning("Fatal error.\rI will now attempt to save and quit."); + + /* Attempt to save */ + if (!save_player()) mac_warning("Warning -- save failed!"); + + /* Quit */ + quit(NULL); +} + + + +/*** Main program ***/ + + +/* + * Init some stuff + * + * XXX XXX XXX Hack -- This function attempts to "fix" the nasty + * "Macintosh Save Bug" by using "absolute" path names, since on + * System 7 machines anyway, the "current working directory" often + * "changes" due to background processes, invalidating any "relative" + * path names. Note that the Macintosh is limited to 255 character + * path names, so be careful about deeply embedded directories... + * + * XXX XXX XXX Hack -- This function attempts to "fix" the nasty + * "missing lib folder bug" by allowing the user to help find the + * "lib" folder by hand if the "application folder" code fails... + */ +static void init_stuff(void) +{ + int i; + + short vrefnum; + long drefnum; + long junk; + + SFTypeList types; + SFReply reply; + + Rect r; + Point topleft; + + char path[1024]; + + + /* Fake rectangle */ + r.left = 0; + r.top = 0; + r.right = 344; + r.bottom = 188; + + /* Center it */ + center_rect(&r, &qd.screenBits.bounds); + + /* Extract corner */ + topleft.v = r.top; + topleft.h = r.left; + + + /* Default to the "lib" folder with the application */ + refnum_to_name(path, app_dir, app_vol, (char*)("\plib:")); + + + /* Check until done */ + while (1) + { + /* Prepare the paths */ + init_file_paths(path); + + /* Build the filename */ + path_build(path, 1024, ANGBAND_DIR_FILE, "news.txt"); + + /* Attempt to open and close that file */ + if (0 == fd_close(fd_open(path, O_RDONLY))) break; + + /* Warning */ + plog_fmt("Unable to open the '%s' file.", path); + + /* Warning */ + plog("The Angband 'lib' folder is probably missing or misplaced."); + + /* Warning */ + plog("Please 'open' any file in any sub-folder of the 'lib' folder."); + + /* Allow "text" files */ + types[0] = 'TEXT'; + + /* Allow "save" files */ + types[1] = 'SAVE'; + + /* Allow "data" files */ + types[2] = 'DATA'; + + /* Get any file */ + SFGetFile(topleft, "\p", NULL, 3, types, NULL, &reply); + + /* Allow cancel */ + if (!reply.good) quit(NULL); + + /* Extract textual file name for given file */ + GetWDInfo(reply.vRefNum, &vrefnum, &drefnum, &junk); + refnum_to_name(path, drefnum, vrefnum, (char*)reply.fName); + + /* Hack -- Remove the "filename" */ + i = strlen(path) - 1; + while ((i > 0) && (path[i] != ':')) i--; + if (path[i] == ':') path[i + 1] = '\0'; + + /* Hack -- allow "lib" folders */ + if (suffix(path, "lib:")) continue; + + /* Hack -- Remove the "sub-folder" */ + i = i - 1; + while ((i > 1) && (path[i] != ':')) i--; + if (path[i] == ':') path[i + 1] = '\0'; + } +} + + +/* + * Macintosh Main loop + */ +int main(void) +{ + int i; + + EventRecord tempEvent; + int numberOfMasters = 10; + + /* Increase stack space by 64K */ + SetApplLimit(GetApplLimit() - 65536L); + + /* Stretch out the heap to full size */ + MaxApplZone(); + + /* Get more Masters */ + while (numberOfMasters--) MoreMasters(); + + /* Set up the Macintosh */ + InitGraf(&qd.thePort); + InitFonts(); + InitWindows(); + InitMenus(); + /* TEInit(); */ + InitDialogs(NULL); + InitCursor(); + + /* Flush events */ + FlushEvents(everyEvent, 0); + + /* Flush events some more (?) */ + if (EventAvail(everyEvent, &tempEvent)) FlushEvents(everyEvent, 0); + + +#ifdef ANGBAND_LITE_MAC + + /* Nothing */ + +#else /* ANGBAND_LITE_MAC */ + +# if defined(powerc) || defined(__powerc) + + /* Assume System 7 */ + + /* Assume Color Quickdraw */ + +# else + + /* Block */ + if (TRUE) + { + OSErr err; + long versionNumber; + + /* Check the Gestalt */ + err = Gestalt(gestaltSystemVersion, &versionNumber); + + /* Check the version */ + if ((err != noErr) || (versionNumber < 0x0700)) + { + quit("You must have System 7 to use this program."); + } + } + + /* Block */ + if (TRUE) + { + SysEnvRec env; + + /* Check the environs */ + if (SysEnvirons(1, &env) != noErr) + { + quit("The SysEnvirons call failed!"); + } + + /* Check for System Seven Stuff */ + if (env.systemVersion < 0x0700) + { + quit("You must have System 7 to use this program."); + } + + /* Check for Color Quickdraw */ + if (!env.hasColorQD) + { + quit("You must have Color Quickdraw to use this program."); + } + } + +# endif + +#endif /* ANGBAND_LITE_MAC */ + + +#ifdef USE_SFL_CODE + + /* Obtain a "Universal Procedure Pointer" */ + AEH_Start_UPP = NewAEEventHandlerProc(AEH_Start); + + /* Install the hook (ignore error codes) */ + AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, AEH_Start_UPP, + 0L, FALSE); + + /* Obtain a "Universal Procedure Pointer" */ + AEH_Quit_UPP = NewAEEventHandlerProc(AEH_Quit); + + /* Install the hook (ignore error codes) */ + AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, AEH_Quit_UPP, + 0L, FALSE); + + /* Obtain a "Universal Procedure Pointer" */ + AEH_Print_UPP = NewAEEventHandlerProc(AEH_Print); + + /* Install the hook (ignore error codes) */ + AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, AEH_Print_UPP, + 0L, FALSE); + + /* Obtain a "Universal Procedure Pointer" */ + AEH_Open_UPP = NewAEEventHandlerProc(AEH_Open); + + /* Install the hook (ignore error codes) */ + AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, AEH_Open_UPP, + 0L, FALSE); + +#endif + + + /* Find the current application */ + SetupAppDir(); + + + /* Mark ourself as the file creator */ + _fcreator = ANGBAND_CREATOR; + + /* Default to saving a "text" file */ + _ftype = 'TEXT'; + + +#if defined(ALLOW_NO_SAVE_QUITS) && defined(__MWERKS__) + + /* Obtian a "Universal Procedure Pointer" */ + ynfilterUPP = NewModalFilterProc(ynfilter); + +#endif /* ALLOW_NO_SAVE_QUITS && __MWERKS__ */ + + + /* Hook in some "z-virt.c" hooks */ + rnfree_aux = hook_rnfree; + ralloc_aux = hook_ralloc; + rpanic_aux = hook_rpanic; + + /* Hooks in some "z-util.c" hooks */ + plog_aux = hook_plog; + quit_aux = hook_quit; + core_aux = hook_core; + + + /* Initialize colors */ + for (i = 0; i < 256; i++) + { + u16b rv, gv, bv; + + /* Extract the R,G,B data */ + rv = angband_color_table[i][1]; + gv = angband_color_table[i][2]; + bv = angband_color_table[i][3]; + + /* Save the actual color */ + color_info[i].red = (rv | (rv << 8)); + color_info[i].green = (gv | (gv << 8)); + color_info[i].blue = (bv | (bv << 8)); + } + + + /* Show the "watch" cursor */ + SetCursor(*(GetCursor(watchCursor))); + + /* Prepare the menubar */ + init_menubar(); + + /* Prepare the windows */ + init_windows(); + + /* Hack -- process all events */ + while (CheckEvents(TRUE)) /* loop */; + + /* Reset the cursor */ + SetCursor(&qd.arrow); + + + /* Mega-Hack -- Allocate a "lifeboat" */ + lifeboat = NewPtr(16384); + + /* Note the "system" */ + ANGBAND_SYS = "mac"; + + + /* Initialize */ + init_stuff(); + + /* Initialize */ + init_angband(); + + + /* Hack -- process all events */ + while (CheckEvents(TRUE)) /* loop */; + + + /* We are now initialized */ + initialized = TRUE; + + + /* Handle "open_when_ready" */ + handle_open_when_ready(); + +#ifndef SAVEFILE_SCREEN + + /* Prompt the user */ + /* In [Z], it's currently prtf(17, 23, ); */ + prt("[Choose 'New' or 'Open' from the 'File' menu]", 23, 15); + + /* Flush the prompt */ + Term_fresh(); + + /* Hack -- Process Events Forever */ + while (TRUE) CheckEvents(TRUE); + +#else + + /* Game is in progress */ + game_in_progress = 1; + + /* Wait for keypress */ + pause_line(23); + + /* flush input - Warning: without this, _system_ would hang */ + flush(); + + /* Play the game - note the value of the argument */ + play_game(FALSE); + + /* Quit */ + quit(NULL); + +#endif /* !SAVEFILE_SCREEN */ +} + +#endif /* MACINTOSH */ -- cgit v1.2.3