OSDN Git Service

無駄なobject_is_weapon_armour_ammo()呼び出しの削除.
[hengband/hengband.git] / src / main-mac.c
index 1a5c3d9..03c12a1 100644 (file)
 
 #include "angband.h"
 
+#ifdef MACH_O_CARBON
+
+#include <Carbon/Carbon.h>
+#include <QuickTime/QuickTime.h>
+#include <CoreServices/CoreServices.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#define TARGET_API_MAC_CARBON 1
+
+#else /* MACH_O_CARBON */
+
 #include <Types.h>
 #include <Gestalt.h>
 #include <QuickDraw.h>
 #include <Sound.h>
 #if TARGET_API_MAC_CARBON
 #include <Navigation.h>
+#include <CFPreferences.h>
+#include <CFNumber.h>
 # ifdef MAC_MPW
 # include <CarbonStdCLib.h>
 # endif
 
 #endif
 
+#endif /* MACH_O_CARBON */
+
+/*
+ * Use rewritten asynchronous sound player
+ */
+#define USE_ASYNC_SOUND
+
 /*
  * Cleaning up a couple of things to make these easier to change --AR
  */
 /* #define USE_MALLOC */
 
 
+/* Default creator signature */
+#ifndef ANGBAND_CREATOR
+# define ANGBAND_CREATOR 'Heng'
+#endif
+
+
 #if defined(powerc) || defined(__powerc)
 
 /*
 
 
 
+#ifndef MACH_O_CARBON
 #ifdef USE_SFL_CODE
 
 /*
 #include <Folders.h>
 
 #endif
-
+#endif /* !MACH_O_CARBON */
 
 /*
  * Globals for MPW compilation
  */
 #if defined(MACH_O_CARBON) || defined(MAC_MPW)
        /* Globals needed */
+#if !TARGET_API_MAC_CARBON
+       QDGlobals qd;
+#endif
        OSType _ftype;
        OSType _fcreator;
 #endif
@@ -356,6 +386,7 @@ struct term_data
  */
 static bool CheckEvents(bool wait);
 
+#ifndef MACH_O_CARBON
 
 /*
  * Hack -- location of the main directory
@@ -363,6 +394,7 @@ static bool CheckEvents(bool wait);
 static short app_vol;
 static long  app_dir;
 
+#endif /* !MACH_O_CARBON */
 
 /*
  * Delay handling of double-clicked savefiles
@@ -406,11 +438,14 @@ static bool initialized = FALSE;
 static long mac_os_version;
 
 
+#if defined(__MWERKS__)
 /*
  * CodeWarrior uses Universal Procedure Pointers
  */
 static ModalFilterUPP ynfilterUPP;
 
+#endif /* __MWERKS__ */
+
 #ifdef USE_SFL_CODE
 
 /*
@@ -423,6 +458,507 @@ AEEventHandlerUPP AEH_Open_UPP;
 
 #endif
 
+# ifdef USE_ASYNC_SOUND
+
+/*
+ * Asynchronous sound player revised
+ */
+#if defined(USE_QT_SOUND) && !defined(MACH_O_CARBON)
+# undef USE_QT_SOUND
+#endif /* USE_QT_SOUND && !MACH_O_CARBON */
+
+
+/*
+ * Number of channels in the channel pool
+ */
+#if TARGET_API_MAC_CARBON
+#define MAX_CHANNELS           8
+#else
+#define MAX_CHANNELS           4
+#endif
+
+/*
+ * 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];
+
+
+/*
+ * Sound effects
+ *
+ * These constants aren't used by the program at the moment.
+ */
+#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 SInt16 sound_volume = SOUND_VOLUME_MAX;
+
+#ifdef USE_QT_SOUND
+
+/*
+ * Moving graphics resources into data fork -- pelpel
+ *
+ * (Carbon, Bundle)
+ * Given base and type names of a resource, find a file in the
+ * current application bundle and return its FSSpec in the third argument.
+ * Returns true on success, false otherwise.
+ * e.g. get_resource_spec(CFSTR("8x8"), CFSTR("png"), &spec);
+ */
+static Boolean get_resource_spec(
+       CFStringRef base_name, CFStringRef type_name, FSSpec *spec)
+{
+       CFURLRef res_url;
+       FSRef ref;
+
+       /* Find resource (=file) in the current bundle */
+       res_url = CFBundleCopyResourceURL(
+               CFBundleGetMainBundle(), base_name, type_name, NULL);
+
+       /* Oops */
+       if (res_url == NULL) return (false);
+
+       /* Convert CFURL to FSRef */
+       (void)CFURLGetFSRef(res_url, &ref);
+
+       /* Convert FSRef to FSSpec */
+       (void)FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+
+       /* Free allocated CF data */
+       CFRelease(res_url);
+
+       /* Success */
+       return (true);
+}
+
+/*
+ * QuickTime sound, by Ron Anderson
+ *
+ * I didn't choose to use Windows-style .ini files (Ron wrote a parser
+ * for it, but...), nor did I use lib/xtra directory, hoping someone
+ * would code plist-based configuration code in the future -- pelpel
+ */
+
+/*
+ * (QuickTime)
+ * Load sound effects from data-fork resources.  They are wav files
+ * with the same names as angband_sound_name[] (variable.c)
+ *
+ * Globals referenced: angband_sound_name[]
+ * Globals updated: samples[] (they can be *huge*)
+ */
+static void load_sounds(void)
+{
+       OSErr err;
+       int i;
+
+       /* Start QuickTime */
+       err = EnterMovies();
+
+       /* Error */
+       if (err != noErr) return;
+
+       /*
+        * This loop may take a while depending on the count and size of samples
+        * to load.
+        *
+        * We should use a progress dialog for this.
+        */
+       for (i = 1; i < SOUND_MAX; i++)
+       {
+               /* Apple APIs always give me headacke :( */
+               CFStringRef name;
+               FSSpec spec;
+               SInt16 file_id;
+               SInt16 res_id;
+               Str255 movie_name;
+               Movie movie;
+               Track track;
+               Handle h;
+               Boolean res;
+
+               /* Allocate CFString with the name of sound event to be processed */
+               name = CFStringCreateWithCString(NULL, angband_sound_name[i],
+                       kTextEncodingUS_ASCII);
+
+               /* Error */
+               if (name == NULL) continue;
+
+               /* Find sound sample resource with the same name */
+               res = get_resource_spec(name, CFSTR("wav"), &spec);
+
+               /* Free the reference to CFString */
+               CFRelease(name);
+
+               /* Error */
+               if (!res) continue;
+
+               /* Open the sound file */
+               err = OpenMovieFile(&spec, &file_id, fsRdPerm);
+
+               /* Error */
+               if (err != noErr) continue;
+
+               /* Create Movie from the file */
+               err = NewMovieFromFile(&movie, file_id, &res_id, movie_name,
+                       newMovieActive, NULL);
+
+               /* Error */
+               if (err != noErr) goto close_file;
+
+               /* Get the first track of the movie */
+               track = GetMovieIndTrackType(movie, 1, AudioMediaCharacteristic,
+                       movieTrackCharacteristic | movieTrackEnabledOnly );
+
+               /* Error */
+               if (track == NULL) goto close_movie;
+
+               /* Allocate a handle to store sample */
+               h = NewHandle(0);
+
+               /* Error */
+               if (h == NULL) goto close_track;
+
+               /* Dump the sample into the handle */
+               err = PutMovieIntoTypedHandle(movie, track, soundListRsrc, h, 0,
+                       GetTrackDuration(track), 0L, NULL);
+
+               /* Success */
+               if (err == noErr)
+               {
+                       /* Store the handle in the sample list */
+                       samples[i] = (SndListHandle)h;
+               }
+
+               /* Failure */
+               else
+               {
+                       /* Free unused handle */
+                       DisposeHandle(h);
+               }
+
+               /* Free the track */
+               close_track: DisposeMovieTrack(track);
+
+               /* Free the movie */
+               close_movie: DisposeMovie(movie);
+
+               /* Close the movie file */
+               close_file: CloseMovieFile(file_id);
+       }
+
+       /* Stop QuickTime */
+       ExitMovies();
+}
+
+#else /* USE_QT_SOUND */
+
+/*
+ * 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));
+}
+
+#endif /* USE_QT_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]);
+               }
+
+#ifndef USE_QT_SOUND
+
+               /* Release it */
+               if (samples[i]) ReleaseResource((Handle)samples[i]);
+#else
+
+               /* Free handle */
+               if (samples[i]) DisposeHandle((Handle)samples[i]);
+#endif /* !USE_QT_SOUND */
+       }
+}
+
+
+/*
+ * 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, SInt16 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 */
+#ifdef JP
+                               plog("¥µ¥¦¥ó¥É¥Á¥ã¥ó¥Í¥ë¤ò½é´ü²½½ÐÍè¤Þ¤»¤ó!");
+#else
+                               plog("Cannot initialise sound channels!");
+#endif
+
+                               /* 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 = ((SInt32)vol << 16) | 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 */
+#ifdef USE_QT_SOUND
+               h = samples[num];
+#else
+               h = find_sound(num);
+#endif /* USE_QT_SOUND */
+
+               /* Sample not available */
+               if (h == NULL) return;
+
+#ifndef USE_QT_SOUND
+
+               /* Load resource */
+               LoadResource((Handle)h);
+
+               /* Remember it */
+               samples[num] = h;
+
+#endif /* !USE_QT_SOUND */
+
+               /* Lock the handle */
+               HLockHi((Handle)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]);
+
+#ifndef USE_QT_SOUND
+
+                       /* Release */
+                       ReleaseResource((Handle)samples[prev_num]);
+
+                       /* Forget handle */
+                       samples[prev_num] = NULL;
+
+#endif /* !USE_QT_SOUND */
+
+                       /* 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;
+}
+
+# else /* USE_ASYNC_SOUND */
+
+/*
+ * Play sound synchronously
+ *
+ * This may not be your choice, but much safer and much less resource hungry.
+ */
+static void play_sound(int num, SInt16 vol)
+{
+       Handle handle;
+       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 */
+       handle = GetNamedResource('snd ', sound);
+
+       /* Oops */
+       if (handle == NULL) return;
+
+       /* Load and Lock */
+       LoadResource(handle);
+       HLockHi(handle);
+
+       /* Play sound (wait for completion) */
+       SndPlay(NULL, (SndListHandle)handle, FALSE);
+
+       /* Unlock and release */
+       HUnlock(handle);
+       ReleaseResource(handle);
+}
+
+# endif /* USE_ASYNC_SOUND */
+
+#ifndef MACH_O_CARBON
+
 /*
        Extra Sound Mode
 */
@@ -505,10 +1041,11 @@ static int soundchoice[] = {
        SND_TRAP,
 };
 
-static int                     soundmode[8];
-
 static int ext_graf = 0;
 
+#endif /* !MACH_O_CARBON */
+
+static short                   soundmode[8];
 
 
 /*
@@ -520,7 +1057,6 @@ static int ext_graf = 0;
 static void refnum_to_name(char *buf, long refnum, short vrefnum, char *fname)
 {
        CInfoPBRec pb;
-       Str255 name;
        int err;
        int i, j;
 
@@ -685,6 +1221,7 @@ static bool askfor_file(char *buf, int len)
 
 #endif
 
+#if !TARGET_API_MAC_CARBON
 static void local_to_global( Rect *r )
 {
        Point           temp;
@@ -705,6 +1242,7 @@ static void local_to_global( Rect *r )
        r->right = temp.h;
        r->bottom = temp.v;
 }
+#endif /* !TARGET_API_MAC_CARBON */
 
 static void global_to_local( Rect *r )
 {
@@ -860,6 +1398,84 @@ static void center_rect(Rect *r, Rect *s)
 }
 
 
+#ifdef MACH_O_CARBON
+
+/* Carbon File Manager utilities by pelpel */
+
+/*
+ * (Carbon)
+ * Convert a pathname to a corresponding FSSpec.
+ * Returns noErr on success.
+ */
+static OSErr path_to_spec(const char *path, FSSpec *spec)
+{
+       OSErr err;
+       FSRef ref;
+
+       /* Convert pathname to FSRef ... */
+       err = FSPathMakeRef(path, &ref, NULL);
+       if (err != noErr) return (err);
+
+       /* ... then FSRef to FSSpec */
+       err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+       
+       /* Inform caller of success or failure */
+       return (err);
+}
+
+
+/*
+ * (Carbon)
+ * Convert a FSSpec to a corresponding pathname.
+ * Returns noErr on success.
+ */
+static OSErr spec_to_path(const FSSpec *spec, char *buf, size_t size)
+{
+       OSErr err;
+       FSRef ref;
+
+       /* Convert FSSpec to FSRef ... */
+       err = FSpMakeFSRef(spec, &ref);
+       if (err != noErr) return (err);
+
+       /* ... then FSRef to pathname */
+       err = FSRefMakePath(&ref, buf, size);
+
+       /* Inform caller of success or failure */
+       return (err);
+}
+
+
+/*
+ * (Carbon) [via path_to_spec]
+ * Set creator and filetype of a file specified by POSIX-style pathname.
+ * Returns 0 on success, -1 in case of errors.
+ */
+void fsetfileinfo(cptr pathname, OSType fcreator, OSType ftype)
+{
+       OSErr err;
+       FSSpec spec;
+       FInfo info;
+
+       /* Convert pathname to FSSpec */
+       if (path_to_spec(pathname, &spec) != noErr) return;
+
+       /* Obtain current finder info of the file */
+       if (FSpGetFInfo(&spec, &info) != noErr) return;
+
+       /* Overwrite creator and type */
+       info.fdCreator = fcreator;
+       info.fdType = ftype;
+       err = FSpSetFInfo(&spec, &info);
+
+       /* Done */
+       return;
+}
+
+
+#else /* MACH_O_CARBON */
+
+
 /*
  * Convert a pascal string in place
  *
@@ -943,55 +1559,7 @@ static void PathNameFromDirID(long dirID, short vRefNum, StringPtr fullPathName)
 }
 
 #endif
-
-#if TARGET_API_MAC_CARBON
-
-static OSErr ChooseFile( StringPtr filename, FSSpec selfld )
-{
-       NavReplyRecord          reply;
-       NavDialogOptions        dialogOptions;
-       NavTypeListHandle       navTypeList = NULL;
-       OSErr                           err;
-       AEDesc  deffld;
-       
-       AECreateDesc( typeFSS, &selfld, sizeof(FSSpec), &deffld );
-       
-       err = NavGetDefaultDialogOptions( &dialogOptions );
-       
-       if( err == noErr ){
-               
-               err = NavChooseFile( &deffld, &reply, &dialogOptions, NULL, NULL, NULL, navTypeList, NULL );
-               
-               if ( reply.validRecord && err == noErr ){
-                       // grab the target FSSpec from the AEDesc:
-                       FSSpec          finalFSSpec;
-                       AEKeyword       keyWord;
-                       DescType        typeCode;
-                       Size            actualSize = 0;
-
-                       // retrieve the returned selection:
-                       // there is only one selection here we get only the first AEDescList:
-                       if (( err = AEGetNthPtr( &(reply.selection), 1, typeFSS, &keyWord, &typeCode, &finalFSSpec, sizeof( FSSpec ), &actualSize )) == noErr )
-                       {
-                               refnum_to_name( (char *)filename, finalFSSpec.parID, finalFSSpec.vRefNum, (char *)finalFSSpec.name );
-                               // 'finalFSSpec' is the chosen file¥Î
-                       }
-                       
-                       err = NavDisposeReply( &reply );
-               }
-               if( navTypeList != NULL )
-               {
-                       DisposeHandle( (Handle)navTypeList );
-                       navTypeList = NULL;
-               }
-       }
-       
-       AEDisposeDesc( &deffld );
-       
-       return err;
-}
-
-#endif
+#endif /* MACH_O_CARBON */
 
 /*
  * Activate a given window, if necessary
@@ -1591,7 +2159,6 @@ static void Term_init_mac(term *t)
 
        /* Block */
        {
-               Rect tempRect;
                Rect globalRect;
                GDHandle mainGDH;
                GDHandle currentGDH;
@@ -1814,46 +2381,9 @@ static errr Term_xtra_mac(int n, int v)
                /* Make a sound */
                case TERM_XTRA_SOUND:
                {
-                       Handle handle;
-
-                       Str255 sound;
-
-#if 0
-                       short oldResFile;
-                       short newResFile;
-
-                       /* Open the resource file */
-                       oldResFile = CurResFile();
-                       newResFile = OpenResFile(sound);
-
-                       /* Close the resource file */
-                       CloseResFile(newResFile);
-                       UseResFile(oldResFile);
-#endif
-
-                       /* Get the proper sound name */
-                       sprintf((char*)sound + 1, "%.16s.wav", angband_sound_name[v]);
-                       sound[0] = strlen((char*)sound + 1);
-
-                       /* Obtain resource XXX XXX XXX */
-                       handle = Get1NamedResource('snd ', sound);
-                       if( handle == NULL || ext_sound )
-                               handle = GetNamedResource('snd ', sound);
-                       
-                       /* Oops */
-                       if (handle && soundmode[soundchoice[v]] == true)
-                       {
-                               /* Load and Lock */
-                               LoadResource(handle);
-                               HLock(handle);
-
-                               /* Play sound (wait for completion) */
-                               SndPlay(nil, (SndListHandle)handle, true);
+                       /* Play sound */
+                       play_sound(v, sound_volume);
 
-                               /* Unlock and release */
-                               HUnlock(handle);
-                               ReleaseResource(handle);
-                       }
                        /* Success */
                        return (0);
                }
@@ -1965,7 +2495,7 @@ static errr Term_xtra_mac(int n, int v)
                                 * Even if ticks are 0, it's worth calling for
                                 * the above mentioned reasons.
                                 */
-                               WaitNextEvent(~everyEvent, &tmp, ticks, nil);
+                               WaitNextEvent((EventMask)~everyEvent, &tmp, ticks, nil);
 #else
                                long m = TickCount() + (v * 60L) / 1000;
 
@@ -2101,12 +2631,8 @@ static errr Term_text_mac(int x, int y, int n, byte a, const char *cp)
  *
  * Erase "n" characters starting at (x,y)
  */
-#ifdef USE_TRANSPARENCY
 static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp,
                          const byte *tap, const char *tcp)
-#else
-static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp)
-#endif
 {
        int i;
        Rect r2;
@@ -2114,8 +2640,6 @@ static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp)
        GDHandle saveGDevice;
        GWorldPtr saveGWorld;
        
-       PixMapHandle PortPix;
-       
        /* Save GWorld */
        GetGWorld(&saveGWorld, &saveGDevice);
        
@@ -2184,7 +2708,6 @@ static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp)
                        int col, row;
                        Rect r1;
 
-#ifdef USE_TRANSPARENCY
                        Rect terrain_r;
                        bool terrain_flag = FALSE;
                        byte ta = tap[i];
@@ -2205,7 +2728,6 @@ static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp)
 
                                terrain_flag = TRUE;
                        }
-#endif
 
                        /* Row and Col */
                        row = ((byte)a & 0x7F);
@@ -2229,7 +2751,6 @@ static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp)
 #endif
                        if (use_bigtile) r2.right += td->tile_wid;
 
-#ifdef USE_TRANSPARENCY
                        if (terrain_flag)
                        {
                                /*
@@ -2261,7 +2782,6 @@ static errr Term_pict_mac(int x, int y, int n, const byte *ap, const char *cp)
 #endif
                        }
                        else
-#endif /* USE_TRANSPARENCY */
                        {
 #if TARGET_API_MAC_CARBON
                                CopyBits( (BitMap *) *srcBitMap, (BitMap *) *destBitMap, &r1, &r2, srcCopy, NULL);
@@ -2390,60 +2910,431 @@ static void term_data_link(int i)
 
 
 
+#ifdef MACH_O_CARBON
+
+/*
+ * (Carbon, Bundle)
+ * Return a POSIX pathname of the lib directory, or NULL if it can't be
+ * located.  Caller must supply a buffer along with its size in bytes,
+ * where returned pathname will be stored.
+ * I prefer use of goto's to several nested if's, if they involve error
+ * handling.  Sorry if you are offended by their presence.  Modern
+ * languages have neater constructs for this kind of jobs -- pelpel
+ */
+static char *locate_lib(char *buf, size_t size)
+{
+       CFURLRef main_url = NULL;
+       CFStringRef main_str = NULL;
+       char *p;
+       char *res = NULL;
+
+       /* Obtain the URL of the main bundle */
+       main_url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+
+       /* Oops */
+       if (main_url == NULL) goto ret;
+
+       /* Convert it to POSIX pathname */
+       main_str = CFURLCopyFileSystemPath(main_url, kCFURLPOSIXPathStyle);
+
+       /* Oops */
+       if (main_str == NULL) goto ret;
+
+       /* Convert it again from darn unisomething encoding to ASCII */
+       if (CFStringGetCString(main_str, buf, size, kTextEncodingUS_ASCII) == FALSE)
+               goto ret;
+
+       /* Find the last '/' in the pathname */
+       p = strrchr(buf, '/');
+
+       /* Paranoia - cannot happen */
+       if (p == NULL) goto ret;
+
+       /* Remove the trailing path */
+       *p = '\0';
+
+       /*
+        * Paranoia - bounds check, with 5 being the length of "/lib/"
+        * and 1 for terminating '\0'.
+        */
+       if (strlen(buf) + 5 + 1 > size) goto ret;
+
+       /* Append "/lib/" */
+       strcat(buf, "/lib/");
+
+       /* Set result */
+       res = buf;
+
+ret:
+
+       /* Release objects allocated and implicitly retained by the program */
+       if (main_str) CFRelease(main_str);
+       if (main_url) CFRelease(main_url);
+
+       /* pathname of the lib folder or NULL */
+       return (res);
+}
+
+
+#else /* MACH_O_CARBON */
+
+
+/*
+ * 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 = PBGetFCBInfo(&fcbBlock, FALSE);
+       if (err != noErr)
+       {
+#ifdef JP
+               sprintf(errString, "PBGetFCBInfo ¥¨¥é¡¼ #%d.\r ½ªÎ»¤·¤Þ¤¹.", err);
+#else
+               sprintf(errString, "Fatal PBGetFCBInfo Error #%d.\r Exiting.", err);
+#endif
+               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)
+       {
+#ifdef JP
+               sprintf(errString, "HSetVol ¥¨¥é¡¼ #%d.\r ½ªÎ»¤·¤Þ¤¹.", err);
+#else
+               sprintf(errString, "Fatal HSetVol Error #%d.\r Exiting.", err);
+#endif
+               mac_warning(errString);
+               ExitToShell();
+       }
+}
+
+#endif
+
+
+
+#if TARGET_API_MAC_CARBON
+/*
+ * Using Core Foundation's Preferences services -- pelpel
+ *
+ * Requires OS 8.6 or greater with CarbonLib 1.1 or greater. Or OS X,
+ * of course.
+ *
+ * Without this, we can support older versions of OS 8 as well
+ * (with CarbonLib 1.0.4).
+ *
+ * Frequent allocation/deallocation of small chunks of data is
+ * far from my liking, but since this is only called at the
+ * beginning and the end of a session, I hope this hardly matters.
+ */
+
+
+/*
+ * Store "value" as the value for preferences item name
+ * pointed by key
+ */
+static void save_pref_short(const char *key, short value)
+{
+       CFStringRef cf_key;
+       CFNumberRef cf_value;
+
+       /* allocate and initialise the key */
+       cf_key = CFStringCreateWithCString(NULL, key, kTextEncodingUS_ASCII);
+
+       /* allocate and initialise the value */
+       cf_value = CFNumberCreate(NULL, kCFNumberShortType, &value);
+
+       if ((cf_key != NULL) && (cf_value != NULL))
+       {
+               /* Store the key-value pair in the applications preferences */
+               CFPreferencesSetAppValue(
+                       cf_key,
+                       cf_value,
+                       kCFPreferencesCurrentApplication);
+       }
+
+       /*
+        * Free CF data - the reverse order is a vain attempt to
+        * minimise memory fragmentation.
+        */
+       if (cf_value) CFRelease(cf_value);
+       if (cf_key) CFRelease(cf_key);
+}
+
+
+/*
+ * Load preference value for key, returns TRUE if it succeeds with
+ * vptr updated appropriately, FALSE otherwise.
+ */
+static bool query_load_pref_short(const char *key, short *vptr)
+{
+       CFStringRef cf_key;
+       CFNumberRef cf_value;
+
+       /* allocate and initialise the key */
+       cf_key = CFStringCreateWithCString(NULL, key, kTextEncodingUS_ASCII);
+
+       /* Oops */
+       if (cf_key == NULL) return (FALSE);
+
+       /* Retrieve value for the key */
+       cf_value = CFPreferencesCopyAppValue(
+               cf_key,
+               kCFPreferencesCurrentApplication);
+
+       /* Value not found */
+       if (cf_value == NULL)
+       {
+               CFRelease(cf_key);
+               return (FALSE);
+       }
+
+       /* Convert the value to short */
+       CFNumberGetValue(
+               cf_value,
+               kCFNumberShortType,
+               vptr);
+
+       /* Free CF data */
+       CFRelease(cf_value);
+       CFRelease(cf_key);
+
+       /* Success */
+       return (TRUE);
+}
+
+
+/*
+ * Update short data pointed by vptr only if preferences
+ * value for key is located.
+ */
+static void load_pref_short(const char *key, short *vptr)
+{
+       short tmp;
+
+       if (query_load_pref_short(key, &tmp)) *vptr = tmp;
+       return;
+}
+
+
+/*
+ * Save preferences to preferences file for current host+current user+
+ * current application.
+ */
+static void cf_save_prefs()
+{
+       int i;
+
+       /* Version stamp */
+       save_pref_short("version.major", FAKE_VERSION);
+       save_pref_short("version.minor", FAKE_VER_MAJOR);
+       save_pref_short("version.patch", FAKE_VER_MINOR);
+       save_pref_short("version.extra", FAKE_VER_PATCH);
+
+       /* Gfx settings */
+       save_pref_short("arg.arg_sound", arg_sound);
+       save_pref_short("arg.arg_graphics", arg_graphics);
+       save_pref_short("arg.arg_newstyle_graphics", arg_newstyle_graphics);
+       save_pref_short("arg.arg_bigtile", arg_bigtile);
+
+#ifndef MACH_O_CARBON
+
+       /* SoundMode */
+       for( i = 0 ; i < 7 ; i++ )
+               save_pref_short(format("sound%d.on", i), soundmode[i]);
+
+#endif /* MACH_O_CARBON */
+       
+       /* Windows */
+       for (i = 0; i < MAX_TERM_DATA; i++)
+       {
+               term_data *td = &data[i];
+
+               save_pref_short(format("term%d.mapped", i), td->mapped);
+
+               save_pref_short(format("term%d.font_id", i), td->font_id);
+               save_pref_short(format("term%d.font_size", i), td->font_size);
+               save_pref_short(format("term%d.font_face", i), td->font_face);
+
+               save_pref_short(format("term%d.tile_wid", i), td->tile_wid);
+               save_pref_short(format("term%d.tile_hgt", i), td->tile_hgt);
+
+               save_pref_short(format("term%d.cols", i), td->cols);
+               save_pref_short(format("term%d.rows", i), td->rows);
+               save_pref_short(format("term%d.left", i), td->r.left);
+               save_pref_short(format("term%d.top", i), td->r.top);
+       }
+
+       /*
+        * Make sure preferences are persistent
+        */
+       CFPreferencesAppSynchronize(
+               kCFPreferencesCurrentApplication);
+}
+
 
 /*
- * 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.
+ * Load preferences from preferences file for current host+current user+
+ * current application.
  */
-static void SetupAppDir(void)
+static void cf_load_prefs()
 {
-       FCBPBRec fcbBlock;
-       OSErr err = noErr;
-       char errString[100];
+       bool ok;
+       short pref_major, pref_minor, pref_patch, pref_extra;
+       int i;
 
-       /* Get the location of the Angband executable */
-       fcbBlock.ioCompletion = NULL;
-       fcbBlock.ioNamePtr = NULL;
-       fcbBlock.ioVRefNum = 0;
-       fcbBlock.ioRefNum = CurResFile();
-       fcbBlock.ioFCBIndx = 0;
-       err = PBGetFCBInfo(&fcbBlock, FALSE);
-       if (err != noErr)
+       MenuHandle m;
+
+       /* Assume nothing is wrong, yet */
+       ok = TRUE;
+
+       /* Load version information */
+       ok &= query_load_pref_short("version.major", &pref_major);
+       ok &= query_load_pref_short("version.minor", &pref_minor);
+       ok &= query_load_pref_short("version.patch", &pref_patch);
+       ok &= query_load_pref_short("version.extra", &pref_extra);
+
+       /* Any of the above failed */
+       if (!ok)
        {
+               /* This may be the first run */
 #ifdef JP
-               sprintf(errString, "PBGetFCBInfo ¥¨¥é¡¼ #%d.\r ½ªÎ»¤·¤Þ¤¹.", err);
+               mac_warning("½é´üÀßÄê¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£");
 #else
-               sprintf(errString, "Fatal PBGetFCBInfo Error #%d.\r Exiting.", err);
+               mac_warning("Preferences are not found.");
 #endif
-               mac_warning(errString);
-               ExitToShell();
+
+               /* Ignore the rest */
+               return;
        }
 
-       /* Extract the Vol and Dir */
-       app_vol = fcbBlock.ioFCBVRefNum;
-       app_dir = fcbBlock.ioFCBParID;
+#if 0
 
-       /* Set the current working directory to that location */
-       err = HSetVol(NULL, app_vol, app_dir);
-       if (err != noErr)
+       /* Check version */
+       if ((pref_major != PREF_VER_MAJOR) ||
+               (pref_minor != PREF_VER_MINOR) ||
+               (pref_patch != PREF_VER_PATCH) ||
+               (pref_extra != PREF_VER_EXTRA))
        {
-#ifdef JP
-               sprintf(errString, "HSetVol ¥¨¥é¡¼ #%d.\r ½ªÎ»¤·¤Þ¤¹.", err);
-#else
-               sprintf(errString, "Fatal HSetVol Error #%d.\r Exiting.", err);
+               /* Message */
+               mac_warning(
+                       format("Ignoring %d.%d.%d.%d preferences.",
+                               pref_major, pref_minor, pref_patch, pref_extra));
+
+               /* Ignore */
+               return;
+       }
+
 #endif
-               mac_warning(errString);
-               ExitToShell();
+
+       /* Gfx settings */
+       {
+               short pref_tmp;
+
+               /* sound */
+               if (query_load_pref_short("arg.arg_sound", &pref_tmp))
+                       arg_sound = pref_tmp;
+
+               /* graphics */
+               if (query_load_pref_short("arg.arg_graphics", &pref_tmp))
+                       arg_graphics = pref_tmp;
+
+               /*newstyle graphics*/
+               if (query_load_pref_short("arg.arg_newstyle_graphics", &pref_tmp))
+               {
+                       use_newstyle_graphics = pref_tmp;
+               }
+
+               if (use_newstyle_graphics == true)
+               {
+                       ANGBAND_GRAF = "new";
+                       arg_newstyle_graphics = true;
+                       grafWidth = grafHeight = 16;
+                       pictID = 1002;
+               }
+               else
+               {
+                       ANGBAND_GRAF = "old";
+                       arg_newstyle_graphics = false;
+                       grafWidth = grafHeight = 8;
+                       pictID = 1001;
+               }
+
+               /* double-width tiles */
+               if (query_load_pref_short("arg.arg_bigtile", &pref_tmp))
+               {
+                       use_bigtile = pref_tmp;
+               }
+
        }
-}
 
+#ifndef MACH_O_CARBON
+
+       /* SoundMode */
+       for( i = 0 ; i < 7 ; i++ )
+       {
+               query_load_pref_short(format("sound%d.on", i), &soundmode[i]);
+       }
+
+#endif /* MACH_O_CARBON */
+
+       /* Special menu */
+       m = GetMenuHandle(134);
+
+       /* Item "arg_sound" */
+       CheckMenuItem(m, 1, arg_sound);
+
+       /* Item "arg_graphics" */
+       CheckMenuItem(m, 2, arg_graphics);
+       
+       /* Item "arg_newstyle_graphics"*/
+       CheckMenuItem(m, 8, arg_newstyle_graphics);
+
+       /* Item "arg_bigtile"*/
+       CheckMenuItem(m, 9, arg_bigtile);
+
+       /* Windows */
+       for (i = 0; i < MAX_TERM_DATA; i++)
+       {
+               term_data *td = &data[i];
+
+               load_pref_short(format("term%d.mapped", i), &td->mapped);
+
+               load_pref_short(format("term%d.font_id", i), &td->font_id);
+               load_pref_short(format("term%d.font_size", i), &td->font_size);
+               load_pref_short(format("term%d.font_face", i), &td->font_face);
 
+               load_pref_short(format("term%d.tile_wid", i), &td->tile_wid);
+               load_pref_short(format("term%d.tile_hgt", i), &td->tile_hgt);
 
+               load_pref_short(format("term%d.cols", i), &td->cols);
+               load_pref_short(format("term%d.rows", i), &td->rows);
+               load_pref_short(format("term%d.left", i), &td->r.left);
+               load_pref_short(format("term%d.top", i), &td->r.top);
+       }
+}
 
+#else
 /*
  * Global "preference" file pointer
  */
@@ -2589,16 +3480,6 @@ static void load_prefs(void)
        /* Special menu */
        m = GetMenuHandle(134);
 
-#if TARGET_API_MAC_CARBON
-       /* Item "arg_sound" */
-       CheckMenuItem(m, 1, arg_sound);
-
-       /* Item "arg_graphics" */
-       CheckMenuItem(m, 2, arg_graphics);
-       
-       /* Item "arg_newstyle_graphics"*/
-       CheckMenuItem(m, 8, arg_newstyle_graphics);
-#else
        /* Item "arg_sound" */
        CheckItem(m, 1, arg_sound);
 
@@ -2607,7 +3488,9 @@ static void load_prefs(void)
        
        /* Item "arg_newstyle_graphics"*/
        CheckItem(m, 8, arg_newstyle_graphics);
-#endif
+
+       /* Item "arg_bigtile"*/
+       CheckItem(m, 9, arg_bigtile);
 
        /* Windows */
        for (i = 0; i < MAX_TERM_DATA; i++)
@@ -2634,7 +3517,7 @@ static void load_prefs(void)
                if (feof(fff)) break;
        }
 }
-
+#endif /* TARGET_API_MAC_CARBON */
 
 
 
@@ -2645,18 +3528,24 @@ static void term_data_hack(term_data *td)
 {
        short fid;
 
-#ifdef JP
 #if TARGET_API_MAC_CARBON
+#ifdef JP
        /* Default to Osaka font (Japanese) */
        fid = FMGetFontFamilyFromName( "\pOsaka¡ÝÅùÉý" );
 #else
+       /* Default to Monaco font */
+       fid = FMGetFontFamilyFromName("\pmonaco");
+#endif
+#else
+#ifdef JP
+       /* Default to ÅùÉýÌÀÄ« font (Japanese) */
        GetFNum( "\pÅùÉýÌÀÄ«", &fid);
        SetFScaleDisable( true );
-#endif
 #else
        /* Default to Monaco font */
        GetFNum("\pmonaco", &fid);
 #endif
+#endif
 
        /* Wipe it */
        WIPE(td, term_data);
@@ -2707,12 +3596,16 @@ static void init_windows(void)
 
        term_data *td;
 
+#if !TARGET_API_MAC_CARBON
+
        SysEnvRec env;
        short savev;
        long saved;
 
        bool oops;
 
+#endif /* !TARGET_API_MAC_CARBON */
+
 
        /*** Default values ***/
 
@@ -2754,7 +3647,10 @@ static void init_windows(void)
 
 
        /*** Load preferences ***/
-
+       
+#if TARGET_API_MAC_CARBON
+       cf_load_prefs();
+#else
        /* Assume failure */
        oops = TRUE;
 
@@ -2797,8 +3693,6 @@ static void init_windows(void)
 
 #endif /* USE_SFL_CODE */
 
-#if TARGET_API_MAC_CARBON
-#else
        /* Oops */
        if (oops)
        {
@@ -2815,7 +3709,6 @@ static void init_windows(void)
                /* Restore */
                HSetVol(0, savev, saved);
        }
-#endif
 
        /* Load preferences */
        if (fff)
@@ -2826,6 +3719,7 @@ static void init_windows(void)
                /* Close the file */
                my_fclose(fff);
        }
+#endif /* TARGET_API_MAC_CARBON */
 
 
        /*** Instantiate ***/
@@ -2852,6 +3746,8 @@ static void init_windows(void)
        Term_activate(td->t);
 }
 
+#ifndef MACH_O_CARBON
+
 static void init_sound( void )
 {
        int err, i;
@@ -2992,6 +3888,8 @@ static void init_graf( void )
        }
 }
 
+#endif /* MACH_O_CARBON */
+
 #ifdef CHUUKEI
 /*
 
@@ -3094,7 +3992,6 @@ short GetCheck( DialogPtr targetDlg, short check )
 void SoundConfigDLog(void)
 {
        DialogPtr dialog;
-       Rect r;
        short item_hit;
        int     i;
 
@@ -3127,6 +4024,12 @@ void SoundConfigDLog(void)
 /*
  * Exit the program
  */
+#if TARGET_API_MAC_CARBON
+static void save_pref_file(void)
+{
+       cf_save_prefs();
+}
+#else
 static void save_pref_file(void)
 {
        bool oops;
@@ -3183,8 +4086,6 @@ static void save_pref_file(void)
 
 #endif /* USE_SFL_CODE */
 
-#if TARGET_API_MAC_CARBON
-#else
        /* Oops */
        if (oops)
        {
@@ -3202,7 +4103,6 @@ static void save_pref_file(void)
                /* Restore */
                HSetVol(0, savev, saved);
        }
-#endif
 
        /* Save preferences */
        if (fff)
@@ -3214,8 +4114,11 @@ static void save_pref_file(void)
                my_fclose(fff);
        }
 }
+#endif
+
 
 
+#if defined(__MWERKS__)
 
 /*
  * A simple "Yes/No" filter to parse "key press" events in dialog windows
@@ -3262,6 +4165,139 @@ static pascal Boolean ynfilter(DialogPtr dialog, EventRecord *event, short *ip)
        return (0);
 }
 
+#endif /* __MWERKS__ */
+
+
+#if TARGET_API_MAC_CARBON
+
+/*
+ * Prepare savefile dialogue and set the variable
+ * savefile accordingly. Returns true if it succeeds, false (or
+ * aborts) otherwise. If all is false, only allow files whose type
+ * is 'SAVE'.
+ * Originally written by Peter Ammon
+ */
+static bool select_savefile(bool all)
+{
+       OSErr err;
+       FSSpec theFolderSpec;
+       FSSpec savedGameSpec;
+       NavDialogOptions dialogOptions;
+       NavReplyRecord reply;
+       /* Used only when 'all' is true */
+       NavTypeList types = {ANGBAND_CREATOR, 1, 1, {'SAVE'}};
+       NavTypeListHandle myTypeList;
+       AEDesc defaultLocation;
+
+#ifdef MACH_O_CARBON
+
+       /* Find the save folder */
+       err = path_to_spec(ANGBAND_DIR_SAVE, &theFolderSpec);
+
+#else
+
+       /* Find :lib:save: folder */
+       err = FSMakeFSSpec(app_vol, app_dir, "\p:lib:save:", &theFolderSpec);
+
+#endif
+
+       /* Oops */
+       if (err != noErr) quit("Unable to find the folder :lib:save:");
+
+       /* Get default Navigator dialog options */
+       err = NavGetDefaultDialogOptions(&dialogOptions);
+
+       /* Clear preview option */
+       dialogOptions.dialogOptionFlags &= ~kNavAllowPreviews;
+
+       /* Disable multiple file selection */
+       dialogOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles;
+
+       /* Make descriptor for default location */
+       err = AECreateDesc(typeFSS, &theFolderSpec, sizeof(FSSpec),
+               &defaultLocation);
+
+       /* Oops */
+       if (err != noErr) quit("Unable to allocate descriptor");
+
+       /* We are indifferent to signature and file types */
+       if (all)
+       {
+               myTypeList = (NavTypeListHandle)nil;
+       }
+
+       /* Set up type handle */
+       else
+       {
+               err = PtrToHand(&types, (Handle *)&myTypeList, sizeof(NavTypeList));
+
+               /* Oops */
+               if (err != noErr) quit("Error in PtrToHand. Try enlarging heap");
+
+       }
+
+       /* Call NavGetFile() with the types list */
+       err = NavChooseFile(&defaultLocation, &reply, &dialogOptions, NULL,
+               NULL, NULL, myTypeList, NULL);
+
+       /* Free type list */
+       if (!all) DisposeHandle((Handle)myTypeList);
+
+       /* Error */
+       if (err != noErr)
+       {
+               /* Nothing */
+       }
+
+       /* Invalid response -- allow the user to cancel */
+       else if (!reply.validRecord)
+       {
+               /* Hack -- Fake error */
+               err = -1;
+       }
+
+       /* Retrieve FSSpec from the reply */
+       else
+       {
+               AEKeyword theKeyword;
+               DescType actualType;
+               Size actualSize;
+
+               /* Get a pointer to selected file */
+               (void)AEGetNthPtr(&reply.selection, 1, typeFSS, &theKeyword,
+                       &actualType, &savedGameSpec, sizeof(FSSpec), &actualSize);
+
+               /* Dispose NavReplyRecord, resources and descriptors */
+               (void)NavDisposeReply(&reply);
+       }
+
+       /* Dispose location info */
+       AEDisposeDesc(&defaultLocation);
+
+       /* Error */
+       if (err != noErr) return (FALSE);
+
+#ifdef MACH_O_CARBON
+
+       /* Convert FSSpec to pathname and store it in variable savefile */
+       (void)spec_to_path(&savedGameSpec, savefile, sizeof(savefile));
+
+#else
+
+       /* Convert FSSpec to pathname and store it in variable savefile */
+       refnum_to_name(
+               savefile,
+               savedGameSpec.parID,
+               savedGameSpec.vRefNum,
+               (char *)savedGameSpec.name);
+
+#endif
+
+       /* Success */
+       return (TRUE);
+}
+#endif
+
 
 /*
  * Handle menu: "File" + "New"
@@ -3291,37 +4327,14 @@ static void do_menu_file_new(void)
 #if TARGET_API_MAC_CARBON
 static void do_menu_file_open(bool all)
 {
-       int err;
-       short vrefnum;
-       long drefnum;
-       long junk;
-       DirInfo pb;
-       SFTypeList types;
-       SFReply reply;
-       Point topleft;
-       BitMap screen;
-       FSSpec  fsp;
-       char path[1024];
-       
-       refnum_to_name(path, app_dir, app_vol, (char*)("\plib:save:"));
-       
-       FSpLocationFromFullPath( strlen(path), path, &fsp );
-       
-       /* Get any file */
-       ChooseFile( (StringPtr)savefile, fsp );
-       
-       /* Allow cancel */
-       if (err != noErr) return;
+       /* Let the player to choose savefile */
+       if (!select_savefile(all)) 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;
+       game_in_progress = TRUE;
 
        /* Flush input */
        flush();
@@ -4924,6 +5937,13 @@ static pascal OSErr AEH_Open(const AppleEvent *theAppleEvent,
        /* Ignore non 'SAVE' files */
        if (myFileInfo.fdType != 'SAVE') return noErr;
 
+#ifdef MACH_O_CARBON
+
+       /* Extract a file name */
+       (void)spec_to_path(&myFSS, savefile, sizeof(savefile));
+
+#else
+
        /* XXX XXX XXX Extract a file name */
        PathNameFromDirID(myFSS.parID, myFSS.vRefNum, (StringPtr)savefile);
        pstrcat((StringPtr)savefile, (StringPtr)&myFSS.name);
@@ -4931,6 +5951,8 @@ static pascal OSErr AEH_Open(const AppleEvent *theAppleEvent,
        /* Convert the string */
        ptocstr((StringPtr)savefile);
 
+#endif /* MACH_O_CARBON */
+
        /* Delay actual open */
        open_when_ready = TRUE;
 
@@ -5497,7 +6519,7 @@ static vptr hook_rpanic(huge size)
 
 #pragma unused (size)
 
-       vptr mem = NULL;
+       /* vptr mem = NULL; */
 
        /* Free the lifeboat */
        if (lifeboat)
@@ -5541,6 +6563,13 @@ static void hook_quit(cptr str)
        /* Warning if needed */
        if (str) mac_warning(str);
 
+#ifdef USE_ASYNC_SOUND
+
+       /* Clean up sound support */
+       cleanup_sound();
+
+#endif /* USE_ASYNC_SOUND */
+
        /* Write a preference file */
        save_pref_file();
 
@@ -5600,12 +6629,14 @@ static void init_stuff(void)
 {
        int i;
 
+#if !TARGET_API_MAC_CARBON
        short vrefnum;
        long drefnum;
        long junk;
 
        SFTypeList types;
        SFReply reply;
+#endif
 
        Rect r;
        Point topleft;
@@ -5641,7 +6672,11 @@ static void init_stuff(void)
 
 
        /* Default to the "lib" folder with the application */
+#ifdef MACH_O_CARBON
+       if (locate_lib(path, sizeof(path)) == NULL) quit(NULL);
+#else
        refnum_to_name(path, app_dir, app_vol, (char*)("\plib:"));
+#endif
 
 
        /* Check until done */
@@ -5788,7 +6823,7 @@ static void init_stuff(void)
 /*
  * Macintosh Main loop
  */
-void main(void)
+int main(void)
 {
        EventRecord tempEvent;
        int numberOfMasters = 10;
@@ -5842,6 +6877,19 @@ void main(void)
 
 # else
 
+#if TARGET_API_MAC_CARBON
+
+       {
+               OSErr err;
+               long response;
+
+               /* Check for existence of Carbon */
+               err = Gestalt(gestaltCarbonVersion, &response);
+
+               if (err != noErr) quit("This program requires Carbon API");
+       }
+
+#else
        /* Block */
        if (TRUE)
        {
@@ -5898,7 +6946,8 @@ void main(void)
                }
        }
 
-# endif
+#endif /* CARBON */
+#endif
 
 #endif /* ANGBAND_LITE_MAC */
 
@@ -5934,12 +6983,13 @@ void main(void)
                              0L, FALSE);
 #endif
 
+#ifndef MACH_O_CARBON
        /* Find the current application */
        SetupAppDir();
-
+#endif
 
        /* Mark ourself as the file creator */
-       _fcreator = 'Heng';
+       _fcreator = ANGBAND_CREATOR;
 
        /* Default to saving a "text" file */
        _ftype = 'TEXT';
@@ -5979,9 +7029,13 @@ void main(void)
        /* Prepare the windows */
        init_windows();
 
+#ifndef MACH_O_CARBON
+
        init_sound();
 
        init_graf();
+
+#endif
        
        /* Hack -- process all events */
        while (CheckEvents(TRUE)) /* loop */;
@@ -6007,6 +7061,9 @@ void main(void)
        /* Initialize */
        init_stuff();
 
+       /* Catch nasty signals */
+       signals_init();
+
        /* Initialize */
        init_angband();