shithub: duke3d

Download patch

ref: 902ed01830d2a92579df825d8babf5bf2ac0a021
parent: 62984ca13048b15166da4511f10c43d747980e85
author: Fabien Sanglard <[email protected]>
date: Wed Dec 12 21:36:22 EST 2012

Compile and run on MacOS X :)

--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
 .xcuserstate
 *.xcuserdatad
 .DS_Store
+xcshareddata
--- a/Engine/src/a.c
+++ b/Engine/src/a.c
@@ -189,10 +189,12 @@
     {
 	    i1 += i4;
         
+        //FCS
         //((unsigned long)i4) >>= mach3_al;
-        unsigned long tmp = i4;
-	    tmp >>= mach3_al;
-        i4 = tmp;
+        i4 = ((unsigned long)i4) >> mach3_al;
+        //unsigned long tmp = i4;
+	    //tmp >>= mach3_al;
+        //i4 = tmp;
         
 	    i4 = (i4&0xffffff00) | (source[i4]&0xff);
 	    *dest = ((unsigned char*)i2)[i4];
@@ -202,6 +204,9 @@
     }
 } /* prevlineasm1 */
 
+//FCS:Debug
+//extern unsigned char * get_framebuffer(void);
+
 /* #pragma aux vlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */
 long vlineasm1(long vince, long palookupoffse, long i3, long vplce, long bufplce, long i6)
 {
@@ -208,12 +213,17 @@
     unsigned long temp;
     unsigned char *dest = (unsigned char *)i6;
 
+    
     i3++;
     while (i3)
     {
 	    temp = ((unsigned)vplce) >> mach3_al;
+        
 	    temp = ((unsigned char *)bufplce)[temp];
-	    *dest = ((unsigned char*)palookupoffse)[temp];
+        //temp = ((unsigned int *)bufplce)[temp];
+        
+    //    if (dest < (get_framebuffer()+(640*480)))
+        *dest = ((unsigned char*)palookupoffse)[temp];
 	    vplce += vince;
 	    dest += fixchain;
 	    i3--;
--- a/Engine/src/cache1d.c
+++ b/Engine/src/cache1d.c
@@ -359,6 +359,11 @@
 		}
 		gfileoffs[numgroupfiles][gnumfiles[numgroupfiles]] = j;
 	}
+    else
+    {
+        printf("Unable to find GRP file %s.\n",filename);
+        exit(0);
+    }
 
 	// Compute CRC32 of thw whole grp and implicitely caches the GRP in memory through windows
 	lseek(groupfil[numgroupfiles], 0, SEEK_SET);
@@ -722,6 +727,15 @@
 	return(-1);
 #endif
 }
+
+#ifdef __APPLE__
+long filelength(long fd)
+{
+    struct stat stats;
+    fstat(fd, &stats);
+    return stats.st_size;
+}
+#endif
 
 long kfilelength(long handle)
 {
--- /dev/null
+++ b/Engine/src/dummy_multi.c
@@ -1,0 +1,16 @@
+//
+//  dummy.c
+//  Duke3D
+//
+//  Created by fabien sanglard on 12-12-12.
+//  Copyright (c) 2012 fabien sanglard. All rights reserved.
+//
+
+#include "build.h"
+
+
+short numplayers = 0, myconnectindex = 0;
+short connecthead, connectpoint2[MAXPLAYERS];
+
+
+char syncstate=0;
\ No newline at end of file
--- a/Engine/src/engine.c
+++ b/Engine/src/engine.c
@@ -1023,8 +1023,18 @@
 		palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8);
 
 		bufplce[0] = lwal[x] + globalxpanning;
-		if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; }
-		if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy;
+		if (bufplce[0] >= tsizx)
+        {
+            if (xnice == 0)
+                bufplce[0] %= tsizx;
+            else
+                bufplce[0] &= tsizx;
+        }
+        
+		if (ynice == 0)
+            bufplce[0] *= tsizy;
+        else
+            bufplce[0] <<= tsizy;
 
 		vince[0] = swal[x]*globalyscale;
 		vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);
@@ -1038,7 +1048,12 @@
 		{
 			y1ve[z] = max(uwal[x+z],umost[x+z]);
 			y2ve[z] = min(dwal[x+z],dmost[x+z])-1;
-			if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }
+            
+			if (y2ve[z] < y1ve[z])
+            {
+                bad += pow2char[z];
+                continue;
+            }
 
 			i = lwal[x+z] + globalxpanning;
 			if (i >= tsizx) { if (xnice == 0) i %= tsizx; else i &= tsizx; }
@@ -1048,6 +1063,7 @@
 			vince[z] = swal[x+z]*globalyscale;
 			vplce[z] = globalzd + vince[z]*(y1ve[z]-globalhoriz+1);
 		}
+        
 		if (bad == 15) continue;
 
 		palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8);
--- a/Engine/src/macos_compat.h
+++ b/Engine/src/macos_compat.h
@@ -47,6 +47,12 @@
 #define IP_RECVERR  SO_BROADCAST
 
 #define stricmp strcasecmp
+#define strcmpi strcasecmp
 
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
 
 #endif
--- a/Engine/src/sdl_driver.c
+++ b/Engine/src/sdl_driver.c
@@ -55,6 +55,28 @@
 */
 /**/
 
+
+// NATIVE TIMER FUNCTION DECLARATION
+/*
+ FCS: The timer section sadly uses Native high precision calls to implement timer functions.
+ QueryPerformanceFrequency and QueryPerformanceCounter
+ it seems SDL precision was not good enough (or rather using unaccurate OS functions) to replicate
+ a DOS timer.
+ */
+
+int TIMER_GetPlatformTicksInOneSecond(int64_t* t);
+void TIMER_GetPlatformTicks(int64_t* t);
+
+//END // NATIVE TIMER FUNCTION DECLARATION
+
+
+
+
+// NETWORK STUFF
+#ifdef __APPLE__
+  #define USER_DUMMY_NETWORK 1
+#endif 
+
 void Setup_UnstableNetworking();
 void Setup_StableNetworking();
 
@@ -67,6 +89,7 @@
 // This mess shouldn't even be in this file. /slap /slap
 void callcommit(void)
 {
+#ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:		
@@ -76,9 +99,11 @@
 		stable_callcommit();
 		break;		
 	}
+#endif
 }
 void initcrc(void)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:	
@@ -88,9 +113,11 @@
 		stable_initcrc();
 		break;
 	}
+#endif
 }
 long getcrc(char *buffer, short bufleng)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -98,11 +125,12 @@
 	case 1:
 		return stable_getcrc(buffer, bufleng);
 	}
-
+#endif
 	return 0;
 }
 void initmultiplayers(char damultioption, char dacomrateoption, char dapriority)
 {
+#ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -112,9 +140,11 @@
 		stable_initmultiplayers(damultioption, dacomrateoption, dapriority);
 		break;
 	}
+#endif
 }
 void sendpacket(long other, char *bufptr, long messleng)
 {
+#ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -124,9 +154,11 @@
 		stable_sendpacket(other, bufptr, messleng);
 		break;
 	}
+#endif
 }
 void setpackettimeout(long datimeoutcount, long daresendagaincount)
 {
+#ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -136,10 +168,11 @@
 		stable_setpackettimeout(datimeoutcount, daresendagaincount);
 		break;
 	}
-
+#endif
 }
 void uninitmultiplayers(void)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -149,9 +182,11 @@
 		stable_uninitmultiplayers();
 		break;
 	}
+#endif
 }
 void sendlogon(void)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -161,9 +196,11 @@
 		unstable_sendlogon();
 		break;
 	}
+#endif
 }
 void sendlogoff(void)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -173,9 +210,11 @@
 		stable_sendlogoff();
 		break;
 	}
+#endif
 }
 int  getoutputcirclesize(void)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -183,11 +222,12 @@
 	case 1:
 		return stable_getoutputcirclesize();		
 	}
-
+#endif
 	return 0;
 }
 void setsocket(short newsocket)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -197,9 +237,11 @@
 		stable_setsocket(newsocket);
 		break;
 	}
+#endif
 }
 short getpacket(short *other, char *bufptr)
 {
+#ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -207,11 +249,12 @@
 	case 1:
 		return stable_getpacket(other, bufptr);
 	}
-
+#endif
 	return 0;
 }
 void flushpackets(void)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -221,9 +264,11 @@
 		stable_flushpackets();
 		break;
 	}
+#endif
 }
 void genericmultifunction(long other, char *bufptr, long messleng, long command)
 {
+    #ifndef USER_DUMMY_NETWORK
 	switch(nNetMode)
 	{
 	case 0:
@@ -233,6 +278,7 @@
 		stable_genericmultifunction(other, bufptr, messleng, command);
 		break;
 	}
+#endif
 }
 
 #if (defined USE_OPENGL)
@@ -451,7 +497,7 @@
 } /* output_driver_info */
 
 
-static Uint8 *get_framebuffer(void)
+Uint8 *get_framebuffer(void)
 {
     assert(renderer != RENDERER_OPENGL3D);
 
@@ -723,7 +769,7 @@
 	SDL_QuitSubSystem(SDL_INIT_VIDEO);
 	_platform_init(0, NULL, "Duke Nukem 3D", "Duke3D");
 	_setgamemode(ScreenMode,x,y);
-	vscrn();
+	//vscrn();
 
 	return;
 }
@@ -1047,7 +1093,7 @@
 void set_sdl_renderer(void)
 {
     const char *envr = getenv(BUILD_RENDERER);
-
+    char buffer[256];
 #ifdef USE_OPENGL
     int need_opengl_lib = 0;
 #endif
@@ -1054,18 +1100,6 @@
 
     if ((envr == NULL) || (strcmp(envr, ENVRSTR_RENDERER_SOFTWARE) == 0))
         renderer = RENDERER_SOFTWARE;
-
-#ifdef USE_OPENGL
-#if 0
-    else if (strcmp(envr, ENVRSTR_RENDERER_OPENGL3D) == 0)
-    {
-        renderer = RENDERER_OPENGL3D;
-        need_opengl_lib = 1;
-    } /* else if */
-#endif
-
-#endif
-
     else
     {
         fprintf(stderr,
@@ -1074,7 +1108,11 @@
         _exit(1);
     } /* else */
 
-    if (SDL_Init(SDL_INIT_VIDEO |SDL_INIT_NOPARACHUTE) == -1)
+#ifdef __APPLE__
+    SDL_putenv("SDL_VIDEODRIVER=Quartz");
+#endif
+    
+    if (SDL_Init(SDL_INIT_VIDEO) == -1)
     {
 		Error(EXIT_FAILURE, "BUILDSDL: SDL_Init() failed!\n"
 							"BUILDSDL: SDL_GetError() says \"%s\".\n", SDL_GetError());
@@ -1164,7 +1202,7 @@
     _argv = argv;
 
 	// FIX_00061: "ERROR: Two players have the same random ID" too frequent cuz of internet windows times
-    QueryPerformanceCounter(&timeElapsed);
+    TIMER_GetPlatformTicks(&timeElapsed);
 	srand(timeElapsed&0xFFFFFFFF);
 
 	Setup_UnstableNetworking();
@@ -2276,15 +2314,7 @@
 //  TIMER
 //=================================================================================================
 
-/*
- FCS: The timer section sadly uses Native high precision calls to implement timer functions.
- QueryPerformanceFrequency and QueryPerformanceCounter
- it seems SDL precision was not good enough (or rather using unaccurate OS functions) to replicate
- a DOS timer.
- */
 
-int TIMER_GetPlatformTicksInOneSecond(int64_t* t);
-void TIMER_GetPlatformTicks(int64_t* t);
 
 
 // FIX_00007: game speed corrected. The game speed is now as the real
--- a/Game/src/config.c
+++ b/Game/src/config.c
@@ -65,7 +65,7 @@
 
 int32 ControllerType;
 int32 MouseAiming = 0;
-int32 BFullScreen = 1;
+int32 BFullScreen = 0;
 
 //
 // Screen variables
--- a/Game/src/dukeunix.h
+++ b/Game/src/dukeunix.h
@@ -98,4 +98,6 @@
 // Giving all access is ugly but it is just game OK !
 #define mkdir(X) mkdir(X,0777)
 
+#define getch getchar
+
 #endif
--- /dev/null
+++ b/Game/src/dummy_audiolib.c
@@ -1,0 +1,195 @@
+//
+//  dummy_audiolib.c
+//  Duke3D
+//
+//  Created by fabien sanglard on 12-12-12.
+//  Copyright (c) 2012 fabien sanglard. All rights reserved.
+//
+
+#include "audiolib/fx_man.h"
+
+char *FX_ErrorString( int ErrorNumber ){
+   static char nope = '\0';
+    return &nope;
+}
+
+int   FX_SetupCard( int SoundCard, fx_device *device ){return 1;}
+int   FX_GetBlasterSettings( fx_blaster_config *blaster ){return 1;}
+int   FX_SetupSoundBlaster( fx_blaster_config blaster, int *MaxVoices, int *MaxSampleBits, int *MaxChannels ){return 1;}
+int   FX_Init( int SoundCard, int numvoices, int numchannels, int samplebits, unsigned mixrate ){return FX_Ok;}
+int   FX_Shutdown( void ){return 1;}
+int   FX_SetCallBack( void ( *function )( unsigned long ) ){return FX_Ok;}
+void  FX_SetVolume( int volume ){}
+int   FX_GetVolume( void ){return 1;}
+
+void  FX_SetReverseStereo( int setting ){}
+int   FX_GetReverseStereo( void ){return 1;}
+void  FX_SetReverb( int reverb ){}
+void  FX_SetFastReverb( int reverb ){}
+int   FX_GetMaxReverbDelay( void ){}
+int   FX_GetReverbDelay( void ){return 1;}
+void  FX_SetReverbDelay( int delay ){}
+
+int FX_VoiceAvailable( int priority ){return 1;}
+int FX_EndLooping( int handle ){return 1;}
+int FX_SetPan( int handle, int vol, int left, int right ){return 1;}
+int FX_SetPitch( int handle, int pitchoffset ){return 1;}
+int FX_SetFrequency( int handle, int frequency ){return 1;}
+
+int FX_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right,
+               int priority, unsigned long callbackval ){return 1;}
+int FX_PlayLoopedVOC( char *ptr, long loopstart, long loopend,
+                     int pitchoffset, int vol, int left, int right, int priority,
+                     unsigned long callbackval ){return 1;}
+int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right,
+               int priority, unsigned long callbackval ){return 1;}
+int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend,
+                     int pitchoffset, int vol, int left, int right, int priority,
+                     unsigned long callbackval ){return 1;}
+int FX_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance,
+                 int priority, unsigned long callbackval ){return 1;}
+int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance,
+                 int priority, unsigned long callbackval ){return 1;}
+int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate,
+               int pitchoffset, int vol, int left, int right, int priority,
+               unsigned long callbackval ){return 1;}
+int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart,
+                     char *loopend, unsigned rate, int pitchoffset, int vol, int left,
+                     int right, int priority, unsigned long callbackval ){return 1;}
+int FX_Pan3D( int handle, int angle, int distance ){return 1;}
+int FX_SoundActive( int handle ){return 1;}
+int FX_SoundsPlaying( void ){return 0;}
+int FX_StopSound( int handle ){return 1;}
+int FX_StopAllSounds( void ){return 1;}
+int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ),
+                               int rate, int pitchoffset, int vol, int left, int right,
+                               int priority, unsigned long callbackval ){return 1;}
+int  FX_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) ){return 1;}
+void FX_StopRecord( void ){}
+
+
+
+
+//Dummy music
+#include "audiolib/music.h"
+
+char *MUSIC_ErrorString(int ErrorNumber)
+{
+	return "";
+}
+
+int MUSIC_Init(int SoundCard, int Address)
+{
+	return 0;
+}
+
+int MUSIC_Shutdown(void)
+{
+	return 0;
+}
+
+void MUSIC_SetMaxFMMidiChannel(int channel)
+{
+}
+
+void MUSIC_SetVolume(int volume)
+{
+}
+
+void MUSIC_SetMidiChannelVolume(int channel, int volume)
+{
+}
+
+void MUSIC_ResetMidiChannelVolumes(void)
+{
+}
+
+int MUSIC_GetVolume(void)
+{
+	return 0;
+}
+
+void MUSIC_SetLoopFlag(int loopflag)
+{
+}
+
+int MUSIC_SongPlaying(void)
+{
+	return 0;
+}
+
+void MUSIC_Continue(void)
+{
+}
+
+void MUSIC_Pause(void)
+{
+}
+
+int MUSIC_StopSong(void)
+{
+	return 0;
+}
+
+int MUSIC_PlaySong(unsigned char *song, int loopflag)
+{
+	return 0;
+}
+
+
+void MUSIC_SetContext(int context)
+{
+}
+
+int MUSIC_GetContext(void)
+{
+	return 0;
+}
+
+void MUSIC_SetSongTick(unsigned long PositionInTicks)
+{
+}
+
+void MUSIC_SetSongTime(unsigned long milliseconds)
+{
+}
+
+void MUSIC_SetSongPosition(int measure, int beat, int tick)
+{
+}
+
+void MUSIC_GetSongPosition(songposition *pos)
+{
+}
+
+void MUSIC_GetSongLength(songposition *pos)
+{
+}
+
+int MUSIC_FadeVolume(int tovolume, int milliseconds)
+{
+	return 0;
+}
+
+int MUSIC_FadeActive(void)
+{
+	return 0;
+}
+
+void MUSIC_StopFade(void)
+{
+}
+
+void MUSIC_RerouteMidiChannel(int channel, int cdecl function( int event, int c1, int c2 ))
+{
+}
+
+void MUSIC_RegisterTimbreBank(unsigned char *timbres)
+{
+}
+
+void PlayMusic(short dummy)
+{
+        
+}
+
--- a/Game/src/game.c
+++ b/Game/src/game.c
@@ -26,6 +26,8 @@
 
 #ifdef _WIN32
   #include <windows.h>
+#elif defined(__APPLE__)
+  #include "SDL.h"
 #endif
 
 #include "types.h"
@@ -349,7 +351,14 @@
 void gamenumber(long x,long y,long n,char s)
 {
     char b[10];
-    ltoa(n,b,10);
+    
+    
+    //
+    // char * ltoa(long l, char * buffer, int radix);
+    // is NON-STANDARD and equivalent to STANDARD
+    // (void) sprintf(buffer, "%ld", l);
+    //ltoa(n,b,10);
+    sprintf(b,"%ld",n);
     gametext(x,y,b,s,2+8+16);
 }
 
@@ -1195,6 +1204,7 @@
           //printext256(4L,138L,31,0,"RUN DN3DHELP.EXE for information.",0);
           minitext(21,30+35+30, "Missed Network packet!", COLOR_ON,2+8+16);
       }
+ 
 }
 
 
@@ -1637,7 +1647,13 @@
     short i, j, k, p, c;
     char b[10];
 
-    ltoa(n,b,10);
+    //
+    // char * ltoa(long l, char * buffer, int radix);
+    // is NON-STANDARD and equivalent to STANDARD
+    // (void) sprintf(buffer, "%ld", l);
+    //ltoa(n,b,10);
+    sprintf(b,"%ld",n);
+    
     i = strlen(b);
     j = 0;
 
@@ -8087,7 +8103,7 @@
 		sprintf(groupfilefullpath, "%s", groupfile[kbdKey-'1']);
 	}
 	
-	FindClose(hFind);
+	FindClose(hFind);sprintf(groupfilefullpath, "%s\\%s", game_dir, grpName);
 }
 
 #else
@@ -8094,8 +8110,9 @@
 
 void findGRPToUse(char* game_dir,char* baseDir,char* groupfilefullpath){
     
-    char *grpName="DUKE3D.GRP";
-    sprintf(groupfilefullpath, "%s\\%s", game_dir, grpName);
+    //char *grpName="DUKE3D.GRP";
+    //sprintf(groupfilefullpath, "%s\\%s", game_dir, grpName);
+    sprintf(groupfilefullpath, "%s","/Users/fabiensanglard/Desktop/DUKE3D.GRP");
     printf("The ONLY GRP location for this port is '%s'.\n",groupfilefullpath);
 }
 
@@ -10723,7 +10740,7 @@
 	char score[20];
 	time_t time4file;
 	struct tm *tmHMS;
-	
+    
 
 	// xduke: Build a nice name w/ date and players name if in multi mode.
 	time(&time4file);
@@ -10752,7 +10769,8 @@
 			if(ud.m_coop==0 || ud.m_coop==2)  // if DM or DM No spawn. Add Score as well
 			{
 				strcat(tempbuf, "(");
-				strcat(tempbuf, itoa(ps[i].frag-ps[i].fraggedself, score, 10));
+                snprintf(ps[i].frag-ps[i].fraggedself, sizeof(ps[i].frag-ps[i].fraggedself), "%d", score);
+				strcat(tempbuf, ps[i].frag-ps[i].fraggedself);
 				strcat(tempbuf, ") vs ");
 			}
 			else
--- a/xcode/Duke3D.xcodeproj/project.pbxproj
+++ b/xcode/Duke3D.xcodeproj/project.pbxproj
@@ -18,10 +18,6 @@
 		2D7B62251678885A00E35E54 /* unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B620D1678885A00E35E54 /* unix.c */; };
 		2D7B62261678885A00E35E54 /* win32.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B620E1678885A00E35E54 /* win32.c */; };
 		2D7B62271678885A00E35E54 /* engine.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B62101678885A00E35E54 /* engine.c */; };
-		2D7B62281678885A00E35E54 /* mmulti_stable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B62131678885A00E35E54 /* mmulti_stable.cpp */; };
-		2D7B62291678885A00E35E54 /* mmulti.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B62161678885A00E35E54 /* mmulti.c */; };
-		2D7B622A1678885A00E35E54 /* mmulti.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B62171678885A00E35E54 /* mmulti.cpp */; };
-		2D7B622B1678885A00E35E54 /* multi.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B62181678885A00E35E54 /* multi.c */; };
 		2D7B622C1678885A00E35E54 /* pragmas.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B621A1678885A00E35E54 /* pragmas.c */; };
 		2D7B622D1678885A00E35E54 /* sdl_driver.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B621C1678885A00E35E54 /* sdl_driver.c */; };
 		2D7B623616788ACE00E35E54 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D7B623416788AB200E35E54 /* Cocoa.framework */; };
@@ -47,6 +43,10 @@
 		2D7B627F16788F9B00E35E54 /* scriplib.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B626516788F9B00E35E54 /* scriplib.c */; };
 		2D7B628016788F9B00E35E54 /* sector.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B626716788F9B00E35E54 /* sector.c */; };
 		2D7B628116788F9B00E35E54 /* sounds.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B626A16788F9B00E35E54 /* sounds.c */; };
+		2D7B62FF16790E8100E35E54 /* dummy_audiolib.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B62FE16790E8000E35E54 /* dummy_audiolib.c */; };
+		2D7B630116791C0300E35E54 /* dummy_multi.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B630016791C0200E35E54 /* dummy_multi.c */; };
+		2D7B7AEE16792D6700DB503A /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D7B7AED16792D6700DB503A /* SDLMain.m */; };
+		2D7B7B121679325D00DB503A /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D7B7B111679325D00DB503A /* CoreFoundation.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -95,12 +95,6 @@
 		2D7B62101678885A00E35E54 /* engine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = engine.c; path = ../../Engine/src/engine.c; sourceTree = "<group>"; };
 		2D7B62111678885A00E35E54 /* engine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = engine.h; path = ../../Engine/src/engine.h; sourceTree = "<group>"; };
 		2D7B62121678885A00E35E54 /* icon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = icon.h; path = ../../Engine/src/icon.h; sourceTree = "<group>"; };
-		2D7B62131678885A00E35E54 /* mmulti_stable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mmulti_stable.cpp; path = ../../Engine/src/mmulti_stable.cpp; sourceTree = "<group>"; };
-		2D7B62141678885A00E35E54 /* mmulti_stable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mmulti_stable.h; path = ../../Engine/src/mmulti_stable.h; sourceTree = "<group>"; };
-		2D7B62151678885A00E35E54 /* mmulti_unstable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mmulti_unstable.h; path = ../../Engine/src/mmulti_unstable.h; sourceTree = "<group>"; };
-		2D7B62161678885A00E35E54 /* mmulti.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mmulti.c; path = ../../Engine/src/mmulti.c; sourceTree = "<group>"; };
-		2D7B62171678885A00E35E54 /* mmulti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mmulti.cpp; path = ../../Engine/src/mmulti.cpp; sourceTree = "<group>"; };
-		2D7B62181678885A00E35E54 /* multi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = multi.c; path = ../../Engine/src/multi.c; sourceTree = "<group>"; };
 		2D7B62191678885A00E35E54 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = ../../Engine/src/platform.h; sourceTree = "<group>"; };
 		2D7B621A1678885A00E35E54 /* pragmas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pragmas.c; path = ../../Engine/src/pragmas.c; sourceTree = "<group>"; };
 		2D7B621B1678885A00E35E54 /* pragmas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pragmas.h; path = ../../Engine/src/pragmas.h; sourceTree = "<group>"; };
@@ -162,6 +156,11 @@
 		2D7B626C16788F9B00E35E54 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = types.h; path = ../../Game/src/types.h; sourceTree = "<group>"; };
 		2D7B626D16788F9B00E35E54 /* util_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util_lib.h; path = ../../Game/src/util_lib.h; sourceTree = "<group>"; };
 		2D7B62FD167905C400E35E54 /* dukeunix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dukeunix.h; path = ../../Game/src/dukeunix.h; sourceTree = "<group>"; };
+		2D7B62FE16790E8000E35E54 /* dummy_audiolib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dummy_audiolib.c; path = ../../Game/src/dummy_audiolib.c; sourceTree = "<group>"; };
+		2D7B630016791C0200E35E54 /* dummy_multi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dummy_multi.c; path = ../../Engine/src/dummy_multi.c; sourceTree = "<group>"; };
+		2D7B7AED16792D6700DB503A /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = "<group>"; };
+		2D7B7AEF16792D8900DB503A /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = "<group>"; };
+		2D7B7B111679325D00DB503A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -169,6 +168,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				2D7B7B121679325D00DB503A /* CoreFoundation.framework in Frameworks */,
 				2D7B623816788AF800E35E54 /* SDL.framework in Frameworks */,
 				2D7B623716788AE200E35E54 /* SDL_mixer.framework in Frameworks */,
 				2D7B623616788ACE00E35E54 /* Cocoa.framework in Frameworks */,
@@ -181,6 +181,7 @@
 		2D7B61D3167886FB00E35E54 = {
 			isa = PBXGroup;
 			children = (
+				2D7B7B111679325D00DB503A /* CoreFoundation.framework */,
 				2D7B61E1167886FB00E35E54 /* Duke3D */,
 				2D7B61DF167886FB00E35E54 /* Products */,
 			);
@@ -202,6 +203,8 @@
 				2D7B623216788AAB00E35E54 /* SDL_mixer.framework */,
 				2D7B623016788A9B00E35E54 /* SDL.framework */,
 				2D7B61F01678884400E35E54 /* Engine */,
+				2D7B7AED16792D6700DB503A /* SDLMain.m */,
+				2D7B7AEF16792D8900DB503A /* SDLMain.h */,
 			);
 			path = Duke3D;
 			sourceTree = "<group>";
@@ -220,12 +223,6 @@
 				2D7B62101678885A00E35E54 /* engine.c */,
 				2D7B62111678885A00E35E54 /* engine.h */,
 				2D7B62121678885A00E35E54 /* icon.h */,
-				2D7B62131678885A00E35E54 /* mmulti_stable.cpp */,
-				2D7B62141678885A00E35E54 /* mmulti_stable.h */,
-				2D7B62151678885A00E35E54 /* mmulti_unstable.h */,
-				2D7B62161678885A00E35E54 /* mmulti.c */,
-				2D7B62171678885A00E35E54 /* mmulti.cpp */,
-				2D7B62181678885A00E35E54 /* multi.c */,
 				2D7B62191678885A00E35E54 /* platform.h */,
 				2D7B621A1678885A00E35E54 /* pragmas.c */,
 				2D7B621B1678885A00E35E54 /* pragmas.h */,
@@ -232,6 +229,7 @@
 				2D7B621C1678885A00E35E54 /* sdl_driver.c */,
 				2D7B622E1678887600E35E54 /* win32_compat.h */,
 				2D7B622F1678895A00E35E54 /* macos_compat.h */,
+				2D7B630016791C0200E35E54 /* dummy_multi.c */,
 			);
 			name = Engine;
 			sourceTree = "<group>";
@@ -325,6 +323,7 @@
 				2D7B626C16788F9B00E35E54 /* types.h */,
 				2D7B626D16788F9B00E35E54 /* util_lib.h */,
 				2D7B62FD167905C400E35E54 /* dukeunix.h */,
+				2D7B62FE16790E8000E35E54 /* dummy_audiolib.c */,
 			);
 			name = Game;
 			sourceTree = "<group>";
@@ -404,10 +403,6 @@
 				2D7B62251678885A00E35E54 /* unix.c in Sources */,
 				2D7B62261678885A00E35E54 /* win32.c in Sources */,
 				2D7B62271678885A00E35E54 /* engine.c in Sources */,
-				2D7B62281678885A00E35E54 /* mmulti_stable.cpp in Sources */,
-				2D7B62291678885A00E35E54 /* mmulti.c in Sources */,
-				2D7B622A1678885A00E35E54 /* mmulti.cpp in Sources */,
-				2D7B622B1678885A00E35E54 /* multi.c in Sources */,
 				2D7B622C1678885A00E35E54 /* pragmas.c in Sources */,
 				2D7B622D1678885A00E35E54 /* sdl_driver.c in Sources */,
 				2D7B626E16788F9B00E35E54 /* actors.c in Sources */,
@@ -430,6 +425,9 @@
 				2D7B627F16788F9B00E35E54 /* scriplib.c in Sources */,
 				2D7B628016788F9B00E35E54 /* sector.c in Sources */,
 				2D7B628116788F9B00E35E54 /* sounds.c in Sources */,
+				2D7B62FF16790E8100E35E54 /* dummy_audiolib.c in Sources */,
+				2D7B630116791C0300E35E54 /* dummy_multi.c in Sources */,
+				2D7B7AEE16792D6700DB503A /* SDLMain.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -440,7 +438,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
@@ -469,7 +467,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = YES;
--- /dev/null
+++ b/xcode/Duke3D/SDLMain.h
@@ -1,0 +1,11 @@
+/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
+ Initial Version: Darrell Walisser <[email protected]>
+ Non-NIB-Code & other changes: Max Horn <[email protected]>
+ 
+ Feel free to customize this file to suit your needs
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface SDLMain : NSObject
+@end
\ No newline at end of file
--- /dev/null
+++ b/xcode/Duke3D/SDLMain.m
@@ -1,0 +1,383 @@
+/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
+ Initial Version: Darrell Walisser <[email protected]>
+ Non-NIB-Code & other changes: Max Horn <[email protected]>
+ 
+ Feel free to customize this file to suit your needs
+ */
+
+#import "SDL.h"
+#import "SDLMain.h"
+#import <sys/param.h> /* for MAXPATHLEN */
+#import <unistd.h>
+
+/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
+ but the method still is there and works. To avoid warnings, we declare
+ it ourselves here. */
+@interface NSApplication(SDL_Missing_Methods)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
+/* Use this flag to determine whether we use SDLMain.nib or not */
+#define		SDL_USE_NIB_FILE	0
+
+/* Use this flag to determine whether we use CPS (docking) or not */
+#define		SDL_USE_CPS		1
+#ifdef SDL_USE_CPS
+/* Portions of CPS.h */
+typedef struct CPSProcessSerNum
+{
+	UInt32		lo;
+	UInt32		hi;
+} CPSProcessSerNum;
+
+extern OSErr	CPSGetCurrentProcess( CPSProcessSerNum *psn);
+extern OSErr 	CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+extern OSErr	CPSSetFrontProcess( CPSProcessSerNum *psn);
+
+#endif /* SDL_USE_CPS */
+
+static int    gArgc;
+static char  **gArgv;
+static BOOL   gFinderLaunch;
+static BOOL   gCalledAppMainline = FALSE;
+
+static NSString *getApplicationName(void)
+{
+    NSDictionary *dict;
+    NSString *appName = 0;
+    
+    /* Determine the application name */
+    dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+    if (dict)
+        appName = [dict objectForKey: @"CFBundleName"];
+    
+    if (![appName length])
+        appName = [[NSProcessInfo processInfo] processName];
+    
+    return appName;
+}
+
+#if SDL_USE_NIB_FILE
+/* A helper category for NSString */
+@interface NSString (ReplaceSubString)
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
+@end
+#endif
+
+@interface SDLApplication : NSApplication
+@end
+
+@implementation SDLApplication
+/* Invoked from the Quit menu item */
+- (void)terminate:(id)sender
+{
+    /* Post a SDL_QUIT event */
+    SDL_Event event;
+    event.type = SDL_QUIT;
+    SDL_PushEvent(&event);
+}
+@end
+
+/* The main class of the application, the application's delegate */
+@implementation SDLMain
+
+/* Set the working directory to the .app's parent directory */
+- (void) setupWorkingDirectory:(BOOL)shouldChdir
+{
+    if (shouldChdir)
+    {
+        char parentdir[MAXPATHLEN];
+		CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+		CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
+		if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
+	        assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
+		}
+		CFRelease(url);
+		CFRelease(url2);
+	}
+    
+}
+
+#if SDL_USE_NIB_FILE
+
+/* Fix menu to contain the real app name instead of "SDL App" */
+- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
+{
+    NSRange aRange;
+    NSEnumerator *enumerator;
+    NSMenuItem *menuItem;
+    
+    aRange = [[aMenu title] rangeOfString:@"SDL App"];
+    if (aRange.length != 0)
+        [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
+    
+    enumerator = [[aMenu itemArray] objectEnumerator];
+    while ((menuItem = [enumerator nextObject]))
+    {
+        aRange = [[menuItem title] rangeOfString:@"SDL App"];
+        if (aRange.length != 0)
+            [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
+        if ([menuItem hasSubmenu])
+            [self fixMenu:[menuItem submenu] withAppName:appName];
+    }
+    [ aMenu sizeToFit ];
+}
+
+#else
+
+static void setApplicationMenu(void)
+{
+    /* warning: this code is very odd */
+    NSMenu *appleMenu;
+    NSMenuItem *menuItem;
+    NSString *title;
+    NSString *appName;
+    
+    appName = getApplicationName();
+    appleMenu = [[NSMenu alloc] initWithTitle:@""];
+    
+    /* Add menu items */
+    title = [@"About " stringByAppendingString:appName];
+    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+    
+    [appleMenu addItem:[NSMenuItem separatorItem]];
+    
+    title = [@"Hide " stringByAppendingString:appName];
+    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+    
+    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+    
+    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+    
+    [appleMenu addItem:[NSMenuItem separatorItem]];
+    
+    title = [@"Quit " stringByAppendingString:appName];
+    [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+    
+    
+    /* Put menu into the menubar */
+    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+    [menuItem setSubmenu:appleMenu];
+    [[NSApp mainMenu] addItem:menuItem];
+    
+    /* Tell the application object that this is now the application menu */
+    [NSApp setAppleMenu:appleMenu];
+    
+    /* Finally give up our references to the objects */
+    [appleMenu release];
+    [menuItem release];
+}
+
+/* Create a window menu */
+static void setupWindowMenu(void)
+{
+    NSMenu      *windowMenu;
+    NSMenuItem  *windowMenuItem;
+    NSMenuItem  *menuItem;
+    
+    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+    
+    /* "Minimize" item */
+    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+    [windowMenu addItem:menuItem];
+    [menuItem release];
+    
+    /* Put menu into the menubar */
+    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
+    [windowMenuItem setSubmenu:windowMenu];
+    [[NSApp mainMenu] addItem:windowMenuItem];
+    
+    /* Tell the application object that this is now the window menu */
+    [NSApp setWindowsMenu:windowMenu];
+    
+    /* Finally give up our references to the objects */
+    [windowMenu release];
+    [windowMenuItem release];
+}
+
+/* Replacement for NSApplicationMain */
+static void CustomApplicationMain (int argc, char **argv)
+{
+    NSAutoreleasePool	*pool = [[NSAutoreleasePool alloc] init];
+    SDLMain				*sdlMain;
+    
+    /* Ensure the application object is initialised */
+    [SDLApplication sharedApplication];
+    
+#ifdef SDL_USE_CPS
+    {
+        CPSProcessSerNum PSN;
+        /* Tell the dock about us */
+        if (!CPSGetCurrentProcess(&PSN))
+            if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
+                if (!CPSSetFrontProcess(&PSN))
+                    [SDLApplication sharedApplication];
+    }
+#endif /* SDL_USE_CPS */
+    
+    /* Set up the menubar */
+    [NSApp setMainMenu:[[NSMenu alloc] init]];
+    setApplicationMenu();
+    setupWindowMenu();
+    
+    /* Create SDLMain and make it the app delegate */
+    sdlMain = [[SDLMain alloc] init];
+    [NSApp setDelegate:sdlMain];
+    
+    /* Start the main event loop */
+    [NSApp run];
+    
+    [sdlMain release];
+    [pool release];
+}
+
+#endif
+
+
+/*
+ * Catch document open requests...this lets us notice files when the app
+ *  was launched by double-clicking a document, or when a document was
+ *  dragged/dropped on the app's icon. You need to have a
+ *  CFBundleDocumentsType section in your Info.plist to get this message,
+ *  apparently.
+ *
+ * Files are added to gArgv, so to the app, they'll look like command line
+ *  arguments. Previously, apps launched from the finder had nothing but
+ *  an argv[0].
+ *
+ * This message may be received multiple times to open several docs on launch.
+ *
+ * This message is ignored once the app's mainline has been called.
+ */
+- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
+{
+    const char *temparg;
+    size_t arglen;
+    char *arg;
+    char **newargv;
+    
+    if (!gFinderLaunch)  /* MacOS is passing command line args. */
+        return FALSE;
+    
+    if (gCalledAppMainline)  /* app has started, ignore this document. */
+        return FALSE;
+    
+    temparg = [filename UTF8String];
+    arglen = SDL_strlen(temparg) + 1;
+    arg = (char *) SDL_malloc(arglen);
+    if (arg == NULL)
+        return FALSE;
+    
+    newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
+    if (newargv == NULL)
+    {
+        SDL_free(arg);
+        return FALSE;
+    }
+    gArgv = newargv;
+    
+    SDL_strlcpy(arg, temparg, arglen);
+    gArgv[gArgc++] = arg;
+    gArgv[gArgc] = NULL;
+    return TRUE;
+}
+
+
+/* Called when the internal event loop has just started running */
+- (void) applicationDidFinishLaunching: (NSNotification *) note
+{
+    int status;
+    
+    /* Set the working directory to the .app's parent directory */
+    [self setupWorkingDirectory:gFinderLaunch];
+    
+#if SDL_USE_NIB_FILE
+    /* Set the main menu to contain the real app name instead of "SDL App" */
+    [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
+#endif
+    
+    /* Hand off to main application code */
+    gCalledAppMainline = TRUE;
+    status = SDL_main (gArgc, gArgv);
+    
+    /* We're done, thank you for playing */
+    exit(status);
+}
+@end
+
+
+@implementation NSString (ReplaceSubString)
+
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
+{
+    unsigned int bufferSize;
+    unsigned int selfLen = [self length];
+    unsigned int aStringLen = [aString length];
+    unichar *buffer;
+    NSRange localRange;
+    NSString *result;
+    
+    bufferSize = selfLen + aStringLen - aRange.length;
+    buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
+    
+    /* Get first part into buffer */
+    localRange.location = 0;
+    localRange.length = aRange.location;
+    [self getCharacters:buffer range:localRange];
+    
+    /* Get middle part into buffer */
+    localRange.location = 0;
+    localRange.length = aStringLen;
+    [aString getCharacters:(buffer+aRange.location) range:localRange];
+    
+    /* Get last part into buffer */
+    localRange.location = aRange.location + aRange.length;
+    localRange.length = selfLen - localRange.location;
+    [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
+    
+    /* Build output string */
+    result = [NSString stringWithCharacters:buffer length:bufferSize];
+    
+    NSDeallocateMemoryPages(buffer, bufferSize);
+    
+    return result;
+}
+
+@end
+
+
+
+#ifdef main
+#  undef main
+#endif
+
+
+/* Main entry point to executable - should *not* be SDL_main! */
+int main (int argc, char **argv)
+{
+    /* Copy the arguments into a global variable */
+    /* This is passed if we are launched by double-clicking */
+    if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
+        gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
+        gArgv[0] = argv[0];
+        gArgv[1] = NULL;
+        gArgc = 1;
+        gFinderLaunch = YES;
+    } else {
+        int i;
+        gArgc = argc;
+        gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
+        for (i = 0; i <= argc; i++)
+            gArgv[i] = argv[i];
+        gFinderLaunch = NO;
+    }
+    
+#if SDL_USE_NIB_FILE
+    [SDLApplication poseAsClass:[NSApplication class]];
+    NSApplicationMain (argc, argv);
+#else
+    CustomApplicationMain (argc, argv);
+#endif
+    return 0;
+}