diff --git a/wolf3d/code/env/common.h b/wolf3d/code/env/common.h index ad0d486..44f5121 100644 --- a/wolf3d/code/env/common.h +++ b/wolf3d/code/env/common.h @@ -181,6 +181,7 @@ extern void Client_Init( void ); #define BUTTON_ATTACK 1 #define BUTTON_USE 2 #define BUTTON_CHANGE_WEAPON 4 +#define BUTTON_ALTERNATE_ATTACK 8 //gsh #define BUTTON_ANY 128 // any key whatsoever diff --git a/wolf3d/code/env/fileio.c b/wolf3d/code/env/fileio.c index 1848e55..de8917b 100644 --- a/wolf3d/code/env/fileio.c +++ b/wolf3d/code/env/fileio.c @@ -216,8 +216,6 @@ PUBLIC filehandle_t *FS_OpenFile( const char *filename, W32 FlagsAndAttributes ) pathBase = iphoneDocDirectory; my_snprintf( netpath, sizeof( netpath ), "%s/%s", pathBase, filename ); } else { -// extern char iphoneAppDirectory[1024]; -// pathBase = iphoneAppDirectory; pathBase = FS_Gamedir(); my_snprintf( netpath, sizeof( netpath ), "%s/%s", pathBase, filename ); } @@ -225,7 +223,17 @@ PUBLIC filehandle_t *FS_OpenFile( const char *filename, W32 FlagsAndAttributes ) // high performance file mapping path, avoiding stdio fd = open( netpath, O_RDONLY ); if ( fd == -1 ) { - return NULL; +// return NULL; + //if it couldn't be found in that path then check again in the document directory + //gsh + //pathBase = FS_ForceGamedir(); + extern char iphoneDocDirectory[1024]; + pathBase = iphoneDocDirectory; + my_snprintf( netpath, sizeof( netpath ), "%s/%s", pathBase, filename ); + fd = open( netpath, O_RDONLY ); + if ( fd == -1 ) { //okay, couldn't find it there either... return null + return NULL; + } } fstat( fd, &s ); diff --git a/wolf3d/code/env/files.c b/wolf3d/code/env/files.c index acd92e2..cb9fba4 100644 --- a/wolf3d/code/env/files.c +++ b/wolf3d/code/env/files.c @@ -60,7 +60,7 @@ PRIVATE char fs_gamedir[ MAX_OSPATH ]; - +//PRIVATE char fs_soddir[ MAX_OSPATH ]; //gsh /* @@ -77,8 +77,24 @@ PRIVATE char fs_gamedir[ MAX_OSPATH ]; */ PUBLIC char *FS_Gamedir( void ) { + /* + //gsh... this is a trick to load in where the iphoneDocDirectory is + if (currentMap.episode >= 6) + { +// sprintf( fs_soddir, "%s/SODbase", iphoneDocDirectory ); //if you're downloading the SOD data + sprintf( fs_soddir, "%s/", iphoneDocDirectory ); //if you're only downloading the spear maps + return fs_soddir; + }*/ + return fs_gamedir; } +/* +//gsh this is so that we can force a non-SOD folder +//it's only getting used in the FSOpenFile() of fileio.c +PUBLIC char *FS_ForceGamedir( void ) +{ + return fs_gamedir; +}*/ /* diff --git a/wolf3d/code/env/filesystem.h b/wolf3d/code/env/filesystem.h index 59bde77..b158fec 100644 --- a/wolf3d/code/env/filesystem.h +++ b/wolf3d/code/env/filesystem.h @@ -45,6 +45,7 @@ extern void FS_InitFilesystem(void); extern char *FS_Gamedir(void); +//extern char *FS_ForceGamedir(void); //gsh diff --git a/wolf3d/code/env/sound.c b/wolf3d/code/env/sound.c index 7ed3524..bd7ecc2 100644 --- a/wolf3d/code/env/sound.c +++ b/wolf3d/code/env/sound.c @@ -690,7 +690,7 @@ PRIVATE void Sound_Register( void ) { s_initSound = Cvar_Get( "s_initSound", "1", CVAR_INIT ); - s_masterVolume = Cvar_Get( "s_masterVolume", "1.0", CVAR_ARCHIVE ); + s_masterVolume = Cvar_Get( "s_masterVolume", "0.3", CVAR_ARCHIVE ); //gsh changed this from "1.0" to "0.3" for the volume hack... otherwise it's too loud s_sfxVolume = Cvar_Get( "s_sfxVolume", "1.0", CVAR_ARCHIVE ); s_musicVolume = Cvar_Get( "s_musicVolume", "1.0", CVAR_ARCHIVE ); s_minDistance = Cvar_Get( "s_minDistance", "0.0", CVAR_ARCHIVE ); diff --git a/wolf3d/code/env/sound_sfx_id.c b/wolf3d/code/env/sound_sfx_id.c index 4c8d11b..6175529 100644 --- a/wolf3d/code/env/sound_sfx_id.c +++ b/wolf3d/code/env/sound_sfx_id.c @@ -248,33 +248,57 @@ PUBLIC void Sound_BeginRegistration( void ) s_registering = true; } + PUBLIC sfx_t *Sound_RegisterSound( const char *name ) { sfx_t *sfx; + bool isSpearSound = false; if( ! sound_initialized ) { return NULL; } - - if( g_version->value == 1 ) + + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && strncmp(name, "iphone", 6) && currentMap.episode < 9)//added the episode & iphone check... gsh { + isSpearSound = true; + char tempname[ 256 ]; - my_snprintf( tempname, sizeof( tempname ), "sod%s", name ); - sfx = Sound_FindSound( tempname ); + + //gsh + //Com_Printf("Finding Sound: %s\n", tempname); } else { sfx = Sound_FindSound( name ); + + //gsh + //Com_Printf("Finding Sound: %s\n", name); } - +/* + //original if( ! s_registering ) { Sound_LoadSound( sfx ); } - +*/ + //gsh + if( ! s_registering ) + { + //if it couldn't be found and we tried finding it in sod + //then it might exist in wolf3d + if( !Sound_LoadSound( sfx ) && isSpearSound) + { + sfx = Sound_FindSound( name ); + //Com_Printf("Finding Sound Again: %s\n", name); + + if( ! s_registering ) + Sound_LoadSound( sfx ); //try loading again + } + } + return sfx; } diff --git a/wolf3d/code/env/texture_manager.c b/wolf3d/code/env/texture_manager.c index 18c16a8..d960d1d 100644 --- a/wolf3d/code/env/texture_manager.c +++ b/wolf3d/code/env/texture_manager.c @@ -464,14 +464,14 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type ) { return r_notexture; } - + // Check for file extension len = strlen( name ); if( len < 5 ) { return r_notexture; } - + // look for it in the texture cache for( i = 0, tex = ttextures; i < numttextures; ++i, ++tex ) { @@ -490,7 +490,8 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type ) return r_notexture; } -// Com_Printf( "Loading texture: %s\n", name ); + //gsh + //Com_Printf( "Loading texture: %s\n", name ); // look for the pre-digested 5551 version strcpy( digested, name ); @@ -514,7 +515,6 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type ) { GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_UNSIGNED_BYTE, 2 }, }; - picHeader_t *ph = (picHeader_t *)fh->filedata; int noMips = 0; @@ -606,7 +606,7 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type ) if ( fh == NULL ) { Com_Printf( "Failed to find texture %s\n", name ); return r_notexture; - } + } //else { //added the else...gsh jpgSize = FS_GetFileSize( fh ); jpgData = fh->ptrStart; @@ -616,13 +616,48 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type ) if ( ! data ) { free( jpgData ); return r_notexture; - } + } //else { //added the else tex = TM_LoadTexture( name, data, width, height, type, bytes ); MM_FREE( data ); tex->maxS = tex->maxT = 1.0f; return tex; + + + } + + /* + Com_Printf("Trying to find texture made it to the end\n"); + + //gsh.. couldn't find it... try doing it again, but looking in a new location + if (spritelocation == SODSPRITESDIRNAME && spritelocation != WL6SPRITESDIRNAME) + { + //need to remove the 'sod' + if (strncmp(spritelocation, name, strlen(spritelocation)) == 0) + { + char buffer[64]; + char tempName[64]; + int offset = strlen(spritelocation) + 1; + for (int i = 0; i < strlen(name) - offset; ++i) + { + buffer[i] = name[i+offset]; + } + buffer[i] = '\0'; //just in case + + spritelocation = WL6SPRITESDIRNAME; + + //TODO: + my_snprintf(tempName, sizeof(tempName), "%s/%s", spritelocation, buffer); + + Com_Printf("tempName: %s\n", tempName); + Com_Printf("buffer: %s\n", buffer); + + spritelocation = SODSPRITESDIRNAME; //return to sodsprites + tex = TM_FindTexture( tempName, type); + return tex; + } } + return r_notexture;*/ return NULL; } diff --git a/wolf3d/code/iphone/EAGLView.h b/wolf3d/code/iphone/EAGLView.h index 80e8881..dd2c39a 100644 --- a/wolf3d/code/iphone/EAGLView.h +++ b/wolf3d/code/iphone/EAGLView.h @@ -24,6 +24,13 @@ #import #import + + + +#ifdef VOLUMEHACK +#import +#endif + /* This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass. The view content is basically an EAGL surface you render your OpenGL scene into. @@ -49,6 +56,14 @@ Note that setting the view non-opaque will only work if the EAGL surface has an NSTimer *animationTimer; NSTimeInterval animationInterval; + //gsh... an attempt at hacking the volume button +#ifdef VOLUMEHACK + MPVolumeView *volumeView; + UISlider *volumeViewSlider; + float lastFramesVolume; +#endif +// NSThread *pLoadThread; + } @property NSTimeInterval animationInterval; diff --git a/wolf3d/code/iphone/EAGLView.m b/wolf3d/code/iphone/EAGLView.m index 13cb97f..7fde3ec 100644 --- a/wolf3d/code/iphone/EAGLView.m +++ b/wolf3d/code/iphone/EAGLView.m @@ -16,6 +16,11 @@ #include "wolfiphone.h" + + +//gsh +//#define NOTIFYLISTEN //uncomment to receive notifications + struct AVSystemControllerPrivate; @interface AVSystemController : NSObject @@ -144,6 +149,40 @@ - (id)initWithCoder:(NSCoder*)coder { ((void(*)(int))eglSwapInterval)( 2 ); } #endif + +#ifdef VOLUMEHACK + //------------------- + // Volume Button Hack + //gsh + // Note: MediaPlayer framework required for this trick + //create a MPVolumeView to hack the volume button + CGRect frame = CGRectMake(0, -30, 180, 10); //put this thing offscreen + volumeView = [[[MPVolumeView alloc] initWithFrame:frame] autorelease]; + [volumeView sizeToFit]; + [self addSubview:volumeView]; + + // Find the volume view slider + for (UIView *view in [volumeView subviews]){ + if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) { + volumeViewSlider = (UISlider *)view; + } + } + + //listen for volume changes + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(volumeListener:) + name:@"AVSystemController_SystemVolumeDidChangeNotification" + object:nil]; + + //--------------------- +#endif + +#ifdef NOTIFYLISTEN //gsh + //this is a general purpose listener + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationListener:) + name:nil + object:nil]; +#endif // with swapinterval, we want to update as fast as possible float interval = 1.0 / 30.0f; @@ -155,7 +194,14 @@ - (id)initWithCoder:(NSCoder*)coder { return self; } +//gsh +- (void)viewDidLoad { + + Com_Printf("\n---------------\nviewDidLoad() called\n---------------\n\n"); +} + - (void)drawView { + [ (wolf3dAppDelegate *)[UIApplication sharedApplication].delegate restartAccelerometerIfNeeded]; #if 0 @@ -175,11 +221,28 @@ - (void)drawView { } } #endif + +#ifdef VOLUMEHACK //------------------ + // volume hack + + + //check for volume adjustments gsh + if ( menuState == IPM_CONTROLS) + { + if (lastFramesVolume != s_masterVolume->value) + { + lastFramesVolume = s_masterVolume->value; + [volumeViewSlider setValue:lastFramesVolume animated:NO]; + [volumeViewSlider _commitVolumeChange]; + } + } +#endif iphoneFrame(); // swapBuffers() will be called from here } + - (void)swapBuffers { // glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].beforeSwap = Sys_Milliseconds(); @@ -215,7 +278,11 @@ - (void)dealloc { - (void) handleTouches:(NSSet*)touches withEvent:(UIEvent*)event { int touchCount = 0; int points[16]; - static int previousTouchCount; + static int previousTouchCount = 0; + + //gsh + if (previousTouchCount == 0) + isTouchMoving = 0; NSSet *t = [event allTouches]; for (UITouch *myTouch in t) @@ -232,10 +299,12 @@ - (void) handleTouches:(NSSet*)touches withEvent:(UIEvent*)event { } if (myTouch.phase == UITouchPhaseMoved) { // touch moved handler + //gsh, use this for swipe events in the scrolling menus + isTouchMoving = 1; } if (myTouch.phase == UITouchPhaseEnded) { touchCount--; - } + } } // toggle the console with four touches @@ -281,11 +350,62 @@ - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [self handleTouches:touches withEvent:event]; } - - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [self handleTouches:touches withEvent:event]; } +// gsh +#ifdef NOTIFYLISTEN +- (void) notificationListener:(NSNotification *)notify +{ + Com_Printf("notificationListener: %s\n", [notify.name UTF8String]); +//NSString + + if ([notify.name isEqualToString:@"CPDistributedMessagingCenterServerDidTerminateNotification"] && menuState == IPM_STOREKIT) + { + iphoneMessageBox("Apple Store Failed", "Connection to app store has terminated. Please try again later."); + menuState = IPM_MAIN; + } + //sometimes after requrestProductData() is called we get these notifications + //and the storekit no longer responds (making it appear as a crash) + /* +notificationListener: CPDistributedMessagingCenterServerDidTerminateNotification +notificationListener: SKNotificationRequestFinished +notificationListener: SKNotificationTransactionsRefreshed +notificationListener: CPDistributedMessagingCenterServerDidTerminateNotification +*/ +} +#endif + +#ifdef VOLUMEHACK +//------------------- +// Volume Button Hack +// gsh +// currently this is problematic... +// it's slow if the user holds the volume button +// let's see if inlining this with the normal game loop is faster +// than listening for the event... it's not +// Note: MediaPlayer framework required for this trick +//------------------- +- (void) volumeListener:(NSNotification *)notify +{ + //TODO: provide left/right click attacks + if (volumeViewSlider.value < s_masterVolume->value) + { + + [volumeViewSlider setValue:s_masterVolume->value animated:NO];//volumeSetting animated:NO]; + [volumeViewSlider _commitVolumeChange]; //again, ignoring compiler warning complaints + //this might have a warning because it's currently undocumented? + Cvar_Set("volumeFireDown", "1"); + } + else if (volumeViewSlider.value > s_masterVolume->value)//volumeSetting) + { + [volumeViewSlider setValue:s_masterVolume->value animated:NO];//volumeSetting animated:NO]; + [volumeViewSlider _commitVolumeChange]; //again, ignoring compiler warning complaints + Cvar_Set("volumeFireUp", "1"); + } +} +#endif @end diff --git a/wolf3d/code/iphone/FSCopyObject.c b/wolf3d/code/iphone/FSCopyObject.c new file mode 100644 index 0000000..d4580be --- /dev/null +++ b/wolf3d/code/iphone/FSCopyObject.c @@ -0,0 +1,1986 @@ +/* + File: FSCopyObject.c + + Contains: A Copy/Delete Files/Folders engine which uses HFS+ API's. + This code takes some tricks/techniques from MoreFilesX and + MPFileCopy, wraps them all up into an easy to use API, and + adds a bunch of features. It will run on Mac OS 9.1 through + 9.2.x and 10.1.x and up (Classic, Carbon and Mach-O) + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2002-2004 Apple Computer, Inc., All Rights Reserved +*/ + +#include "FSCopyObject.h" +#include "GenLinkedList.h" +#if !TARGET_API_MAC_OSX +#include +#endif +#include +#include + +#pragma mark ----- Tunable Parameters ----- + +/* The following constants control the behavior of the copy engine. */ + +enum { /* BufferSizeForVolSpeed */ +/* kDefaultCopyBufferSize = 2L * 1024 * 1024,*/ /* 2MB, Fast but not very responsive. */ + kDefaultCopyBufferSize = 256L * 1024, /* 256kB, Slower but can still use machine. */ + kMaximumCopyBufferSize = 2L * 1024 * 1024, + kMinimumCopyBufferSize = 1024 +}; + +enum { /* CheckForDestInsideSrc */ + errFSDestInsideSource = -1234 +}; + +enum { + /* for use with PBHGetDirAccess in IsDropBox */ + kPrivilegesMask = kioACAccessUserWriteMask | kioACAccessUserReadMask | kioACAccessUserSearchMask, + + /* for use with FSGetCatalogInfo and FSPermissionInfo->mode */ + /* from sys/stat.h... note -- sys/stat.h definitions are in octal */ + /* */ + /* You can use these values to adjust the users/groups permissions */ + /* on a file/folder with FSSetCatalogInfo and extracting the */ + /* kFSCatInfoPermissions field. See code below for examples */ + kRWXUserAccessMask = 0x01C0, + kReadAccessUser = 0x0100, + kWriteAccessUser = 0x0080, + kExecuteAccessUser = 0x0040, + + kRWXGroupAccessMask = 0x0038, + kReadAccessGroup = 0x0020, + kWriteAccessGroup = 0x0010, + kExecuteAccessGroup = 0x0008, + + kRWXOtherAccessMask = 0x0007, + kReadAccessOther = 0x0004, + kWriteAccessOther = 0x0002, + kExecuteAccessOther = 0x0001, + + kDropFolderValue = kWriteAccessOther | kExecuteAccessOther +}; + +#define kNumObjects 80 + +#define VolHasCopyFile(volParms) (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0) + +#pragma mark ----- Struct Definitions ----- + + /* The CopyParams data structure holds the copy buffer used */ + /* when copying the forks over, as well as special case */ + /* info on the destination */ +struct CopyParams { + void *copyBuffer; + ByteCount copyBufferSize; + Boolean copyingToDropFolder; + Boolean copyingToLocalVolume; + Boolean volHasCopyFile; + DupeAction dupeAction; +}; +typedef struct CopyParams CopyParams; + + /* The FilterParams data structure holds the date and info */ + /* that the caller wants passed into the Filter Proc, as well */ + /* as the Filter Proc Pointer itself */ +struct FilterParams { + FSCatalogInfoBitmap whichInfo; + CopyObjectFilterProcPtr filterProcPtr; + Boolean containerChanged; + Boolean wantSpec; + Boolean wantName; + void *yourDataPtr; +}; +typedef struct FilterParams FilterParams; + + /* The ForkTracker data structure holds information about a specific fork, */ + /* specifically the name and the refnum. We use this to build a list of */ + /* all the forks before we start copying them. We need to do this because */ + /* if we're copying into a drop folder, we must open all the forks before */ + /* we start copying data into any of them. */ + /* Plus it's a convenient way to keep track of all the forks... */ +struct ForkTracker { + HFSUniStr255 forkName; + SInt64 forkSize; + SInt16 forkDestRefNum; +}; +typedef struct ForkTracker ForkTracker; +typedef ForkTracker *ForkTrackerPtr; + + /* The FolderListData data structure holds FSRefs to the source and */ + /* coorisponding destination folder, as well as which level its on */ + /* for use in ProcessFolderList. */ +struct FolderListData +{ + FSRef sourceDirRef; + FSRef destDirRef; + UInt32 level; +}; +typedef struct FolderListData FolderListData; + + /* The FSCopyFolderGlobals data structure holds the information needed to */ + /* copy a directory */ +struct FSCopyFolderGlobals +{ + FSRef *sourceDirRef; + FSRef *destDirRef; + + FSCatalogInfo *catInfoList; + FSRef *srcRefList; + HFSUniStr255 *nameList; + + GenLinkedList folderList; + GenIteratorPtr folderListIter; + + CopyParams *copyParams; + FilterParams *filterParams; + Boolean containerChanged; + + ItemCount maxLevels; + ItemCount currentLevel; +}; +typedef struct FSCopyFolderGlobals FSCopyFolderGlobals; + + /* The FSDeleteObjectGlobals data structure holds information needed to */ + /* recursively delete a directory */ +struct FSDeleteObjectGlobals +{ + FSCatalogInfo catalogInfo; /* FSCatalogInfo */ + ItemCount actualObjects; /* number of objects returned */ + OSErr result; /* result */ +}; +typedef struct FSDeleteObjectGlobals FSDeleteObjectGlobals; + +#pragma mark ----- Local Prototypes ----- + +static OSErr FSCopyObjectPreflight ( const FSRef *source, + const FSRef *destDir, + const DupeAction dupeAction, + FSCatalogInfo *sourceCatInfo, + CopyParams *copyParams, /* can be NULL */ + HFSUniStr255 *newObjectName, + FSRef *deleteMeRef, + Boolean *isReplacing, + Boolean *isDirectory ); + +static OSErr FSCopyFile ( const FSRef *source, + const FSRef *destDir, + const FSCatalogInfo *sourceCatInfo, + const HFSUniStr255 *newFileName, + CopyParams *copyParams, + FilterParams *filterParams, + FSRef *newFileRef, /* can be NULL */ + FSSpec *newFileSpec ); /* can be NULL */ + +static OSErr CopyFile ( const FSRef *source, + FSCatalogInfo *sourceCatInfo, + const FSRef *destDir, + const HFSUniStr255 *destName, /* can be NULL */ + CopyParams *copyParams, + FSRef *newRef, /* can be NULL */ + FSSpec *newSpec ); /* can be NULL */ + +static OSErr FSUsePBHCopyFile ( const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + const HFSUniStr255 *destName, /* can be NULL (no rename during copy) */ + TextEncoding textEncodingHint, + FSRef *newRef, /* can be NULL */ + FSSpec *newSpec ); /* can be NULL */ + +static OSErr DoCopyFile ( const FSRef *source, + FSCatalogInfo *sourceCatInfo, + const FSRef *destDir, + const HFSUniStr255 *destName, + CopyParams *params, + FSRef *newRef, /* can be NULL */ + FSSpec *newSpec ); /* can be NULL */ + +static OSErr FSCopyFolder ( const FSRef *source, + const FSRef *destDir, + const FSCatalogInfo *sourceCatInfo, + const HFSUniStr255 *newFoldName, + CopyParams *copyParams, + FilterParams *filterParams, + ItemCount maxLevels, + FSRef *outDirRef, /* can be NULL */ + FSSpec *outDirSpec ); /* can be NULL */ + +static OSErr ProcessFolderList ( FSCopyFolderGlobals *folderGlobals ); + +static OSErr CopyFolder ( FSCopyFolderGlobals *folderGlobals ); + +static OSErr CheckForDestInsideSrc ( const FSRef *source, + const FSRef *destDir ); + +static OSErr CopyForks ( const FSRef *source, + const FSRef *dest, + CopyParams *params ); + +static OSErr CopyForksToDisk ( const FSRef *source, + const FSRef *dest, + CopyParams *params ); + +static OSErr CopyForksToDropBox ( const FSRef *source, + const FSRef *dest, + CopyParams *params ); + +static OSErr OpenAllForks ( const FSRef *dest, + GenLinkedList *forkList ); + +static OSErr WriteFork ( const SInt16 srcRefNum, + const SInt16 destRefNum, + const CopyParams *params, + const SInt64 forkSize ); + +static UInt32 CalcBufferSizeForVol ( const GetVolParmsInfoBuffer *volParms, + UInt32 volParmsSize ); + +static UInt32 BufferSizeForVolSpeed ( UInt32 volumeBytesPerSecond ); + +static OSErr FSDeleteFolder ( const FSRef *container ); + +static void FSDeleteFolderLevel ( const FSRef *container, + FSDeleteObjectGlobals *theGlobals ); + +static OSErr IsDropBox ( const FSRef *source, + Boolean *isDropBox ); + +static OSErr GetMagicBusyCreateDate( UTCDateTime *date ); + +static OSErr FSGetVRefNum ( const FSRef *ref, + FSVolumeRefNum *vRefNum ); + +static OSErr FSGetVolParms ( FSVolumeRefNum volRefNum, + UInt32 bufferSize, + GetVolParmsInfoBuffer*volParmsInfo, + UInt32 *actualInfoSize ); /* Can Be NULL */ + +static OSErr UniStrToPStr ( const HFSUniStr255 *uniStr, + TextEncoding textEncodingHint, + Boolean isVolumeName, + Str255 pStr ); + +static OSErr FSMakeFSRef ( FSVolumeRefNum volRefNum, + SInt32 dirID, + ConstStr255Param name, + FSRef *ref ); + +static OSErr SetupDestination ( const FSRef *destDir, + const DupeAction dupeAction, + HFSUniStr255 *sourceName, + FSRef *deleteMeRef, + Boolean *isReplacing); + +static OSErr GetUniqueName ( const FSRef *destDir, + HFSUniStr255 *sourceName ); + +static OSErr GetObjectName ( const FSRef *sourceRef, + HFSUniStr255 *sourceName, + TextEncoding *sourceEncoding ); + +static OSErr CreateFolder ( const FSRef *sourceRef, + const FSRef *destDirRef, + const FSCatalogInfo *catalogInfo, + const HFSUniStr255 *folderName, + CopyParams *params, + FSRef *newFSRefPtr, + FSSpec *newFSSpecPtr ); + +static OSErr DoCreateFolder ( const FSRef *sourceRef, + const FSRef *destDirRef, + const FSCatalogInfo *catalogInfo, + const HFSUniStr255 *folderName, + CopyParams *params, + FSRef *newFSRefPtr, + FSSpec *newFSSpecPtr); + +static pascal void MyDisposeDataProc ( void *pData ); + +static pascal void MyCloseForkProc ( void *pData ); + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +#pragma mark ----- Copy Objects ----- + + /* This routine acts as the top level of the copy engine. */ +OSErr FSCopyObject( const FSRef *source, + const FSRef *destDir, + ItemCount maxLevels, + FSCatalogInfoBitmap whichInfo, + DupeAction dupeAction, + const HFSUniStr255 *newObjectName, /* can be NULL */ + Boolean wantFSSpec, + Boolean wantName, + CopyObjectFilterProcPtr filterProcPtr, /* can be NULL */ + void *yourDataPtr, /* can be NULL */ + FSRef *newObjectRef, /* can be NULL */ + FSSpec *newObjectSpec) /* can be NULL */ +{ + CopyParams copyParams; + FilterParams filterParams; + FSCatalogInfo sourceCatInfo; + HFSUniStr255 sourceName, + tmpObjectName; + FSRef tmpObjectRef, + deleteMeRef; + Boolean isDirectory, + isReplacing = false; + OSErr err = ( source != NULL && destDir != NULL ) ? noErr : paramErr; + + /* Zero out these two FSRefs in case an error occurs before or */ + /* inside FSCopyObjectPreflight. Paranoia mainly... */ + BlockZero( &deleteMeRef, sizeof( FSRef ) ); + BlockZero( &tmpObjectRef, sizeof( FSRef ) ); + + /* setup filterParams */ + filterParams.whichInfo = whichInfo; + filterParams.filterProcPtr = filterProcPtr; + filterParams.wantSpec = ( filterProcPtr && wantFSSpec ); /* only get this info if */ + filterParams.wantName = ( filterProcPtr && wantName ); /* a filterProc is provied */ + filterParams.yourDataPtr = yourDataPtr; + + /* Get and store away the name of the source object */ + /* and setup the initial name of the new object */ + if( err == noErr ) + err = GetObjectName( source, &sourceName, NULL ); + if( err == noErr ) + tmpObjectName = (newObjectName != NULL) ? *newObjectName : sourceName; + + if( err == noErr ) /* preflight/prep the destination and our internal variables */ + err = FSCopyObjectPreflight( source, destDir, dupeAction, &sourceCatInfo, ©Params, &tmpObjectName, &deleteMeRef, &isReplacing, &isDirectory ); + + /* now that we have some info, lets print it */ + if( err == noErr ) + { + dwarning(( "%s -- err: %d, maxLevels: %u, whichInfo: %08x,\n", __FUNCTION__, err, (unsigned int)maxLevels, (int)whichInfo )); + dwarning(( "\t\t\t\tdupeAction: %s, wantSpec: %s, wantName: %s,\n", ((dupeAction == kDupeActionReplace) ? "replace" : ((dupeAction == kDupeActionRename) ? "rename" : "standard")), (filterParams.wantSpec)?"yes":"no", (filterParams.wantName)?"yes":"no" )); + dwarning(( "\t\t\t\tfilterProcPtr: 0x%08x, yourDataPtr: 0x%08x,\n", (unsigned int)filterProcPtr, (unsigned int)yourDataPtr )); + dwarning(( "\t\t\t\tnewObjectRef: 0x%08x, newObjectSpec: 0x%08x,\n", (unsigned int)newObjectRef, (unsigned int)newObjectSpec )); + dwarning(( "\t\t\t\tcopyBufferSize: %dkB, isDirectory: %s, isLocal: %s,\n", (int)copyParams.copyBufferSize/1024, (isDirectory)?"yes":"no", (copyParams.copyingToLocalVolume)?"yes":"no" )); + dwarning(( "\t\t\t\tisDropBox: %s, PBHCopyFileSync supported: %s\n\n", (copyParams.copyingToDropFolder)?"yes":"no", (copyParams.volHasCopyFile)?"yes":"no" )); + } + + if( err == noErr ) /* now copy the file/folder... */ + { /* is it a folder? */ + if ( isDirectory ) + { /* yes */ + err = CheckForDestInsideSrc(source, destDir); + if( err == noErr ) + err = FSCopyFolder( source, destDir, &sourceCatInfo, &tmpObjectName, ©Params, &filterParams, maxLevels, &tmpObjectRef, newObjectSpec ); + } + else /* no */ + err = FSCopyFile(source, destDir, &sourceCatInfo, &tmpObjectName, ©Params, &filterParams, &tmpObjectRef, newObjectSpec); + } + + /* if an object existed in the destination with the same name as */ + /* the source and the caller wants to replace it, we had renamed it */ + /* to ".DeleteMe" earlier. If no errors, we delete it, else delete */ + /* the one we just created and rename the origenal back to its */ + /* origenal name. */ + /* */ + /* This is done mainly to cover the case of the source being in the */ + /* destination directory when kDupeActionReplace is selected */ + /* (3188701) */ + if( copyParams.dupeAction == kDupeActionReplace && isReplacing == true ) + { + dwarning(("%s -- Cleaning up, this might take a moment. err : %d\n", __FUNCTION__, err)); + + if( err == noErr ) + err = FSDeleteObjects( &deleteMeRef ); + else + { /* not much we can do if the delete or rename fails, we need to preserve */ + /* the origenal error code that got us here. */ + /* */ + /* If an error occurs before or inside SetupDestination, newFileRef and */ + /* deleteMeRef will be invalid so the delete and rename will simply fail */ + /* leaving the source and destination unchanged */ + myverify_noerr( FSDeleteObjects( &tmpObjectRef ) ); + myverify_noerr( FSRenameUnicode( &deleteMeRef, sourceName.length, sourceName.unicode, sourceCatInfo.textEncodingHint, NULL ) ); + } + } + + if( err == noErr && newObjectRef != NULL ) + *newObjectRef = tmpObjectRef; + + /* Clean up for space and safety... Who me? */ + if( copyParams.copyBuffer != NULL ) + DisposePtr((char*)copyParams.copyBuffer); + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + + /* Does a little preflighting (as the name suggests) to figure out the optimal */ + /* buffer size, if its a drop box, on a remote volume etc */ +static OSErr FSCopyObjectPreflight( const FSRef *source, + const FSRef *destDir, + const DupeAction dupeAction, + FSCatalogInfo *sourceCatInfo, + CopyParams *copyParams, + HFSUniStr255 *newObjectName, + FSRef *deleteMeRef, + Boolean *isReplacing, + Boolean *isDirectory) +{ + GetVolParmsInfoBuffer srcVolParms, + destVolParms; + UInt32 srcVolParmsSize = 0, + destVolParmsSize = 0; + FSVolumeRefNum srcVRefNum, + destVRefNum; + OSErr err = ( source != NULL && destDir != NULL && + sourceCatInfo != NULL && copyParams != NULL && + newObjectName != NULL && deleteMeRef != NULL && + isDirectory != NULL ) ? noErr : paramErr; + + BlockZero( copyParams, sizeof( CopyParams ) ); + + copyParams->dupeAction = dupeAction; + + if( err == noErr ) /* Get the info we will need later about the source object */ + err = FSGetCatalogInfo( source, kFSCatInfoSettableInfo, sourceCatInfo, NULL, NULL, NULL ); + if( err == noErr ) /* get the source's vRefNum */ + err = FSGetVRefNum( source, &srcVRefNum ); + if( err == noErr ) /* get the source's volParams */ + err = FSGetVolParms( srcVRefNum, sizeof(GetVolParmsInfoBuffer), &srcVolParms, &srcVolParmsSize ); + if( err == noErr ) /* get the destination's vRefNum */ + err = FSGetVRefNum( destDir, &destVRefNum ); + if( err == noErr ) + { + /* Calculate the optimal copy buffer size for the src vol */ + copyParams->copyBufferSize = CalcBufferSizeForVol( &srcVolParms, srcVolParmsSize ); + + /* if src and dest on different volumes, get its vol parms */ + /* and calculate its optimal buffer size */ + /* else destVolParms = srcVolParms */ + if( srcVRefNum != destVRefNum ) + { + err = FSGetVolParms( destVRefNum, sizeof(GetVolParmsInfoBuffer), &destVolParms, &destVolParmsSize ); + if( err == noErr ) + { + ByteCount tmpBufferSize = CalcBufferSizeForVol( &destVolParms, destVolParmsSize ); + if( tmpBufferSize < copyParams->copyBufferSize ) + copyParams->copyBufferSize = tmpBufferSize; + } + } + else + destVolParms = srcVolParms; + } + if( err == noErr ) + err = ((copyParams->copyBuffer = NewPtr( copyParams->copyBufferSize )) != NULL ) ? noErr : MemError(); + + /* figure out if source is a file or folder */ + /* if it is on a local volume, */ + /* if destination is a drop box */ + /* if source and dest are on same server */ + /* and if it supports PBHCopyFile */ + if( err == noErr ) /* is the destination a Drop Box */ + err = IsDropBox( destDir, ©Params->copyingToDropFolder ); + if( err == noErr ) + { + /* Is it a directory */ + *isDirectory = ((sourceCatInfo->nodeFlags & kFSNodeIsDirectoryMask) != 0); + /* destVolParms.vMServerAdr is non-zero for remote volumes */ + copyParams->copyingToLocalVolume = (destVolParms.vMServerAdr == 0); + if( !copyParams->copyingToLocalVolume ) + { + /* If the destination is on a remote volume, and source and dest are on */ + /* the same server, then it might support PBHCopyFileSync */ + /* If not, then PBHCopyFileSync won't work */ + + /* figure out if the volumes support PBHCopyFileSync */ + copyParams->volHasCopyFile = ( err == noErr && destVolParms.vMServerAdr == srcVolParms.vMServerAdr ) ? + VolHasCopyFile(&srcVolParms) : false; + } + } + + if( err == noErr ) + err = SetupDestination( destDir, copyParams->dupeAction, newObjectName, deleteMeRef, isReplacing ); + + return err; +} + +#pragma mark ----- Copy Files ----- + +/*****************************************************************************/ + +static OSErr FSCopyFile( const FSRef *source, + const FSRef *destDir, + const FSCatalogInfo *sourceCatInfo, + const HFSUniStr255 *newFileName, + CopyParams *copyParams, + FilterParams *filterParams, + FSRef *outFileRef, + FSSpec *outFileSpec ) +{ + FSCatalogInfo catInfo = *sourceCatInfo; + FSRef newFileRef; + FSSpec newFileSpec; + OSErr err = ( source != NULL && destDir != NULL && + copyParams != NULL && filterParams != NULL ) ? noErr : paramErr; + + /* If you would like a Pre-Copy filter (i.e to weed out objects */ + /* you don't want to copy) you should add it here */ + + if( err == noErr ) /* copy the file over */ + err = CopyFile( source, &catInfo, destDir, newFileName, copyParams, &newFileRef, (filterParams->wantSpec || outFileSpec) ? &newFileSpec : NULL ); + + /* Call the IterateFilterProc _after_ the new file was created even if an error occured. */ + /* Note: if an error occured above, the FSRef and other info might not be valid */ + if( filterParams->filterProcPtr != NULL ) + { + /* get the extra info the user wanted on the new file that we don't have */ + if( err == noErr && (filterParams->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone ) + err = FSGetCatalogInfo( &newFileRef, filterParams->whichInfo & ~kFSCatInfoSettableInfo, &catInfo, NULL, NULL, NULL ); + + err = CallCopyObjectFilterProc( filterParams->filterProcPtr, false, 0, err, &catInfo, &newFileRef, + (filterParams->wantSpec) ? &newFileSpec : NULL, + (filterParams->wantName) ? newFileName : NULL, + filterParams->yourDataPtr); + } + + if( err == noErr ) + { + if( outFileRef != NULL ) + *outFileRef = newFileRef; + if( outFileSpec != NULL ) + *outFileSpec = newFileSpec; + } + + mycheck_noerr(err); + + return err; +} + +/*****************************************************************************/ + +static OSErr CopyFile( const FSRef *source, + FSCatalogInfo *sourceCatInfo, + const FSRef *destDir, + const HFSUniStr255 *destName, /* can be NULL */ + CopyParams *params, + FSRef *newFile, /* can be NULL */ + FSSpec *newSpec ) /* can be NULL */ +{ + OSErr err = paramErr; + + /* Clear the "inited" bit so that the Finder positions the icon for us. */ + ((FInfo *)(sourceCatInfo->finderInfo))->fdFlags &= ~kHasBeenInited; + + /* if the volumes support PBHCopyFileSync, try to use it */ + if( params->volHasCopyFile == true ) + err = FSUsePBHCopyFile( source, destDir, destName, kTextEncodingUnknown, newFile, newSpec ); + + /* if PBHCopyFile didn't work or not supported, */ + if( err != noErr ) /* then try old school file transfer */ + err = DoCopyFile( source, sourceCatInfo, destDir, destName, params, newFile, newSpec ); + + mycheck_noerr(err); + + return err; +} + +/*****************************************************************************/ + + /* Wrapper function for PBHCopyFileSync */ +static OSErr FSUsePBHCopyFile( const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + const HFSUniStr255 *destName, /* can be NULL */ + TextEncoding textEncodingHint, + FSRef *newRef, /* can be NULL */ + FSSpec *newSpec) /* can be NULL */ +{ + FSSpec srcFileSpec; + FSCatalogInfo catalogInfo; + HParamBlockRec pb; + Str255 hfsName; + OSErr err = ( srcFileRef != NULL && dstDirectoryRef != NULL ) ? noErr : paramErr; + + if( err == noErr ) /* get FSSpec of source FSRef */ + err = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL); + if( err == noErr ) /* get the destination vRefNum and nodeID (nodeID is the dirID) */ + err = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume | kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL); + if( err == noErr ) /* gather all the info needed */ + { + pb.copyParam.ioVRefNum = srcFileSpec.vRefNum; + pb.copyParam.ioDirID = srcFileSpec.parID; + pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name; + pb.copyParam.ioDstVRefNum = catalogInfo.volume; + pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID; + pb.copyParam.ioNewName = NULL; + if( destName != NULL ) + err = UniStrToPStr( destName, textEncodingHint, false, hfsName ); + pb.copyParam.ioCopyName = ( destName != NULL && err == noErr ) ? hfsName : NULL; + } + if( err == noErr ) /* tell the server to copy the object */ + err = PBHCopyFileSync(&pb); + + if( err == noErr ) + { + if( newSpec != NULL ) /* caller wants an FSSpec, so make it */ + myverify_noerr(FSMakeFSSpec( pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newSpec)); + if( newRef != NULL ) /* caller wants an FSRef, so make it */ + myverify_noerr(FSMakeFSRef( pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newRef)); + } + + if( err != paramErr ) /* returning paramErr is ok, it means PBHCopyFileSync was not supported */ + mycheck_noerr(err); + + return err; +} + +/*****************************************************************************/ + + /* Copies a file referenced by source to the directory referenced by */ + /* destDir. destName is the name the file we are going to copy to the */ + /* destination. sourceCatInfo is the catalog info of the file, which */ + /* is passed in as an optimization (we could get it by doing a */ + /* FSGetCatalogInfo but the caller has already done that so we might as */ + /* well take advantage of that). */ + /* */ +static OSErr DoCopyFile(const FSRef *source, + FSCatalogInfo *sourceCatInfo, + const FSRef *destDir, + const HFSUniStr255 *destName, + CopyParams *params, + FSRef *newRef, + FSSpec *newSpec ) +{ + FSRef dest; + FSSpec tmpSpec; + FSPermissionInfo originalPermissions; + OSType originalFileType = 'xxxx'; + UInt16 originalNodeFlags = kFSCatInfoNone; + Boolean getSpec; + OSErr err = noErr; + + /* If we're copying to a drop folder, we won't be able to reset this */ + /* information once the copy is done, so we don't mess it up in */ + /* the first place. We still clear the locked bit though; items dropped */ + /* into a drop folder always become unlocked. */ + if (!params->copyingToDropFolder) + { + /* Remember to clear the file's type, so the Finder doesn't */ + /* look at the file until we're done. */ + originalFileType = ((FInfo *) &sourceCatInfo->finderInfo)->fdType; + ((FInfo *) &sourceCatInfo->finderInfo)->fdType = kFirstMagicBusyFiletype; + + /* Remember and clear the file's locked status, so that we can */ + /* actually write the forks we're about to create. */ + originalNodeFlags = sourceCatInfo->nodeFlags; + } + sourceCatInfo->nodeFlags &= ~kFSNodeLockedMask; + + /* figure out if we should get the FSSpec to the new file or not */ + /* If the caller asked for it, or if we need it for symlinks */ + getSpec = ( ( newSpec != NULL ) || ( !params->copyingToDropFolder && originalFileType == 'slnk' && ((FInfo *) &sourceCatInfo->finderInfo)->fdCreator == 'rhap' ) ); + + /* we need to have user level read/write/execute access to the file we are */ + /* going to create otherwise FSCreateFileUnicode will return */ + /* -5000 (afpAccessDenied), and the FSRef returned will be invalid, yet */ + /* the file is created (size 0k)... bug? */ + originalPermissions = *((FSPermissionInfo*)sourceCatInfo->permissions); + ((FSPermissionInfo*)sourceCatInfo->permissions)->mode |= kRWXUserAccessMask; + + /* Classic only supports 9.1 and higher, so we don't have to worry */ + /* about 2397324 */ + if( err == noErr ) + err = FSCreateFileUnicode(destDir, destName->length, destName->unicode, kFSCatInfoSettableInfo, sourceCatInfo, &dest, ( getSpec ) ? &tmpSpec : NULL ); + if( err == noErr ) /* Copy the forks over to the new file */ + err = CopyForks(source, &dest, params); + + /* Restore the original file type, creation and modification dates, */ + /* locked status and permissions. */ + /* This is one of the places where we need to handle drop */ + /* folders as a special case because this FSSetCatalogInfo will fail for */ + /* an item in a drop folder, so we don't even attempt it. */ + if (err == noErr && !params->copyingToDropFolder) + { + ((FInfo *) &sourceCatInfo->finderInfo)->fdType = originalFileType; + sourceCatInfo->nodeFlags = originalNodeFlags; + *((FSPermissionInfo*)sourceCatInfo->permissions) = originalPermissions; + + /* 2796751, FSSetCatalogInfo returns -36 when setting the Finder Info */ + /* for a symlink. To workaround this, when the file is a */ + /* symlink (slnk/rhap) we will finish the copy in two steps. First */ + /* setting everything but the Finder Info on the file, then calling */ + /* FSpSetFInfo to set the Finder Info for the file. I would rather use */ + /* an FSRef function to set the Finder Info, but FSSetCatalogInfo is */ + /* the only one... catch-22... */ + /* */ + /* The Carbon File Manager always sets the type/creator of a symlink to */ + /* slnk/rhap if the file is a symlink we do the two step, if it isn't */ + /* we use FSSetCatalogInfo to do all the work. */ + if ((originalFileType == 'slnk') && (((FInfo *) &sourceCatInfo->finderInfo)->fdCreator == 'rhap')) + { /* Its a symlink */ + /* set all the info, except the Finder info */ + err = FSSetCatalogInfo(&dest, kFSCatInfoNodeFlags | kFSCatInfoPermissions, sourceCatInfo); + if ( err == noErr ) /* set the Finder Info to that file */ + err = FSpSetFInfo( &tmpSpec, ((FInfo *) &sourceCatInfo->finderInfo) ); + } + else /* its a regular file */ + err = FSSetCatalogInfo(&dest, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo | kFSCatInfoPermissions, sourceCatInfo); + } + + /* If we created the file and the copy failed, try to clean up by */ + /* deleting the file we created. We do this because, while it's */ + /* possible for the copy to fail halfway through and the File Manager */ + /* doesn't really clean up that well in that case, we *really* don't want */ + /* any half-created files being left around. */ + /* if the file already existed, we don't want to delete it */ + if( err == noErr || err == dupFNErr ) + { /* if everything was fine, then return the new file Spec/Ref */ + if( newRef != NULL ) + *newRef = dest; + if( newSpec != NULL ) + *newSpec = tmpSpec; + } + else + myverify_noerr( FSDeleteObjects(&dest) ); + + mycheck_noerr(err); + + return err; +} + +/*****************************************************************************/ + +#pragma mark ----- Copy Folders ----- + +static OSErr FSCopyFolder( const FSRef *source, + const FSRef *destDir, + const FSCatalogInfo *sourceCatInfo, + const HFSUniStr255 *newObjectName, + CopyParams *copyParams, + FilterParams *filterParams, + ItemCount maxLevels, + FSRef *outDirRef, + FSSpec *outDirSpec ) +{ + FSCopyFolderGlobals folderGlobals; + FolderListData *tmpListData = NULL; + FSCatalogInfo catInfo = *sourceCatInfo; + FSRef newDirRef; + FSSpec newDirSpec; + OSErr err; + + /* setup folder globals */ + folderGlobals.catInfoList = (FSCatalogInfo*) NewPtr( sizeof( FSCatalogInfo ) * kNumObjects ); + folderGlobals.srcRefList = (FSRef*) NewPtr( sizeof( FSRef ) * kNumObjects ); + folderGlobals.nameList = (HFSUniStr255*) NewPtr( sizeof( HFSUniStr255 ) * kNumObjects ); + folderGlobals.folderListIter = NULL; + folderGlobals.copyParams = copyParams; + folderGlobals.filterParams = filterParams; + folderGlobals.maxLevels = maxLevels; + folderGlobals.currentLevel = 0; + + /* if any of the NewPtr calls failed, we MUST bail */ + err = ( folderGlobals.catInfoList != NULL && + folderGlobals.srcRefList != NULL && + folderGlobals.nameList != NULL ) ? noErr : memFullErr; + + /* init the linked list we will use to keep track of the folders */ + InitLinkedList( &folderGlobals.folderList, MyDisposeDataProc ); + + if( err == noErr && !copyParams->copyingToDropFolder ) + err = GetMagicBusyCreateDate( &catInfo.createDate ); + if( err == noErr ) /* create the directory */ + err = DoCreateFolder( source, destDir, &catInfo, newObjectName, folderGlobals.copyParams, &newDirRef, (filterParams->wantSpec || outDirSpec ) ? &newDirSpec : NULL ); + + /* Note: if an error occured above, the FSRef and other info might not be valid */ + if( filterParams->filterProcPtr != NULL ) + { + /* get the info the user wanted about the source directory we don't have */ + if( err == noErr && (filterParams->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone ) + err = FSGetCatalogInfo(&newDirRef, filterParams->whichInfo & ~kFSCatInfoSettableInfo, &catInfo, NULL, NULL, NULL); + + err = CallCopyObjectFilterProc(filterParams->filterProcPtr, false, folderGlobals.currentLevel, + err, &catInfo, &newDirRef, + ( filterParams->wantSpec ) ? &newDirSpec : NULL, + ( filterParams->wantName ) ? newObjectName : NULL, + filterParams->yourDataPtr); + } + if( err == noErr ) /* create the memory for this folder */ + err = ( ( tmpListData = (FolderListData*) NewPtr( sizeof( FolderListData ) ) ) != NULL ) ? noErr : MemError(); + if( err == noErr ) + { /* setup the folder info */ + tmpListData->sourceDirRef = *source; + tmpListData->destDirRef = newDirRef; + tmpListData->level = folderGlobals.currentLevel; + /* add this folder to the list to give ProcessFolderList something to chew on */ + err = AddToTail( &folderGlobals.folderList, tmpListData ); + if( err == noErr ) /* tmpListData added successfully */ + err = ProcessFolderList( &folderGlobals ); + else /* error occured, so dispose of memory */ + DisposePtr( (char*) tmpListData ); + } + + dwarning(("\n%s -- %u folders were found\n", __FUNCTION__, (unsigned int)GetNumberOfItems( &folderGlobals.folderList ) )); + + /* when we're done destroy the list and free up any memory we allocated */ + DestroyList( &folderGlobals.folderList ); + + /* now that the copy is complete, we can set things back to normal */ + /* for the directory we just created. */ + /* We have to do this only for the top directory of the copy */ + /* all subdirectories were created all at once */ + if( err == noErr && !folderGlobals.copyParams->copyingToDropFolder ) + err = FSSetCatalogInfo( &newDirRef, kFSCatInfoCreateDate | kFSCatInfoPermissions, sourceCatInfo ); + + /* Copy went as planned, and caller wants an FSRef/FSSpec to the new directory */ + if( err == noErr ) + { + if( outDirRef != NULL) + *outDirRef = newDirRef; + if( outDirSpec != NULL ) + *outDirSpec = newDirSpec; + } + + /* clean up for space and safety, who me? */ + if( folderGlobals.catInfoList ) + DisposePtr( (char*) folderGlobals.catInfoList ); + if( folderGlobals.srcRefList ) + DisposePtr( (char*) folderGlobals.srcRefList ); + if( folderGlobals.nameList ) + DisposePtr( (char*) folderGlobals.nameList ); + + mycheck_noerr(err); + + return ( err ); +} + +/*****************************************************************************/ + + /* We now store a list of all the folders/subfolders we encounter in the source */ + /* Each node in the list contains an FSRef to the source, an FSRef to the */ + /* mirror folder in the destination, and the level in the source that folder */ + /* is on. This is done so that we can use FSGetCatalogInfoBulk to its full */ + /* potential (getting items in bulk). We copy the source one folder at a time. */ + /* Copying over the contents of each folder before we continue on to the next */ + /* folder in the list. This allows us to use the File Manager's own caching */ + /* system to our advantage. */ +static OSErr ProcessFolderList( FSCopyFolderGlobals *folderGlobals ) +{ + FolderListData *folderListData; + OSErr err = noErr; + + /* iterate through the list of folders and copy over each one individually */ + for( InitIterator( &folderGlobals->folderList, &folderGlobals->folderListIter ); folderGlobals->folderListIter != NULL && err == noErr; Next( &folderGlobals->folderListIter ) ) + { + /* Get the data for this folder */ + folderListData = (FolderListData*) GetData( folderGlobals->folderListIter ); + if( folderListData != NULL ) + { + #if DEBUG && !TARGET_API_MAC_OS8 + { + char path[1024]; + myverify_noerr(FSRefMakePath( &(folderListData->sourceDirRef), (unsigned char*)path, 1024 )); + dwarning(("\n\n%s -- Copying contents of\n\t%s\n", __FUNCTION__, path)); + myverify_noerr(FSRefMakePath( &(folderListData->destDirRef), (unsigned char*)path, 1024 )); + dwarning(("\t\tto\n\t%s\n", path)); + } + #endif + + /* stuff the data into our globals */ + folderGlobals->sourceDirRef = &(folderListData->sourceDirRef); + folderGlobals->destDirRef = &(folderListData->destDirRef); + folderGlobals->currentLevel = folderListData->level; + + /* Copy over this folder and add any subfolders to our list of folders */ + /* so they will get processed later */ + err = CopyFolder( folderGlobals ); + } + } + + return err; +} + +/*****************************************************************************/ + + /* Copy the contents of the source into the destination. If any subfolders */ + /* are found, add them to a local list of folders during the loop stage */ + /* Once the copy is done, insert the local list into the global list right */ + /* after the current position in the list. This is done so we don't jump */ + /* all over the disk getting the different folders to copy */ +static OSErr CopyFolder( FSCopyFolderGlobals *folderGlobals ) +{ + GenLinkedList tmpList; + FolderListData *tmpListData = NULL; + FilterParams *filterPtr = folderGlobals->filterParams; + FSIterator iterator; + FSRef newRef; + FSSpec newSpec; + UInt32 actualObjects; + OSErr err, + junkErr; + int i; + + /* Init the local list */ + InitLinkedList( &tmpList, MyDisposeDataProc); + + err = FSOpenIterator( folderGlobals->sourceDirRef, kFSIterateFlat, &iterator ); + if( err == noErr ) + { + do + { + /* grab a bunch of objects (kNumObjects) from this folder and copy them over */ + err = FSGetCatalogInfoBulk( iterator, kNumObjects, &actualObjects, &filterPtr->containerChanged, + kFSCatInfoSettableInfo, folderGlobals->catInfoList, folderGlobals->srcRefList, + NULL, folderGlobals->nameList ); + if( ( err == noErr || err == errFSNoMoreItems ) && + ( actualObjects != 0 ) ) + { + dwarning(("%s -- actualObjects retrieved from FSGetCatalogInfoBulk: %u\n",__FUNCTION__, (unsigned int)actualObjects )); + + /* iterate over the objects actually returned */ + for( i = 0; i < actualObjects; i++ ) + { + /* Any errors in here will be passed to the filter proc */ + /* we don't want an error in here to prematurely cancel the copy */ + + /* If you would like a Pre-Copy filter (i.e to weed out objects */ + /* you don't want to copy) you should add it here */ + + /* Is the new object a directory? */ + if( ( folderGlobals->catInfoList[i].nodeFlags & kFSNodeIsDirectoryMask ) != 0 ) + { /* yes */ + junkErr = CreateFolder( &folderGlobals->srcRefList[i], folderGlobals->destDirRef, + &folderGlobals->catInfoList[i], &folderGlobals->nameList[i], + folderGlobals->copyParams, &newRef, (filterPtr->wantSpec) ? &newSpec : NULL ); + /* If maxLevels is zero, we aren't checking levels */ + /* If currentLevel+1 < maxLevels, add this folder to the list */ + if( folderGlobals->maxLevels == 0 || (folderGlobals->currentLevel + 1) < folderGlobals->maxLevels ) + { + if( junkErr == noErr ) /* Create memory for folder list data */ + junkErr = ( ( tmpListData = (FolderListData*) NewPtr( sizeof( FolderListData ) ) ) != NULL ) ? noErr : MemError(); + if( junkErr == noErr ) + { /* Setup the folder list data */ + tmpListData->sourceDirRef = folderGlobals->srcRefList[i]; + tmpListData->destDirRef = newRef; + tmpListData->level = folderGlobals->currentLevel + 1; + + /* Add it to the local list */ + junkErr = AddToTail( &tmpList, tmpListData ); + } + /* If an error occured and memory was created, we need to dispose of it */ + /* since it was not added to the list */ + if( junkErr != noErr && tmpListData != NULL ) + DisposePtr( (char*) tmpListData ); + } + } + else + { /* no */ + junkErr = CopyFile( &folderGlobals->srcRefList[i], &folderGlobals->catInfoList[i], + folderGlobals->destDirRef, &folderGlobals->nameList[i], + folderGlobals->copyParams, &newRef, ( filterPtr->wantSpec ) ? &newSpec : NULL ); + } + + /* Note: if an error occured above, the FSRef and other info might not be valid */ + if( filterPtr->filterProcPtr != NULL ) + { + if( junkErr == noErr && (filterPtr->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone ) /* get the extra info about the new object that the user wanted that we don't already have */ + junkErr = FSGetCatalogInfo( &newRef, filterPtr->whichInfo & ~kFSCatInfoSettableInfo, &folderGlobals->catInfoList[i], NULL, NULL, NULL ); + + err = CallCopyObjectFilterProc( filterPtr->filterProcPtr, filterPtr->containerChanged, + folderGlobals->currentLevel, junkErr, + &folderGlobals->catInfoList[i], &newRef, + ( filterPtr->wantSpec ) ? &newSpec : NULL, + ( filterPtr->wantName ) ? &folderGlobals->nameList[i] : NULL, + filterPtr->yourDataPtr); + } + } + } + }while( err == noErr ); + + /* errFSNoMoreItems is OK - it only means we hit the end of this level */ + /* afpAccessDenied is OK too - it only means we cannot see inside the directory */ + if( err == errFSNoMoreItems || err == afpAccessDenied ) + err = noErr; + + /* Insert the local list of folders from the current folder into our global list. Even */ + /* if no items were added to the local list (due to error, or empty folder), InsertList */ + /* handles it correctly. We add the local list even if an error occurred. It will get */ + /* disposed of when the global list is destroyed. Doesn't hurt to have a couple extra */ + /* steps when we're going to bail anyways. */ + InsertList( &folderGlobals->folderList, &tmpList, folderGlobals->folderListIter ); + + /* Close the FSIterator (closing an open iterator should never fail) */ + (void) FSCloseIterator(iterator); + } + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + + /* Determines whether the destination directory is equal to the source */ + /* item, or whether it's nested inside the source item. Returns a */ + /* errFSDestInsideSource if that's the case. We do this to prevent */ + /* endless recursion while copying. */ + /* */ +static OSErr CheckForDestInsideSrc( const FSRef *source, + const FSRef *destDir) +{ + FSRef thisDir = *destDir; + FSCatalogInfo thisDirInfo; + Boolean done = false; + OSErr err; + + do + { + err = FSCompareFSRefs(source, &thisDir); + if (err == noErr) + err = errFSDestInsideSource; + else if (err == diffVolErr) + { + err = noErr; + done = true; + } + else if (err == errFSRefsDifferent) + { + /* This is somewhat tricky. We can ask for the parent of thisDir */ + /* by setting the parentRef parameter to FSGetCatalogInfo but, if */ + /* thisDir is the volume's FSRef, this will give us back junk. */ + /* So we also ask for the parent's dir ID to be returned in the */ + /* FSCatalogInfo record, and then check that against the node */ + /* ID of the root's parent (ie 1). If we match that, we've made */ + /* it to the top of the hierarchy without hitting source, so */ + /* we leave with no error. */ + + err = FSGetCatalogInfo(&thisDir, kFSCatInfoParentDirID, &thisDirInfo, NULL, NULL, &thisDir); + if( ( err == noErr ) && ( thisDirInfo.parentDirID == fsRtParID ) ) + done = true; + } + } while ( err == noErr && ! done ); + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + +#pragma mark ----- Copy Forks ----- + + /* This is where the majority of the work is done. I special cased */ + /* DropBoxes in order to use FSIterateForks to its full potential for */ + /* the more common case (read/write permissions). It also simplifies */ + /* the code to have it seperate. */ +static OSErr CopyForks( const FSRef *source, + const FSRef *dest, + CopyParams *params) +{ + OSErr err; + + err = ( !params->copyingToDropFolder ) ? CopyForksToDisk ( source, dest, params ) : + CopyForksToDropBox ( source, dest, params ); + + mycheck_noerr( err ); + + return err; +} + + /* Open each fork individually and copy them over to the destination */ +static OSErr CopyForksToDisk( const FSRef *source, + const FSRef *dest, + CopyParams *params ) +{ + HFSUniStr255 forkName; + CatPositionRec iterator; + SInt64 forkSize; + SInt16 srcRefNum, + destRefNum; + OSErr err; + + /* need to initialize the iterator before using it */ + iterator.initialize = 0; + + do + { + err = FSIterateForks( source, &iterator, &forkName, &forkSize, NULL ); + + /* Create the fork. Note: Data and Resource forks are automatically */ + /* created when the file is created. FSCreateFork returns noErr for them */ + /* We also want to create the fork even if there is no data to preserve */ + /* empty forks */ + if( err == noErr ) + err = FSCreateFork( dest, forkName.length, forkName.unicode ); + + /* Mac OS 9.0 has a bug (in the AppleShare external file system, */ + /* I think) [2410374] that causes FSCreateFork to return an errFSForkExists */ + /* error even though the fork is empty. The following code swallows */ + /* the error (which is harmless) in that case. */ + if( err == errFSForkExists && !params->copyingToLocalVolume ) + err = noErr; + + /* The remainder of this code only applies if there is actual data */ + /* in the source fork. */ + + if( err == noErr && forkSize > 0 ) + { + destRefNum = srcRefNum = 0; + + /* Open the destination fork */ + err = FSOpenFork(dest, forkName.length, forkName.unicode, fsWrPerm, &destRefNum); + if( err == noErr ) /* Open the source fork */ + err = FSOpenFork(source, forkName.length, forkName.unicode, fsRdPerm, &srcRefNum); + if( err == noErr ) /* Write the fork to disk */ + err = WriteFork( srcRefNum, destRefNum, params, forkSize ); + + if( destRefNum != 0 ) /* Close the destination fork */ + myverify_noerr( FSCloseFork( destRefNum ) ); + if( srcRefNum != 0 ) /* Close the source fork */ + myverify_noerr( FSCloseFork( srcRefNum ) ); + } + } + while( err == noErr ); + + if( err == errFSNoMoreItems ) + err = noErr; + + mycheck_noerr( err ); + + return err; +} + + /* If we're copying to a DropBox, we have to handle the copy process a little */ + /* differently then when we are copying to a regular folder. */ +static OSErr CopyForksToDropBox( const FSRef *source, + const FSRef *dest, + CopyParams *params ) +{ + GenLinkedList forkList; + GenIteratorPtr pIter; + ForkTrackerPtr forkPtr; + SInt16 srcRefNum; + OSErr err; + + InitLinkedList( &forkList, MyCloseForkProc ); + + /* If we're copying into a drop folder, open up all of those forks. */ + /* We have to do this because once we've started writing to a fork */ + /* in a drop folder, we can't open any more forks. */ + err = OpenAllForks( dest, &forkList ); + + /* Copy each fork over to the destination */ + for( InitIterator( &forkList, &pIter ); pIter != NULL && err == noErr; Next( &pIter ) ) + { + srcRefNum = 0; + forkPtr = GetData( pIter ); + /* Open the source fork */ + err = FSOpenFork(source, forkPtr->forkName.length, forkPtr->forkName.unicode, fsRdPerm, &srcRefNum); + if( err == noErr ) /* Write the data over */ + err = WriteFork( srcRefNum, forkPtr->forkDestRefNum, params, forkPtr->forkSize ); + + if( srcRefNum != 0 ) /* Close the source fork */ + myverify_noerr( FSCloseFork( srcRefNum ) ); + } + /* we're done, so destroy the list even if an error occured */ + /* the DisposeDataProc will close any open forks */ + DestroyList( &forkList ); + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + + /* Create and open all the forks in the destination file. We need to do this when */ + /* we're copying into a drop folder, where you must open all the forks before starting */ + /* to write to any of them. */ + /* */ + /* IMPORTANT: If it fails, this routine won't close forks that opened successfully. */ + /* Make sure that the DisposeDataProc for the forkList closed any open forks */ + /* Or you close each one manually before destroying the list */ +static OSErr OpenAllForks( const FSRef *dest, + GenLinkedList *forkList ) +{ + ForkTrackerPtr forkPtr; + HFSUniStr255 forkName; + CatPositionRec iterator; + SInt64 forkSize; + OSErr err = ( dest != NULL && forkList != NULL ) ? noErr : paramErr; + + /* need to initialize the iterator before using it */ + iterator.initialize = 0; + + /* Iterate over the list of forks */ + while( err == noErr ) + { + forkPtr = NULL; /* init forkPtr */ + + err = FSIterateForks( dest, &iterator, &forkName, &forkSize, NULL ); + if( err == noErr ) + err = ( forkPtr = (ForkTrackerPtr) NewPtr( sizeof( ForkTracker ) ) ) != NULL ? noErr : MemError(); + if( err == noErr ) + { + forkPtr->forkName = forkName; + forkPtr->forkSize = forkSize; + forkPtr->forkDestRefNum = 0; + + /* Create the fork. Note: Data and Resource forks are automatically */ + /* created when the file is created. FSCreateFork returns noErr for them */ + /* We also want to create the fork even if there is no data to preserve */ + /* empty forks */ + err = FSCreateFork( dest, forkName.length, forkName.unicode ); + + /* Swallow afpAccessDenied because this operation causes the external file */ + /* system compatibility shim in Mac OS 9 to generate a GetCatInfo request */ + /* to the AppleShare external file system, which in turn causes an AFP */ + /* GetFileDirParms request on the wire, which the AFP server bounces with */ + /* afpAccessDenied because the file is in a drop folder. As there's no */ + /* native support for non-classic forks in current AFP, there's no way I */ + /* can decide how I should handle this in a non-test case. So I just */ + /* swallow the error and hope that when native AFP support arrives, the */ + /* right thing will happen. */ + if( err == afpAccessDenied ) + err = noErr; + + /* only open the fork if the fork has some data */ + if( err == noErr && forkPtr->forkSize > 0 ) + err = FSOpenFork( dest, forkPtr->forkName.length, forkPtr->forkName.unicode, fsWrPerm, &forkPtr->forkDestRefNum ); + + /* if everything is ok, add this fork to the list */ + if( err == noErr ) + err = AddToTail( forkList, forkPtr ); + } + + if( err != noErr && forkPtr != NULL ) + DisposePtr( (char*) forkPtr ); + } + + if( err == errFSNoMoreItems ) + err = noErr; + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + + /* Writes the fork from the source, references by srcRefNum, to the destination fork */ + /* references by destRefNum */ +static OSErr WriteFork( const SInt16 srcRefNum, + const SInt16 destRefNum, + const CopyParams *params, + const SInt64 forkSize ) +{ + UInt64 bytesRemaining; + UInt64 bytesToReadThisTime; + UInt64 bytesToWriteThisTime; + OSErr err; + + + /* Here we create space for the entire fork on the destination volume. */ + /* FSAllocateFork has the right semantics on both traditional Mac OS */ + /* and Mac OS X. On traditional Mac OS it will allocate space for the */ + /* file in one hit without any other special action. On Mac OS X, */ + /* FSAllocateFork is preferable to FSSetForkSize because it prevents */ + /* the system from zero filling the bytes that were added to the end */ + /* of the fork (which would be waste because we're about to write over */ + /* those bytes anyway. */ + err = FSAllocateFork(destRefNum, kFSAllocNoRoundUpMask, fsFromStart, 0, forkSize, NULL); + + /* Copy the file from the source to the destination in chunks of */ + /* no more than params->copyBufferSize bytes. This is fairly */ + /* boring code except for the bytesToReadThisTime/bytesToWriteThisTime */ + /* distinction. On the last chunk, we round bytesToWriteThisTime */ + /* up to the next 512 byte boundary and then, after we exit the loop, */ + /* we set the file's EOF back to the real location (if the fork size */ + /* is not a multiple of 512 bytes). */ + /* */ + /* This technique works around a 'bug' in the traditional Mac OS File Manager, */ + /* where the File Manager will put the last 512-byte block of a large write into */ + /* the cache (even if we specifically request no caching) if that block is not */ + /* full. If the block goes into the cache it will eventually have to be */ + /* flushed, which causes sub-optimal disk performance. */ + /* */ + /* This is only done if the destination volume is local. For a network */ + /* volume, it's better to just write the last bytes directly. */ + /* */ + /* This is extreme over-optimization given the other limits of this */ + /* sample, but I will hopefully get to the other limits eventually. */ + bytesRemaining = forkSize; + while( err == noErr && bytesRemaining != 0 ) + { + if( bytesRemaining > params->copyBufferSize ) + { + bytesToReadThisTime = params->copyBufferSize; + bytesToWriteThisTime = bytesToReadThisTime; + } + else + { + bytesToReadThisTime = bytesRemaining; + bytesToWriteThisTime = ( params->copyingToLocalVolume ) ? + ( (bytesRemaining + 0x01FF ) & ~0x01FF ) : bytesRemaining; + } + + err = FSReadFork( srcRefNum, fsAtMark + noCacheMask, 0, bytesToReadThisTime, params->copyBuffer, NULL ); + if( err == noErr ) + err = FSWriteFork( destRefNum, fsAtMark + noCacheMask, 0, bytesToWriteThisTime, params->copyBuffer, NULL ); + if( err == noErr ) + bytesRemaining -= bytesToReadThisTime; + } + + if (err == noErr && params->copyingToLocalVolume && ( forkSize & 0x01FF ) != 0 ) + err = FSSetForkSize( destRefNum, fsFromStart, forkSize ); + + return err; +} + +/*****************************************************************************/ + +#pragma mark ----- Calculate Buffer Size ----- + + /* This routine calculates the appropriate buffer size for */ + /* the given volParms. It's a simple composition of FSGetVolParms */ + /* BufferSizeForVolSpeed. */ +static UInt32 CalcBufferSizeForVol(const GetVolParmsInfoBuffer *volParms, UInt32 volParmsSize) +{ + UInt32 volumeBytesPerSecond = 0; + + /* Version 1 of the GetVolParmsInfoBuffer included the vMAttrib */ + /* field, so we don't really need to test actualSize. A noErr */ + /* result indicates that we have the info we need. This is */ + /* just a paranoia check. */ + + mycheck(volParmsSize >= offsetof(GetVolParmsInfoBuffer, vMVolumeGrade)); + + /* On the other hand, vMVolumeGrade was not introduced until */ + /* version 2 of the GetVolParmsInfoBuffer, so we have to explicitly */ + /* test whether we got a useful value. */ + + if( ( volParmsSize >= offsetof(GetVolParmsInfoBuffer, vMForeignPrivID) ) && + ( volParms->vMVolumeGrade <= 0 ) ) + { + volumeBytesPerSecond = -volParms->vMVolumeGrade; + } + + return BufferSizeForVolSpeed(volumeBytesPerSecond); +} + +/*****************************************************************************/ + + /* Calculate an appropriate copy buffer size based on the volumes */ + /* rated speed. Our target is to use a buffer that takes 0.25 */ + /* seconds to fill. This is necessary because the volume might be */ + /* mounted over a very slow link (like ARA), and if we do a 256 KB */ + /* read over an ARA link we'll block the File Manager queue for */ + /* so long that other clients (who might have innocently just */ + /* called PBGetCatInfoSync) will block for a noticeable amount of time. */ + /* */ + /* Note that volumeBytesPerSecond might be 0, in which case we assume */ + /* some default value. */ +static UInt32 BufferSizeForVolSpeed(UInt32 volumeBytesPerSecond) +{ + ByteCount bufferSize; + + if (volumeBytesPerSecond == 0) + bufferSize = kDefaultCopyBufferSize; + else + { /* We want to issue a single read that takes 0.25 of a second, */ + /* so devide the bytes per second by 4. */ + bufferSize = volumeBytesPerSecond / 4; + } + + /* Round bufferSize down to 512 byte boundary. */ + bufferSize &= ~0x01FF; + + /* Clip to sensible limits. */ + if (bufferSize < kMinimumCopyBufferSize) + bufferSize = kMinimumCopyBufferSize; + else if (bufferSize > kMaximumCopyBufferSize) + bufferSize = kMaximumCopyBufferSize; + + return bufferSize; +} + +/*****************************************************************************/ + +#pragma mark ----- Delete Objects ----- + +OSErr FSDeleteObjects( const FSRef *source ) +{ + FSCatalogInfo catalogInfo; + OSErr err = ( source != NULL ) ? noErr : paramErr; + + #if DEBUG && !TARGET_API_MAC_OS8 + if( err == noErr ) + { + char path[1024]; + myverify_noerr(FSRefMakePath( source, (unsigned char*)path, 1024 )); + dwarning(("\n%s -- Deleting %s\n", __FUNCTION__, path)); + } + #endif + + /* get nodeFlags for container */ + if( err == noErr ) + err = FSGetCatalogInfo(source, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL); + if( err == noErr && (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0 ) + { /* its a directory, so delete its contents before we delete it */ + err = FSDeleteFolder(source); + } + if( err == noErr && (catalogInfo.nodeFlags & kFSNodeLockedMask) != 0 ) /* is object locked? */ + { /* then attempt to unlock the object (ignore err since FSDeleteObject will set it correctly) */ + catalogInfo.nodeFlags &= ~kFSNodeLockedMask; + (void) FSSetCatalogInfo(source, kFSCatInfoNodeFlags, &catalogInfo); + } + if( err == noErr ) /* delete the object (if it was a directory it is now empty, so we can delete it) */ + err = FSDeleteObject(source); + + mycheck_noerr( err ); + + return ( err ); +} + +/*****************************************************************************/ + +#pragma mark ----- Delete Folders ----- + +static OSErr FSDeleteFolder( const FSRef *container ) +{ + FSDeleteObjectGlobals theGlobals; + + theGlobals.result = ( container != NULL ) ? noErr : paramErr; + + /* delete container's contents */ + if( theGlobals.result == noErr ) + FSDeleteFolderLevel(container, &theGlobals); + + mycheck_noerr( theGlobals.result ); + + return ( theGlobals.result ); +} + +/*****************************************************************************/ + +static void FSDeleteFolderLevel(const FSRef *container, + FSDeleteObjectGlobals *theGlobals ) +{ + FSIterator iterator; + FSRef itemToDelete; + UInt16 nodeFlags; + + /* Open FSIterator for flat access and give delete optimization hint */ + theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator); + if ( theGlobals->result == noErr ) + { + do /* delete the contents of the directory */ + { + /* get 1 item to delete */ + theGlobals->result = FSGetCatalogInfoBulk( iterator, 1, &theGlobals->actualObjects, + NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo, + &itemToDelete, NULL, NULL); + if ( (theGlobals->result == noErr) && (theGlobals->actualObjects == 1) ) + { + /* save node flags in local in case we have to recurse */ + nodeFlags = theGlobals->catalogInfo.nodeFlags; + + /* is it a directory? */ + if ( (nodeFlags & kFSNodeIsDirectoryMask) != 0 ) + { /* yes -- delete its contents before attempting to delete it */ + FSDeleteFolderLevel(&itemToDelete, theGlobals); + } + if ( theGlobals->result == noErr) /* are we still OK to delete? */ + { + if ( (nodeFlags & kFSNodeLockedMask) != 0 ) /* is item locked? */ + { /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */ + theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask; + (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo); + } + /* delete the item */ + theGlobals->result = FSDeleteObject(&itemToDelete); + } + } + } while ( theGlobals->result == noErr ); + + /* we found the end of the items normally, so return noErr */ + if ( theGlobals->result == errFSNoMoreItems ) + theGlobals->result = noErr; + + /* close the FSIterator (closing an open iterator should never fail) */ + myverify_noerr(FSCloseIterator(iterator)); + } + + mycheck_noerr( theGlobals->result ); + + return; +} + +/*****************************************************************************/ + +#pragma mark ----- Utilities ----- + + /* Figures out if the given directory is a drop box or not */ + /* if it is, the Copy Engine will behave slightly differently */ +static OSErr IsDropBox( const FSRef* source, + Boolean *isDropBox ) +{ + FSCatalogInfo tmpCatInfo; + FSSpec sourceSpec; + Boolean isDrop = false; + OSErr err; + + /* get info about the destination, and an FSSpec to it for PBHGetDirAccess */ + err = FSGetCatalogInfo(source, kFSCatInfoNodeFlags | kFSCatInfoPermissions, &tmpCatInfo, NULL, &sourceSpec, NULL); + if( err == noErr ) /* make sure the source is a directory */ + err = ((tmpCatInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) ? noErr : errFSNotAFolder; + if( err == noErr ) + { + HParamBlockRec hPB; + + BlockZero( &hPB, sizeof( HParamBlockRec ) ); + + hPB.accessParam.ioNamePtr = sourceSpec.name; + hPB.accessParam.ioVRefNum = sourceSpec.vRefNum; + hPB.accessParam.ioDirID = sourceSpec.parID; + + /* This is the official way (reads: the way X Finder does it) to figure */ + /* out the current users access privileges to a given directory */ + err = PBHGetDirAccessSync(&hPB); + if( err == noErr ) /* its a drop folder if the current user only has write access */ + isDrop = (hPB.accessParam.ioACAccess & kPrivilegesMask) == kioACAccessUserWriteMask; + else if ( err == paramErr ) + { + /* There is a bug (2908703) in the Classic File System (not OS 9.x or Carbon) */ + /* on 10.1.x where PBHGetDirAccessSync sometimes returns paramErr even when the */ + /* data passed in is correct. This is a workaround/hack for that problem, */ + /* but is not as accurate. */ + /* Basically, if "Everyone" has only Write/Search access then its a drop folder */ + /* that is the most common case when its a drop folder */ + FSPermissionInfo *tmpPerm = (FSPermissionInfo *)tmpCatInfo.permissions; + isDrop = ((tmpPerm->mode & kRWXOtherAccessMask) == kDropFolderValue); + err = noErr; + } + } + + *isDropBox = isDrop; + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + + /* The copy engine is going to set the item's creation date */ + /* to kMagicBusyCreationDate while it's copying the item. */ + /* But kMagicBusyCreationDate is an old-style 32-bit date/time, */ + /* while the HFS Plus APIs use the new 64-bit date/time. So */ + /* we have to call a happy UTC utilities routine to convert from */ + /* the local time kMagicBusyCreationDate to a UTCDateTime */ + /* gMagicBusyCreationDate, which the File Manager will store */ + /* on disk and which the Finder we read back using the old */ + /* APIs, whereupon the File Manager will convert it back */ + /* to local time (and hopefully get the kMagicBusyCreationDate */ + /* back!). */ +static OSErr GetMagicBusyCreateDate( UTCDateTime *date ) +{ + static UTCDateTime magicDate = { 0, 0xDEADBEEF, 0 }; + OSErr err = ( date != NULL ) ? noErr : paramErr; + + if( err == noErr && magicDate.lowSeconds == 0xDEADBEEF ) + err = ConvertLocalTimeToUTC( kMagicBusyCreationDate, &magicDate.lowSeconds ); + if( err == noErr ) + *date = magicDate; + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + +static OSErr FSGetVRefNum( const FSRef *ref, + FSVolumeRefNum *vRefNum) +{ + FSCatalogInfo catalogInfo; + OSErr err = ( ref != NULL && vRefNum != NULL ) ? noErr : paramErr; + + if( err == noErr ) /* get the volume refNum from the FSRef */ + err = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); + if( err == noErr ) + *vRefNum = catalogInfo.volume; + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + +static OSErr FSGetVolParms( FSVolumeRefNum volRefNum, + UInt32 bufferSize, + GetVolParmsInfoBuffer *volParmsInfo, + UInt32 *actualInfoSize) /* Can Be NULL */ +{ + HParamBlockRec pb; + OSErr err = ( volParmsInfo != NULL ) ? noErr : paramErr; + + if( err == noErr ) + { + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr)volParmsInfo; + pb.ioParam.ioReqCount = (SInt32)bufferSize; + err = PBHGetVolParmsSync(&pb); + } + /* return number of bytes the file system returned in volParmsInfo buffer */ + if( err == noErr && actualInfoSize != NULL) + *actualInfoSize = (UInt32)pb.ioParam.ioActCount; + + mycheck_noerr( err ); + + return ( err ); +} + +/*****************************************************************************/ + +/* Converts a unicode string to a PString */ +/* If your code is only for OS X, you can use CFString functions to do all this */ +/* Since this sample code supports OS 9.1 -> OS X, I have to do this the */ +/* old fashioned way. */ +static OSErr UniStrToPStr( const HFSUniStr255 *uniStr, + TextEncoding textEncodingHint, + Boolean isVolumeName, + Str255 pStr ) +{ + UnicodeMapping uMapping; + UnicodeToTextInfo utInfo; + ByteCount unicodeByteLength = 0; + ByteCount unicodeBytesConverted; + ByteCount actualPascalBytes; + OSErr err = (uniStr != NULL && pStr != NULL) ? noErr : paramErr; + + /* make sure output is valid in case we get errors or there's nothing to convert */ + pStr[0] = 0; + + if( err == noErr ) + unicodeByteLength = uniStr->length * sizeof(UniChar); /* length can be zero, which is fine */ + if( err == noErr && unicodeByteLength != 0 ) + { + /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ + if ( kTextEncodingUnknown == textEncodingHint ) + { + ScriptCode script; + RegionCode region; + + script = (ScriptCode)GetScriptManagerVariable(smSysScript); + region = (RegionCode)GetScriptManagerVariable(smRegionCode); + err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, + region, NULL, &textEncodingHint ); + if ( err == paramErr ) + { /* ok, ignore the region and try again */ + err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, + kTextRegionDontCare, NULL, + &textEncodingHint ); + } + if ( err != noErr ) /* ok... try something */ + textEncodingHint = kTextEncodingMacRoman; + } + + uMapping.unicodeEncoding = CreateTextEncoding( kTextEncodingUnicodeV2_0, + kUnicodeCanonicalDecompVariant, + kUnicode16BitFormat); + uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint); + uMapping.mappingVersion = kUnicodeUseHFSPlusMapping; + + err = CreateUnicodeToTextInfo(&uMapping, &utInfo); + if( err == noErr ) + { + err = ConvertFromUnicodeToText( utInfo, unicodeByteLength, uniStr->unicode, kUnicodeLooseMappingsMask, + 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */ + isVolumeName ? kHFSMaxVolumeNameChars : kHFSPlusMaxFileNameChars, + &unicodeBytesConverted, &actualPascalBytes, &pStr[1]); + } + if( err == noErr ) + pStr[0] = actualPascalBytes; + + /* verify the result in debug builds -- there's really not anything you can do if it fails */ + myverify_noerr(DisposeUnicodeToTextInfo(&utInfo)); + } + + mycheck_noerr( err ); + + return ( err ); +} + +/*****************************************************************************/ + + /* Yeah I know there is FSpMakeFSRef, but this way I don't have to */ + /* actually have an FSSpec created to make the FSRef, and this is */ + /* what FSpMakeFSRef does anyways */ +static OSErr FSMakeFSRef( FSVolumeRefNum volRefNum, + SInt32 dirID, + ConstStr255Param name, + FSRef *ref ) +{ + FSRefParam pb; + OSErr err = ( ref != NULL ) ? noErr : paramErr; + + if( err == noErr ) + { + pb.ioVRefNum = volRefNum; + pb.ioDirID = dirID; + pb.ioNamePtr = (StringPtr)name; + pb.newRef = ref; + err = PBMakeFSRefSync(&pb); + } + + mycheck_noerr( err ); + + return ( err ); +} + +/*****************************************************************************/ + + /* This checks the destination to see if an object of the same name as the source */ + /* exists or not. If it does we have to special handle the DupeActions */ + /* */ + /* If kDupeActionReplace we move aside the object by renameing it to ".DeleteMe" */ + /* so that it will be invisible (X only), and give a suggestion on what to do with */ + /* it if for some unknown reason it survives the copy and the user finds it. This */ + /* rename is mainly done to handle the case where the source is in the destination */ + /* and the user wants to replace. Basically keeping the source around throughout */ + /* the copy, deleting it afterwards. Its also done cause its a good idea not to */ + /* dispose of the existing object in case the copy fails */ + /* */ + /* If kDupeActionRename, we create a unique name for the new object and pass */ + /* it back to the caller */ +static OSErr SetupDestination( const FSRef *destDir, + const DupeAction dupeAction, + HFSUniStr255 *sourceName, + FSRef *deleteMeRef, + Boolean *isReplacing ) +{ + FSRef tmpRef; + OSErr err; + + /* check if an object of the same name already exists in the destination */ + err = FSMakeFSRefUnicode( destDir, sourceName->length, sourceName->unicode, kTextEncodingUnknown, &tmpRef ); + if( err == noErr ) + { /* if the user wants to replace the existing */ + /* object, rename it to .DeleteMe first. Delete it */ + if( dupeAction == kDupeActionReplace ) /* only after copying the new one successfully */ + { + err = FSRenameUnicode( &tmpRef, 9, (UniChar*)"\0.\0D\0e\0l\0e\0t\0e\0M\0e", kTextEncodingMacRoman, deleteMeRef ); + *isReplacing = ( err == noErr ) ? true : false; + } + else if( dupeAction == kDupeActionRename ) /* if the user wants to just rename it */ + err = GetUniqueName( destDir, sourceName ); /* then we get a unique name for the new object */ + } + else if ( err == fnfErr ) /* if no object exists then */ + err = noErr; /* continue with no error */ + + return err; +} + +/*****************************************************************************/ + + /* Given a directory and a name, GetUniqueName will check if an object */ + /* with the same name already exists, and if it does it will create */ + /* a new, unique name for and return it. */ + /* it simply appends a number to the end of the name. It is not */ + /* fool proof, and it is limited... I'll take care of that in a */ + /* later release */ + /* If anyone has any suggestions/better techniques I would love to hear */ + /* about them */ +static OSErr GetUniqueName( const FSRef *destDir, + HFSUniStr255 *sourceName ) +{ + HFSUniStr255 tmpName = *sourceName; + FSRef tmpRef; + unsigned char hexStr[17] = "123456789"; /* yeah, only 9... I'm lazy, sosumi */ + long count = 0; + int index; + OSErr err; + + /* find the dot, if there is one */ + for( index = tmpName.length; index >= 0 && tmpName.unicode[index] != (UniChar) '.'; index-- ) { /* Do Nothing */ } + + if( index <= 0) /* no dot or first char is a dot (invisible file), so append to end of name */ + index = tmpName.length; + else /* shift the extension up two spots to make room for our digits */ + BlockMoveData( tmpName.unicode + index, tmpName.unicode + index + 2, (tmpName.length - index) * 2 ); + + /* add the space to the name */ + tmpName.unicode[ index ] = (UniChar)' '; + /* we're adding two characters to the name */ + tmpName.length += 2; + + do { /* add the digit to the name */ + tmpName.unicode[ index + 1 ] = hexStr[count]; + /* check if the file with this new name already exists */ + err = FSMakeFSRefUnicode( destDir, tmpName.length, tmpName.unicode, kTextEncodingUnknown, &tmpRef ); + count++; + } while( err == noErr && count < 10 ); + + if( err == fnfErr ) + { + err = noErr; + *sourceName = tmpName; + } + + return err; +} + +/*****************************************************************************/ + +static OSErr GetObjectName( const FSRef *sourceRef, + HFSUniStr255 *sourceName, /* can be NULL */ + TextEncoding *sourceEncoding ) /* can be NULL */ +{ + FSCatalogInfo catInfo; + FSCatalogInfoBitmap whichInfo = (sourceEncoding != NULL) ? kFSCatInfoTextEncoding : kFSCatInfoNone; + OSErr err; + + err = FSGetCatalogInfo( sourceRef, whichInfo, &catInfo, sourceName, NULL, NULL ); + if( err == noErr && sourceEncoding != NULL ) + *sourceEncoding = catInfo.textEncodingHint; + + return err; +} + +/*****************************************************************************/ + +static OSErr CreateFolder( const FSRef *sourceRef, + const FSRef *destDirRef, + const FSCatalogInfo *catalogInfo, + const HFSUniStr255 *folderName, + CopyParams *params, + FSRef *newFSRefPtr, + FSSpec *newFSSpecPtr ) +{ + FSCatalogInfo tmpCatInfo; + FSPermissionInfo origPermissions; + OSErr err = ( sourceRef != NULL && destDirRef != NULL && catalogInfo != NULL && + folderName != NULL && newFSRefPtr != NULL ) ? noErr : paramErr; + + if( err == noErr ) + { /* store away the catInfo, create date and permissions on the orig folder */ + tmpCatInfo = *catalogInfo; + origPermissions = *((FSPermissionInfo*)catalogInfo->permissions); + } + if( err == noErr ) /* create the new folder */ + err = DoCreateFolder( sourceRef, destDirRef, &tmpCatInfo, folderName, params, newFSRefPtr, newFSSpecPtr ); + if( err == noErr && !params->copyingToDropFolder ) + { /* if its not a drop box, set the permissions on the new folder */ + *((FSPermissionInfo*)tmpCatInfo.permissions) = origPermissions; + err = FSSetCatalogInfo( newFSRefPtr, kFSCatInfoPermissions, &tmpCatInfo ); + } + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + +static OSErr DoCreateFolder(const FSRef *sourceRef, + const FSRef *destDirRef, + const FSCatalogInfo *catalogInfo, + const HFSUniStr255 *folderName, + CopyParams *params, + FSRef *newFSRefPtr, + FSSpec *newFSSpecPtr) +{ + FSCatalogInfo catInfo = *catalogInfo; + OSErr err; + + /* Clear the "inited" bit so that the Finder positions the icon for us. */ + ((FInfo *)(catInfo.finderInfo))->fdFlags &= ~kHasBeenInited; + + /* we need to have user level read/write/execute access to the folder we are going to create, */ + /* otherwise FSCreateDirectoryUnicode will return -5000 (afpAccessDenied), */ + /* and the FSRef returned will be invalid, yet the folder is created... bug? */ + ((FSPermissionInfo*) catInfo.permissions)->mode |= kRWXUserAccessMask; + + err = FSCreateDirectoryUnicode( destDirRef, folderName->length, + folderName->unicode, kFSCatInfoSettableInfo, + &catInfo, newFSRefPtr, + newFSSpecPtr, NULL); + + /* With the new APIs, folders can have forks as well as files. Before */ + /* we start copying items in the folder, we must copy over the forks */ + /* Currently, MacOS doesn't support any file systems that have forks in */ + /* folders, but the API supports it so (for possible future */ + /* compatability) I kept this in here. */ + if( err == noErr ) + err = CopyForks( sourceRef, newFSRefPtr, params ); + + mycheck_noerr( err ); + + return err; +} + +/*****************************************************************************/ + + /* This is the DisposeDataProc that is used by the GenLinkedList in FSCopyFolder */ + /* Simply disposes of the data we created and returns */ +static pascal void MyDisposeDataProc( void *pData ) +{ + if( pData != NULL ) + DisposePtr( (char*) pData ); +} + +/*****************************************************************************/ + + /* This is the DisposeDataProc that is used by the GenLinkedList in CopyItemForks */ + /* Simply closes the resource fork (if opened, != 0) and disposes of the memory */ +static pascal void MyCloseForkProc( void *pData ) +{ + SInt16 refNum; + + if( pData == NULL ) + return; + + refNum = ((ForkTrackerPtr)pData)->forkDestRefNum; + if( refNum != 0 ) + myverify_noerr( FSCloseFork( refNum ) ); /* the fork was opened, so close it */ + + DisposePtr( (char*) pData ); +} diff --git a/wolf3d/code/iphone/FSCopyObject.h b/wolf3d/code/iphone/FSCopyObject.h new file mode 100644 index 0000000..3189f00 --- /dev/null +++ b/wolf3d/code/iphone/FSCopyObject.h @@ -0,0 +1,258 @@ +/* + File: FSCopyObject.h + + Contains: A Copy/Delete Files/Folders engine which uses the HFS+ API's + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2002-2004 Apple Computer, Inc., All Rights Reserved +*/ + + +#ifndef __FSCOPYOBJECT_H__ +#define __FSCOPYOBJECT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#if TARGET_API_MAC_OSX || defined( __APPLE_CC__ ) +#include +#endif + +#define DEBUG 1 /* set to zero if you don't want debug spew */ + +#if DEBUG + #include + + #define QuoteExceptionString(x) #x + + #define dwarning(s) do { printf s; fflush(stderr); } while( 0 ) + + #define mycheck_noerr( error ) \ + do { \ + if( (OSErr) error != noErr ) { \ + dwarning((QuoteExceptionString(error) " != noErr in File: %s, Function: %s, Line: %d, Error: %d\n", \ + __FILE__, __FUNCTION__, __LINE__, (OSErr) error)); \ + } \ + } while( false ) + + #define mycheck( assertion ) \ + do { \ + if( ! assertion ) { \ + dwarning((QuoteExceptionString(assertion) " failed in File: %s, Function: %s, Line: %d\n", \ + __FILE__, __FUNCTION__, __LINE__)); \ + } \ + } while( false ) + + #define myverify(assertion) mycheck(assertion) + #define myverify_noerr(assertion) mycheck_noerr( (assertion) ) +#else + #define dwarning(s) + + #define mycheck(assertion) + #define mycheck_noerr(err) + #define myverify(assertion) do { (void) (assertion); } while (0) + #define myverify_noerr(assertion) myverify(assertion) +#endif + +/* + This code takes some tricks/techniques from MoreFilesX (by Jim Luther) and + MPFileCopy (by Quinn), wraps them all up into an easy to use API, and adds a bunch of + features and bug fixes. It will run on Mac OS 9.1 through 9.2.x and 10.1.x + and up (Classic, Carbon and Mach-O) +*/ + + /* Different options that FSCopyObject can take during a copy */ +typedef UInt32 DupeAction; +enum { + kDupeActionStandard, /* will do the copy with no frills */ + kDupeActionReplace, /* will delete the existing object and then copy over the new one */ + kDupeActionRename /* will rename the new object if an object of the same name exists */ +}; + +/*****************************************************************************/ + +#pragma mark CopyObjectFilterProcPtr + +/* + This is the prototype for the CallCopyObjectFilterProc function which + is called once for each file and directory found by FSCopyObject. + The CallCopyObjectFilterProc can use the read-only data it receives for + whatever it wants. + + The result of the CallCopyObjectFilterProc function indicates if + the copy should be stopped. To stop the copy, return an error; to continue + the copy, return noErr. + + The yourDataPtr parameter can point to whatever data structure you might + want to access from within the CallCopyObjectFilterProc. + + Note: If an error had occured during the copy of the current object + (currentOSErr != noErr) the FSRef etc might not be valid + + containerChanged --> Set to true if the container's contents changed + during iteration. + currentLevel --> The current recursion level into the container. + 1 = the container, 2 = the container's immediate + subdirectories, etc. + currentOSErr --> The current error code, shows the results of the + copy of the current object (ref) + catalogInfo --> The catalog information for the current object. + Only the fields requested by the whichInfo + parameter passed to FSIterateContainer are valid. + ref --> The FSRef to the current object. + spec --> The FSSpec to the current object if the wantFSSpec + parameter passed to FSCopyObject is true. + name --> The name of the current object if the wantName + parameter passed to FSCopyObject is true. + yourDataPtr --> An optional pointer to whatever data structure you + might want to access from within the + CallCopyObjectFilterProc. + result <-- To continue the copy, return noErr + + __________ + + Also see: FSCopyObject +*/ + +typedef CALLBACK_API( OSErr , CopyObjectFilterProcPtr ) ( + Boolean containerChanged, + ItemCount currentLevel, + OSErr currentOSErr, + const FSCatalogInfo *catalogInfo, + const FSRef *ref, + const FSSpec *spec, + const HFSUniStr255 *name, + void *yourDataPtr); + + +/*****************************************************************************/ + +#pragma mark CallCopyObjectFilterProc + +#define CallCopyObjectFilterProc(userRoutine, containerChanged, currentLevel, currentOSErr, catalogInfo, ref, spec, name, yourDataPtr) \ + (*(userRoutine))((containerChanged), (currentLevel), (currentOSErr), (catalogInfo), (ref), (spec), (name), (yourDataPtr)) + +/*****************************************************************************/ + +#pragma mark FSCopyObject + +/* + The FSCopyObject function takes a source object (can be a file or directory) + and copies it (and its contents if it's a directory) to the new destination + directory. + + It will call your CopyObjectFilterProcPtr once for each object copied + + The maxLevels parameter is only used when the object is a directory, + ignored otherwise. + It lets you control how deep the recursion goes. + If maxLevels is 1, FSCopyObject only scans the specified directory; + if maxLevels is 2, FSCopyObject scans the specified directory and + one subdirectory below the specified directory; etc. Set maxLevels to + zero to scan all levels. + + The yourDataPtr parameter can point to whatever data structure you might + want to access from within your CopyObjectFilterProcPtr. + + source --> The FSRef to the object you want to copy + destDir --> The FSRef to the directory you wish to copy source to + maxLevels --> Maximum number of directory levels to scan or + zero to scan all directory levels, ignored if the + object is a file + whichInfo --> The fields of the FSCatalogInfo you wish passed + to you in your CopyObjectFilterProc + dupeAction --> The action to take if an object of the same name exists + in the destination + newName --> The name you want the new object to have. If you pass + in NULL, the source object name will be used. + wantFSSpec --> Set to true if you want the FSSpec to each + object passed to your CopyObjectFilterProc. + wantName --> Set to true if you want the name of each + object passed to your CopyObjectFilterProc. + filterProcPtr --> A pointer to the CopyObjectFilterProc you + want called once for each object found + by FSCopyObject. + yourDataPtr --> An optional pointer to whatever data structure you + might want to access from within the + CopyObjectFilterProc. + newObjectRef --> An optional pointer to an FSRef that, on return, + references the new object. If you don't want this + info returned, pass in NULL + newObjectSpec --> An optional pointer to an FSSPec that, on return, + references the new object. If you don't want this + info returned, pass in NULL +*/ + +OSErr FSCopyObject( const FSRef *source, + const FSRef *destDir, + ItemCount maxLevels, + FSCatalogInfoBitmap whichInfo, + DupeAction dupeAction, + const HFSUniStr255 *newName, /* can be NULL */ + Boolean wantFSSpec, + Boolean wantName, + CopyObjectFilterProcPtr filterProcPtr, /* can be NULL */ + void *yourDataPtr, /* can be NULL */ + FSRef *newObjectRef, /* can be NULL */ + FSSpec *newObjectSpec); /* can be NULL */ + +/*****************************************************************************/ + +#pragma mark FSDeleteObjects + +/* + The FSDeleteObjects function takes an FSRef to a file or directory + and attempts to delete it. If the object is a directory, all files + and subdirectories in the specified directory are deleted. If a + locked file or directory is encountered, it is unlocked and then + deleted. After deleting the directory's contents, the directory + is deleted. If any unexpected errors are encountered, + FSDeleteContainer quits and returns to the caller. + + source --> FSRef to an object (can be file or directory). + + __________ +*/ + +OSErr FSDeleteObjects( const FSRef *source ); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/wolf3d/code/iphone/GenLinkedList.c b/wolf3d/code/iphone/GenLinkedList.c new file mode 100644 index 0000000..50a3761 --- /dev/null +++ b/wolf3d/code/iphone/GenLinkedList.c @@ -0,0 +1,212 @@ +/* + File: GenLinkedList.c + + Contains: Linked List utility routines + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2003-2004 Apple Computer, Inc., All Rights Reserved +*/ + +#include "GenLinkedList.h" + +#pragma mark --- Data Structures --- + + /* This is the internal data structure for the nodes in the linked list. */ + /* */ + /* Note: The memory pointed to by pNext is owned by the list and is disposed of */ + /* in DestroyList. It should not be disposed of in any other way. */ + /* */ + /* Note: The memory pointed to by pData is owned by the caller of the linked */ + /* list. The caller is responsible for disposing of this memory. This can be */ + /* done by simply implementing a DisposeDataProc that will be called on each */ + /* node in the list, giving the caller a chance to dispose of any memory */ + /* created. The DisposeDataProc is called from DestroyList */ +struct GenNode +{ + struct GenNode *pNext; /* Pointer to the next node in the list */ + GenDataPtr pData; /* The data for this node, owned by caller */ +}; +typedef struct GenNode GenNode; + +#pragma mark --- List Implementation --- + + /* Initializes the given GenLinkedList to an empty list. This MUST be */ + /* called before any operations are performed on the list, otherwise bad things */ + /* will happen. */ +void InitLinkedList( GenLinkedList *pList, DisposeDataProcPtr disposeProcPtr) +{ + if( pList == NULL ) + return; + + pList->pHead = pList->pTail = NULL; + pList->NumberOfItems = 0; + pList->DisposeProcPtr = disposeProcPtr; +} + + /* returns the current number of items in the given list. */ + /* If pList == NULL, it returns 0 */ +ItemCount GetNumberOfItems( GenLinkedList *pList ) +{ + return (pList) ? pList->NumberOfItems : 0; +} + + /* Creates a new node, containing pData, and adds it to the tail of pList. */ + /* Note: if an error occurs, pList is unchanged. */ +OSErr AddToTail( GenLinkedList *pList, void *pData ) +{ + OSErr err = paramErr; + GenNode *tmpNode = NULL; + + if( pList == NULL || pData == NULL ) + return err; + + /* create memory for new node, if this fails we _must_ bail */ + err = ( ( tmpNode = (GenNode*) NewPtr( sizeof( GenNode ) ) ) != NULL ) ? noErr : MemError(); + if( err == noErr ) + { + tmpNode->pData = pData; /* Setup new node */ + tmpNode->pNext = NULL; + + if( pList->pTail != NULL ) /* more then one item already */ + ((GenNode*) pList->pTail)->pNext = (void*) tmpNode; /* so append to tail */ + else + pList->pHead = (void*) tmpNode; /* no items, so adjust head */ + + pList->pTail = (void*) tmpNode; + pList->NumberOfItems += 1; + } + + return err; +} + + /* Takes pSrcList and inserts it into pDestList at the location pIter points to. */ + /* The lists must have the same DisposeProcPtr, but the Data can be different. If pSrcList */ + /* is empty, it does nothing and just returns */ + /* */ + /* If pIter == NULL, insert pSrcList before the head */ + /* else If pIter == pTail, append pSrcList to the tail */ + /* else insert pSrcList in the middle somewhere */ + /* On return: pSrcList is cleared and is an empty list. */ + /* The data that was owned by pSrcList is now owned by pDestList */ +void InsertList( GenLinkedList *pDestList, GenLinkedList *pSrcList, GenIteratorPtr pIter ) +{ + if( pDestList == NULL || pSrcList == NULL || + pSrcList->pHead == NULL || pSrcList->pTail == NULL || + pDestList->DisposeProcPtr != pSrcList->DisposeProcPtr ) + return; + + if( pDestList->pHead == NULL && pDestList->pTail == NULL ) /* empty list */ + { + pDestList->pHead = pSrcList->pHead; + pDestList->pTail = pSrcList->pTail; + } + else if( pIter == NULL ) /* insert before head */ + { + /* attach the list */ + ((GenNode*)pSrcList->pTail)->pNext = pDestList->pHead; + /* fix up head */ + pDestList->pHead = pSrcList->pHead; + } + else if( pIter == pDestList->pTail ) /* append to tail */ + { + /* attach the list */ + ((GenNode*)pDestList->pTail)->pNext = pSrcList->pHead; + /* fix up tail */ + pDestList->pTail = pSrcList->pTail; + } + else /* insert in middle somewhere */ + { + GenNode *tmpNode = ((GenNode*)pIter)->pNext; + ((GenNode*)pIter)->pNext = pSrcList->pHead; + ((GenNode*)pSrcList->pTail)->pNext = tmpNode; + } + + pDestList->NumberOfItems += pSrcList->NumberOfItems; /* sync up NumberOfItems */ + + InitLinkedList( pSrcList, NULL); /* reset the source list */ +} + + /* Goes through the list and disposes of any memory we allocated. Calls the DisposeProcPtr,*/ + /* if it exists, to give the caller a chance to free up their memory */ +void DestroyList( GenLinkedList *pList ) +{ + GenIteratorPtr pIter = NULL, + pNextIter = NULL; + + if( pList == NULL ) + return; + + for( InitIterator( pList, &pIter ), pNextIter = pIter; pIter != NULL; pIter = pNextIter ) + { + Next( &pNextIter ); /* get the next node before we blow away the link */ + + if( pList->DisposeProcPtr != NULL ) + CallDisposeDataProc( pList->DisposeProcPtr, GetData( pIter ) ); + DisposePtr( (char*) pIter ); + } + + InitLinkedList( pList, NULL); +} + +/*#############################################*/ +/*#############################################*/ +/*#############################################*/ + +#pragma mark - +#pragma mark --- Iterator Implementation --- + + /* Initializes pIter to point at the head of pList */ + /* This must be called before performing any operations with pIter */ +void InitIterator( GenLinkedList *pList, GenIteratorPtr *pIter ) +{ + if( pList != NULL && pIter != NULL ) + *pIter = pList->pHead; +} + + /* On return, pIter points to the next node in the list. NULL if its gone */ + /* past the end of the list */ +void Next( GenIteratorPtr *pIter ) +{ + if( pIter != NULL ) + *pIter = ((GenNode*)*pIter)->pNext; +} + + /* Returns the data of the current node that pIter points to */ +GenDataPtr GetData( GenIteratorPtr pIter ) +{ + return ( pIter != NULL ) ? ((GenNode*)pIter)->pData : NULL; +} diff --git a/wolf3d/code/iphone/GenLinkedList.h b/wolf3d/code/iphone/GenLinkedList.h new file mode 100644 index 0000000..c6dd69a --- /dev/null +++ b/wolf3d/code/iphone/GenLinkedList.h @@ -0,0 +1,93 @@ +/* + File: GenLinkedList.h + + Contains: Linked List utility routines prototypes + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright © 2003-2004 Apple Computer, Inc., All Rights Reserved +*/ + + +#ifndef __GENLINKEDLIST__ +#define __GENLINKEDLIST__ + +#ifdef __cplusplus +extern "C" { +#endif + +#if TARGET_API_MAC_OSX || defined( __APPLE_CC__ ) +#include +#endif + +/* This is a quick, simple and generic linked list implementation. I tried */ +/* to setup the code so that you could use any linked list implementation you */ +/* want. They just need to support these few functions. */ + +typedef void* GenIteratorPtr; +typedef void* GenDataPtr; + + /* This is a callback that is called from DestroyList for each node in the */ + /* list. It gives the caller the oportunity to free any memory they might */ + /* allocated in each node. */ +typedef CALLBACK_API( void , DisposeDataProcPtr ) ( GenDataPtr pData ); + +#define CallDisposeDataProc( userRoutine, pData ) (*(userRoutine))((pData)) + +struct GenLinkedList +{ + GenDataPtr pHead; /* Pointer to the head of the list */ + GenDataPtr pTail; /* Pointer to the tail of the list */ + ItemCount NumberOfItems; /* Number of items in the list (mostly for debugging) */ + DisposeDataProcPtr DisposeProcPtr; /* rountine called to dispose of caller data, can be NULL */ +}; +typedef struct GenLinkedList GenLinkedList; + +void InitLinkedList ( GenLinkedList *pList, DisposeDataProcPtr disposeProcPtr ); +ItemCount GetNumberOfItems( GenLinkedList *pList ); +OSErr AddToTail ( GenLinkedList *pList, GenDataPtr pData ); +void InsertList ( GenLinkedList *pDestList, GenLinkedList *pSrcList, GenIteratorPtr pIter ); +void DestroyList ( GenLinkedList *pList ); + +void InitIterator ( GenLinkedList *pList, GenIteratorPtr *pIter ); +void Next ( GenIteratorPtr *pIter ); +GenDataPtr GetData ( GenIteratorPtr pIter ); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/wolf3d/code/iphone/Info.plist b/wolf3d/code/iphone/Info.plist index bc5d079..1835ef8 100644 --- a/wolf3d/code/iphone/Info.plist +++ b/wolf3d/code/iphone/Info.plist @@ -7,13 +7,13 @@ CFBundleDevelopmentRegion English CFBundleDisplayName - ${PRODUCT_NAME} + ${PRODUCT_NAME}+ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile ${PRODUCT_NAME}_icon.png CFBundleIdentifier - ${PROFILE_PREFIX}.${PRODUCT_NAME:identifier} + com.idsoftware.${PRODUCT_NAME:identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -22,26 +22,28 @@ APPL CFBundleSignature ???? - CFBundleVersion - 1.1 - LSRequiresIPhoneOS - - NSMainNibFile - MainWindow - UIInterfaceOrientation - UIInterfaceOrientationLandscapeLeft - UIStatusBarHidden - CFBundleURLTypes CFBundleURLName - com.idsoftware.wolf3d + com.idsoftware.wolf3dp CFBundleURLSchemes - wolf3d + wolf3dp + CFBundleVersion + 1.2 + LSRequiresIPhoneOS + + NSMainNibFile + MainWindow + UIInterfaceOrientation + UIInterfaceOrientationLandscapeLeft + UIPrerenderedIcon + + UIStatusBarHidden + diff --git a/wolf3d/code/iphone/arialGlyphRects.h b/wolf3d/code/iphone/arialGlyphRects.h new file mode 100644 index 0000000..7f65fb2 --- /dev/null +++ b/wolf3d/code/iphone/arialGlyphRects.h @@ -0,0 +1,104 @@ +// generated by fontimg +// + +typedef struct { unsigned short x0, y0, x1, y1; float xoff, yoff, xadvance; } GlyphRect; + +GlyphRect glyphRects[] = { + /* ' ' */ { 2, 2, 2, 2, 0.000000, 0.000000, 7.958042 }, + /* '!' */ { 6, 2, 9, 22, 2.250000, -20.750000, 7.958042 }, + /* '"' */ { 14, 2, 21, 9, 1.250000, -20.750000, 10.167832 }, + /* '#' */ { 26, 2, 41, 23, 0.250000, -21.000000, 15.930070 }, + /* '$' */ { 46, 2, 59, 27, 1.000000, -22.500000, 15.930070 }, + /* '%' */ { 64, 2, 86, 24, 1.500000, -21.000000, 25.468531 }, + /* '&' */ { 92, 2, 109, 23, 1.000000, -21.000000, 19.104895 }, + /* ''' */ { 114, 2, 117, 9, 1.250000, -20.750000, 5.468532 }, + /* '(' */ { 122, 2, 129, 29, 1.500000, -21.000000, 9.538462 }, + /* ')' */ { 134, 2, 141, 29, 1.500000, -21.000000, 9.538462 }, + /* '*' */ { 146, 2, 155, 11, 0.750000, -21.000000, 11.146853 }, + /* '+' */ { 160, 2, 173, 15, 1.500000, -17.000000, 16.727272 }, + /* ',' */ { 178, 2, 181, 9, 2.250000, -3.000000, 7.958042 }, + /* '-' */ { 186, 2, 194, 4, 0.750000, -8.750000, 9.538462 }, + /* '.' */ { 198, 2, 201, 5, 2.500000, -3.000000, 7.958042 }, + /* '/' */ { 206, 2, 214, 23, 0.000000, -21.000000, 7.958042 }, + /* '0' */ { 218, 2, 231, 23, 1.000000, -20.750000, 15.930070 }, + /* '1' */ { 236, 2, 243, 22, 3.000000, -20.750000, 15.930070 }, + /* '2' */ { 2, 34, 15, 54, 0.750000, -20.750000, 15.930070 }, + /* '3' */ { 20, 34, 33, 55, 1.000000, -20.750000, 15.930070 }, + /* '4' */ { 38, 34, 52, 54, 0.250000, -20.750000, 15.930070 }, + /* '5' */ { 58, 34, 72, 54, 1.000000, -20.250000, 15.930070 }, + /* '6' */ { 76, 34, 89, 55, 1.000000, -20.750000, 15.930070 }, + /* '7' */ { 94, 34, 107, 54, 1.250000, -20.250000, 15.930070 }, + /* '8' */ { 112, 34, 125, 55, 1.000000, -20.750000, 15.930070 }, + /* '9' */ { 130, 34, 143, 55, 1.000000, -20.750000, 15.930070 }, + /* ':' */ { 148, 34, 151, 49, 2.500000, -15.000000, 7.958042 }, + /* ';' */ { 156, 34, 159, 53, 2.250000, -15.000000, 7.958042 }, + /* '<' */ { 164, 34, 177, 48, 1.500000, -17.250000, 16.727272 }, + /* '=' */ { 182, 34, 195, 42, 1.500000, -14.500000, 16.727272 }, + /* '>' */ { 200, 34, 213, 48, 1.500000, -17.250000, 16.727272 }, + /* '?' */ { 218, 34, 231, 55, 1.250000, -21.000000, 15.930070 }, + /* '@' */ { 2, 60, 28, 87, 1.500000, -21.000000, 29.076923 }, + /* 'A' */ { 34, 60, 53, 80, -0.250000, -20.750000, 19.104895 }, + /* 'B' */ { 58, 60, 73, 80, 2.000000, -20.750000, 19.104895 }, + /* 'C' */ { 78, 60, 96, 81, 1.250000, -21.000000, 20.685314 }, + /* 'D' */ { 102, 60, 119, 80, 2.000000, -20.750000, 20.685314 }, + /* 'E' */ { 124, 60, 139, 80, 2.250000, -20.750000, 19.104895 }, + /* 'F' */ { 144, 60, 158, 80, 2.250000, -20.750000, 17.496504 }, + /* 'G' */ { 162, 60, 181, 81, 1.500000, -21.000000, 22.279720 }, + /* 'H' */ { 186, 60, 202, 80, 2.250000, -20.750000, 20.685314 }, + /* 'I' */ { 208, 60, 211, 80, 2.500000, -20.750000, 7.958042 }, + /* 'J' */ { 216, 60, 227, 81, 0.750000, -20.750000, 14.321678 }, + /* 'K' */ { 232, 60, 249, 80, 2.000000, -20.750000, 19.104895 }, + /* 'L' */ { 2, 92, 15, 112, 2.000000, -20.750000, 15.930070 }, + /* 'M' */ { 20, 92, 39, 112, 2.000000, -20.750000, 23.860140 }, + /* 'N' */ { 44, 92, 60, 112, 2.000000, -20.750000, 20.685314 }, + /* 'O' */ { 66, 92, 85, 113, 1.250000, -21.000000, 22.279720 }, + /* 'P' */ { 90, 92, 106, 112, 2.000000, -20.750000, 19.104895 }, + /* 'Q' */ { 110, 92, 130, 114, 1.000000, -21.000000, 22.279720 }, + /* 'R' */ { 136, 92, 154, 112, 2.250000, -20.750000, 20.685314 }, + /* 'S' */ { 160, 92, 176, 113, 1.250000, -21.000000, 19.104895 }, + /* 'T' */ { 182, 92, 198, 112, 0.500000, -20.750000, 17.496504 }, + /* 'U' */ { 204, 92, 220, 113, 2.250000, -20.750000, 20.685314 }, + /* 'V' */ { 226, 92, 245, 112, 0.000000, -20.750000, 19.104895 }, + /* 'W' */ { 2, 120, 28, 140, 0.250000, -20.750000, 27.034966 }, + /* 'X' */ { 34, 120, 53, 140, 0.000000, -20.750000, 19.104895 }, + /* 'Y' */ { 58, 120, 77, 140, 0.000000, -20.750000, 19.104895 }, + /* 'Z' */ { 82, 120, 98, 140, 0.500000, -20.750000, 17.496504 }, + /* '[' */ { 104, 120, 109, 146, 1.750000, -20.750000, 7.958042 }, + /* '\' */ { 114, 120, 122, 141, 0.000000, -21.000000, 7.958042 }, + /* ']' */ { 126, 120, 131, 146, 0.500000, -20.750000, 7.958042 }, + /* '^' */ { 136, 120, 148, 131, 0.750000, -21.000000, 13.440559 }, + /* '_' */ { 152, 120, 169, 122, -0.500000, 3.750000, 15.930070 }, + /* '`' */ { 174, 120, 179, 124, 1.000000, -20.750000, 9.538462 }, + /* 'a' */ { 184, 120, 197, 135, 1.000000, -15.250000, 15.930070 }, + /* 'b' */ { 202, 120, 215, 141, 1.750000, -20.750000, 15.930070 }, + /* 'c' */ { 220, 120, 233, 135, 1.000000, -15.250000, 14.321678 }, + /* 'd' */ { 238, 120, 251, 141, 0.750000, -20.750000, 15.930070 }, + /* 'e' */ { 2, 152, 15, 167, 1.000000, -15.250000, 15.930070 }, + /* 'f' */ { 20, 152, 28, 173, 0.250000, -21.000000, 7.958042 }, + /* 'g' */ { 34, 152, 47, 173, 0.750000, -15.250000, 15.930070 }, + /* 'h' */ { 52, 152, 64, 172, 1.750000, -20.750000, 15.930070 }, + /* 'i' */ { 70, 152, 72, 172, 1.750000, -20.750000, 6.363636 }, + /* 'j' */ { 78, 152, 84, 179, -1.500000, -20.750000, 6.363636 }, + /* 'k' */ { 88, 152, 100, 172, 1.750000, -20.750000, 14.321678 }, + /* 'l' */ { 106, 152, 108, 172, 1.750000, -20.750000, 6.363636 }, + /* 'm' */ { 114, 152, 134, 167, 1.750000, -15.250000, 23.860140 }, + /* 'n' */ { 140, 152, 152, 167, 1.750000, -15.250000, 15.930070 }, + /* 'o' */ { 158, 152, 172, 167, 0.750000, -15.250000, 15.930070 }, + /* 'p' */ { 178, 152, 191, 173, 1.750000, -15.250000, 15.930070 }, + /* 'q' */ { 196, 152, 209, 173, 1.000000, -15.250000, 15.930070 }, + /* 'r' */ { 214, 152, 222, 167, 1.750000, -15.250000, 9.538462 }, + /* 's' */ { 228, 152, 240, 167, 0.750000, -15.250000, 14.321678 }, + /* 't' */ { 246, 152, 253, 172, 0.500000, -20.250000, 7.958042 }, + /* 'u' */ { 2, 184, 14, 199, 1.750000, -15.000000, 15.930070 }, + /* 'v' */ { 20, 184, 33, 199, 0.250000, -15.000000, 14.321678 }, + /* 'w' */ { 38, 184, 58, 199, 0.000000, -15.000000, 20.685314 }, + /* 'x' */ { 64, 184, 78, 199, 0.000000, -15.000000, 14.321678 }, + /* 'y' */ { 84, 184, 98, 205, 0.250000, -15.000000, 14.321678 }, + /* 'z' */ { 102, 184, 115, 199, 0.500000, -15.000000, 14.321678 }, + /* '{' */ { 120, 184, 128, 211, 0.750000, -21.000000, 9.566434 }, + /* '|' */ { 134, 184, 136, 211, 2.500000, -21.000000, 7.440559 }, + /* '}' */ { 142, 184, 150, 211, 0.500000, -21.000000, 9.566434 }, + /* '~' */ { 156, 184, 170, 188, 1.000000, -12.500000, 16.727272 }, + /* '' */ { 176, 184, 190, 202, 3.500000, -18.000000, 21.482517 } +}; + diff --git a/wolf3d/code/iphone/default.png b/wolf3d/code/iphone/default.png index 9341665..c3505d4 100644 Binary files a/wolf3d/code/iphone/default.png and b/wolf3d/code/iphone/default.png differ diff --git a/wolf3d/code/iphone/gles_glue.c b/wolf3d/code/iphone/gles_glue.c index 08ac8f7..d4d53f9 100644 --- a/wolf3d/code/iphone/gles_glue.c +++ b/wolf3d/code/iphone/gles_glue.c @@ -101,6 +101,14 @@ void pfglVertex2i( GLint x, GLint y ) { immediate[ curr_vertex ] = vab; curr_vertex++; } +void pfglVertex2f( GLfloat x, GLfloat y ) { + assert( curr_vertex < MAX_VERTS ); + vab.xyz[ 0 ] = (float)x; + vab.xyz[ 1 ] = (float)y; + vab.xyz[ 2 ] = 0.0f; + immediate[ curr_vertex ] = vab; + curr_vertex++; +} void pfglColor4ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a ) { vab.c[ 0 ] = r; vab.c[ 1 ] = g; diff --git a/wolf3d/code/iphone/hud.c b/wolf3d/code/iphone/hud.c index 674e964..056a76e 100644 --- a/wolf3d/code/iphone/hud.c +++ b/wolf3d/code/iphone/hud.c @@ -224,6 +224,7 @@ void HudEditFrame() { // solid background color and some UI elements for context R_Draw_Fill( 0, 0, 480, 320, gray ); + iphoneDrawFace(); iphoneDrawNotifyText(); @@ -247,3 +248,336 @@ void HudEditFrame() { } } +//gsh +/* +int boundsLeft = 86;//70; +int boundsRight = 386;//480-72; +int boundsAbove = 80-15;//97; +int boundsUnder = 285-15;//320-15; +*/ +//------------------ +// ConvertFromImageToScreen +// This converts a point placed in the screen of the iphone image +// to the screen coordinates of the actual iphone +// gsh +//------------------- +void ConvertFromImageToScreen(int *x, int *y, rect_t boundsRect) +{ + int boundsLeft = boundsRect.x; + int boundsRight = boundsRect.x + boundsRect.width; + int boundsAbove = boundsRect.y; + int boundsUnder = boundsRect.y + boundsRect.height; + + int valX = *x;//prevTouches[0][0]; + int valY = *y;//prevTouches[0][1]; + + //int boundsLeft = 64; + //int boundsRight = 480-64; + int width = boundsRight - boundsLeft; + + //int boundsAbove = 100; + //int boundsUnder = 320-10; + int height = boundsUnder - boundsAbove; + + valX -= boundsLeft; + valX = 480*valX/width; + + valY -= boundsAbove; + valY = 320*valY/height; + + *x = valX; + *y = valY; +} + +//------------------ +// ConvertFromScreenToImage +// This converts a point placed on the screen of the iphone +// to the coordinates of the screen of the iphone image +// gsh +//------------------- +void ConvertFromScreenToImage(int *x, int *y, rect_t boundsRect) +{ + int boundsLeft = boundsRect.x; + int boundsRight = boundsRect.x + boundsRect.width; + int boundsAbove = boundsRect.y; + int boundsUnder = boundsRect.y + boundsRect.height; + + int valX = *x;//prevTouches[0][0]; + int valY = *y;//prevTouches[0][1]; + + //int boundsLeft = 64; + //int boundsRight = 480-64; + int width = boundsRight - boundsLeft; + + //int boundsAbove = 100; + //int boundsUnder = 320-10; + int height = boundsUnder - boundsAbove; + + valX = width*valX/480; + valX += boundsLeft; + + valY = height*valY/320; + valY += boundsAbove; + + *x = valX; + *y = valY; +} + +//------------------ +// ScaleFromScreenToImage +// This converts to the correct scale to draw with +// gsh +//------------------- +void ScaleFromScreenToImage(int *width, int *height, rect_t boundsRect) +{ + int boundsLeft = boundsRect.x; + int boundsRight = boundsRect.x + boundsRect.width; + int boundsAbove = boundsRect.y; + int boundsUnder = boundsRect.y + boundsRect.height; + + int w = *width; + int h = *height; + + //int boundsLeft = 64; + //int boundsRight = 480-64; + int iW = boundsRight - boundsLeft; + + //int boundsAbove = 100; + //int boundsUnder = 320-10; + int iH = boundsUnder - boundsAbove; + + w = w*iW/480; + h = h*iH/320; + + *width = w; + *height = h; +} + + +/* + ================== + iphoneHudEditFrame + Same as HudEditFrame only different + gsh + ================== + */ +void iphoneHudEditFrame() { + int w; + int x; + colour3_t gray = { 32, 32, 32 }; + + int adjustY = 10; + + rect_t boundsRect = RectMake(86, 80-adjustY, 300, 205); + + + + //iphoneSetNotifyText( "Drag the controls" ); + + if ( numTouches == 0 && numPrevTouches == 1 && dragHud ) { + // if it was released near the center, make it inactive + int x = prevTouches[0][0]; + int y = prevTouches[0][1]; + + //convert x, y coordinates from iphone_image to screen coordinates + ConvertFromImageToScreen( &x, &y, boundsRect); + //ConvertFromScreenToImage( &x, &y); + + if ( x > 120 && x < 360 && y > 80 && y < 240 ) { + dragHud->hudFlags |= HF_DISABLED; + } else { + // magnet pull a matchable axis if it is close enough + if ( dragHud == &huds.forwardStick ) { + SnapSticks( &huds.sideStick, dragHud ); + SnapSticks( &huds.turnStick, dragHud ); + } + if ( dragHud == &huds.sideStick ) { + SnapSticks( &huds.forwardStick, dragHud ); + } + if ( dragHud == &huds.turnStick ) { + SnapSticks( &huds.forwardStick, dragHud ); + } + } + Sound_StartLocalSound( "iphone/baction_01.wav" ); + dragHud = NULL; + } + + if ( numTouches == 1 && numPrevTouches == 0 ) { + // identify the hud being touched for drag + int x = touches[0][0]; + int y = touches[0][1]; + + //convert x, y coordinates from iphone_image to screen coordinates + ConvertFromImageToScreen( &x, &y, boundsRect); +// ConvertFromScreenToImage( &x, &y); + + dragHud = NULL; + for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) { + if ( x >= hud->x && x - hud->x < hud->width && + y >= hud->y && y - hud->y < hud->height ) { + dragHud = hud; + //int tempDragX = dragHud->x; + //int tempDragY = dragHud->y; + //ConvertFromImageToScreen(&, <#int * y#>) + dragX = dragHud->x - x; + dragY = dragHud->y - y; + Sound_StartLocalSound( "iphone/bdown_01.wav" ); + dragHud->hudFlags &= ~HF_DISABLED; + break; + } + } + } + + if ( numTouches == 1 && numPrevTouches == 1 && dragHud ) { + // adjust the position of the dragHud + int x = touches[0][0]; + int y = touches[0][1]; + ConvertFromImageToScreen(&x, &y, boundsRect); + + dragHud->x = x + dragX; + dragHud->y = y + dragY; + if ( dragHud->x < 0 ) { + dragHud->x = 0; + } + if ( dragHud->x > 480 - dragHud->width ) { + dragHud->x = 480 - dragHud->width; + } + if ( dragHud->y < 0 ) { + dragHud->y = 0; + } + if ( dragHud->y > 320 - dragHud->height ) { + dragHud->y = 320 - dragHud->height; + } + } + + // layout the disabled items in the center + w = 0; + for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) { + if ( hud->hudFlags & HF_DISABLED ) { + w += hud->width; + } + } + x = 240 - w / 2; + + for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) { + if ( hud->hudFlags & HF_DISABLED ) { + hud->x = x; + hud->y = 160-hud->height/2; + x += hud->width; + } + } + + // decide where the menu button, map button, and ammo will draw + + // solid background color and some UI elements for context + R_Draw_Fill( 0, 0, 480, 320, gray ); + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + //iphoneDrawPic(240-108, 0, 217, 50, "iphone/header_advanced.tga"); + iphoneDrawPic(240-108*9/10, 0, 217*9/10, 50*9/10, "iphone/header_advanced.tga"); + + //gsh + iphoneDrawPic(10, 60-adjustY, 462, 250, "iphone/iphone_image.tga"); +// iphoneDrawPic(0, 320-240, 480, 240, "iphone/iphone_image.tga"); + + +// iphoneDrawFace(); +// iphoneDrawNotifyText(); + + + // draw the active items at their current locations + for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) { //nice foreach loop! + if ( hud->hudFlags & HF_DISABLED ) { + pfglColor3f( 0.5, 0.5, 0.5 ); + } + if ( hud == &huds.ammo ) { + int x = huds.ammo.x + huds.ammo.width / 2; + int y = huds.ammo.y; + int w = 48; + int h = 48; + + ConvertFromScreenToImage(&x, &y, boundsRect); + ScaleFromScreenToImage(&w, &h, boundsRect); + + iphoneDrawNumber( x, y, 99, w, h ); + } else { + int x = hud->x; + int y = hud->y; + int w = hud->width; + int h = hud->height; + + ConvertFromScreenToImage(&x, &y, boundsRect); + ScaleFromScreenToImage(&w, &h, boundsRect); + + iphoneDrawPicNum( x, y, w, h, hud->glTexNum ); + } + pfglColor3f( 1, 1, 1 ); + } + + + + + + // draw the back button + if ( iphoneDrawPicWithTouch( 0, 0, 64, 36, "iphone/button_back.tga" ) ) { + menuState = IPM_CONTROLS; + iphoneSetNotifyText( "" ); + } + + //x = 64; + //if (revLand->value) + x = 480-64; + // draw the menu button + if ( iphoneDrawPicWithTouch( x, 0, 64, 36, "iphone/menu.tga" ) ) { + //if ( iphoneDrawPicWithTouch( 64, 0, 64, 36, "iphone/button_menu_yellow.tga" ) ) { + menuState = IPM_MAIN; + iphoneSetNotifyText( "" ); + } + + /* + //------------------------------------ + //Draw volume up/down settings... gsh + int width = 64*9/10; + int height = 36;//48*9/10; + + int y = 0; + y = 0; + x = 480-width; + if (revLand->value){ + y = 320-height; + x = 0; + } + + //gsh + if ((int)volumeFireUpSetting->value) { + if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_pistol.tga" )) + Cvar_Set("volumeFireUpSetting", "0"); + } + else { + if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_knife.tga" )) + Cvar_Set("volumeFireUpSetting", "1"); + } + + + x = 480-width-width-5; + if (revLand->value) + x = width+5; + + if ((int)volumeFireDownSetting->value) { + if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_pistol.tga" )) + Cvar_Set("volumeFireDownSetting", "0"); + } + else { + if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_knife.tga" )) + Cvar_Set("volumeFireDownSetting", "1"); + } + //----------------------------------- + */ + //draw the instructions + //if (revLand->value) + // iphoneDrawText(x+width+20, 300, 16, 16, "Drag the controls to customize"); + //else +// iphoneCenterText(240, 300, "Drag each element of the controls to customize"); + iphoneCenterArialText(245, 315, 0.8f, "Drag each element of the controls to customize"); +} + diff --git a/wolf3d/code/iphone/iphone_alerts.h b/wolf3d/code/iphone/iphone_alerts.h new file mode 100644 index 0000000..45227d0 --- /dev/null +++ b/wolf3d/code/iphone/iphone_alerts.h @@ -0,0 +1,39 @@ +/* + * iphone_alerts.h + * wolf3d + * + * Created by Greg Hodges on 7/14/09. + * Copyright 2009 id software. All rights reserved. + * + * C wrappers for the UIAlertView. + * + */ +/* + + Copyright (C) 2009 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef __IPHONE_ALERTS__ +#define __IPHONE_ALERTS__ + +void iphoneMessageBox(char *title, char *message); +void iphoneKillMessageBox(); +void iphoneYesNoBox(char *title, char *message); + +#endif \ No newline at end of file diff --git a/wolf3d/code/iphone/iphone_alerts.m b/wolf3d/code/iphone/iphone_alerts.m new file mode 100644 index 0000000..e1a4464 --- /dev/null +++ b/wolf3d/code/iphone/iphone_alerts.m @@ -0,0 +1,110 @@ +/* + * iphone_alerts.c + * wolf3d + * + * Created by Greg Hodges on 7/14/09. + * Copyright 2009 id software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#import "iphone_alerts.h" +#import "wolf3dAppDelegate.h" + + +/* + ================================== + MessageBox + Provides a basic pop-up message box + =================================== + */ +UIAlertView *alert; + +void InitAlert() +{ + alert = [[UIAlertView alloc] initWithTitle:@"Title" + message:@"Message" + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles: nil]; +} + + +void iphoneMessageBox(char *title, char *message) +{ + //check if alert exists and initialize if it isn't + if (!alert) + { + InitAlert(); + } + + NSString *nsTitle = [[NSString alloc] initWithCString:title]; + NSString *nsMessage = [[NSString alloc] initWithCString:message]; + + alert.title = nsTitle; + alert.message = nsMessage; + + [alert show]; +} + +void iphoneKillMessageBox() +{ + [alert dismissWithClickedButtonIndex:alert.cancelButtonIndex animated:NO]; +} + +#if 1 +/* + ================================== + YesNoBox + Provides a yes/no box. The + appdelegate responds to this + through the UIAlerViewDelegate + ClickedButton call. + =================================== + */ +UIAlertView *alertYesNo; + +void InitAlertYesNo() +{ + alertYesNo = [[UIAlertView alloc] initWithTitle:@"Title" + message:@"Message" + delegate:(wolf3dAppDelegate *)[UIApplication sharedApplication].delegate//nil + cancelButtonTitle:@"No" + otherButtonTitles:@"Yes", nil]; +} + +void iphoneYesNoBox(char *title, char *message) +{ + if (!alertYesNo) + { + InitAlertYesNo(); + } + + NSString *nsTitle = [[NSString alloc] initWithCString:title]; + NSString *nsMessage = [[NSString alloc] initWithCString:message]; + + alertYesNo.title = nsTitle; + alertYesNo.message = nsMessage; + + [alertYesNo show]; +} +#endif diff --git a/wolf3d/code/iphone/iphone_downloadSOD.m b/wolf3d/code/iphone/iphone_downloadSOD.m new file mode 100644 index 0000000..0cf94a3 --- /dev/null +++ b/wolf3d/code/iphone/iphone_downloadSOD.m @@ -0,0 +1,359 @@ +// +// iphone_downloadSOD.m +// wolf3d +// +// Created by Greg Hodges on 6/8/09. +// Copyright 2009 id software. All rights reserved. +// +/* + + Copyright (C) 2009 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + + +#import "../wolfiphone.h" +#import "wolf3dAppDelegate.h" +#import "iphone_alerts.h" + +#include +#include + +#import //this is for testing network availability + +//Note: in order to link the zlib library into the build from usr/lib/libz.ylib +// the flag -lz was added to the OTHER_LDFLAGS under the build options. +// To get there: right click on the wolf3d project. choose get info. +// Click on build and scroll to "Other Link Flags" under "Linking" + + +extern void Com_Printf(const char* fmt, ... ); +extern void my_snprintf( char *dest, size_t size, const char *format, ... ); + +#ifdef SPEARSTOREKIT +extern void PurchaseSOD(); +extern bool isStorekitAvailable; +#endif +extern char iphoneDocDirectory[1024]; +extern menuState_t menuState; + + +int inf(FILE *source, FILE *dest); +void zerr(int ret); + + +//this is used for determining if we have the correctly sized data +const unsigned int DownloadFileSize = 45583; //size of maps + +//----------------------------- +// TestURLConnection +// Test for internet access +//----------------------------- +int TestURLConnection() +{ + Com_Printf("Testing URL Connection\n"); + + //We wish to be able to test connectability to both apple and id + //because we need to communicate to both in order to complete the Spear of Destiny Transaction + + char *hostid = "www.idsoftware.com"; + char *hostApple = "www.apple.com"; + SCNetworkReachabilityFlags flags[2]; + SCNetworkReachabilityRef reachability; + BOOL gotFlags[2]; + + reachability = SCNetworkReachabilityCreateWithName(NULL, hostid); + gotFlags[0] = SCNetworkReachabilityGetFlags(reachability, &flags[0]); + CFRelease(reachability); + + reachability = SCNetworkReachabilityCreateWithName(NULL, hostApple); + gotFlags[1] = SCNetworkReachabilityGetFlags(reachability, &flags[1]); + CFRelease(reachability); + + + if (gotFlags[0] && gotFlags[1]) + { + // kSCNetworkReachabilityFlagsReachable indicates that the specified nodename or address can + // be reached using the current network configuration. + if ((flags[0] & kSCNetworkReachabilityFlagsReachable) && (flags[1] & kSCNetworkReachabilityFlagsReachable)) + { + Com_Printf("Both Hosts were reached\n"); + return 1; + } + } + + //TODO: alert user they cannot download SOD + iphoneMessageBox("Host Server Unavailable", "Check your internet connection and try again later."); + + return 0; +} + +//----------------------------- +// OpenURLConnection +// This connects to a server and downloads the file located there +//----------------------------- +void OpenURLConnection( const char *url ) +{ + Com_Printf( "ConnectURL char *: %s\n", url ); + + //convert url to nsstring + NSString *nssURL = [NSString stringWithUTF8String: url]; + + // create the request + NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:nssURL] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:60.0]; + + // create the connection with the request + // and start loading the data + NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest + delegate:(wolf3dAppDelegate *)[UIApplication sharedApplication].delegate]; + + if (!theConnection) + { + // inform the user that the download could not be made + Com_Printf("Connection failed... no download plausible\n"); + + //inform user + iphoneMessageBox("Connection Failed", "The install was unable to download. Check your internet connection and try again later."); + + //return to main menu + menuState = IPM_MAIN; + } +} + +//============================ +// DisplayWrongVersionedOS +// Display to the user they have the wrong OS version and cannot use storekit +//============================= +void DisplayWrongVersionedOS() +{ + iphoneMessageBox("Feature Unavailable", "Your device is not updated. This feature requires OS 3.0 or higher."); +} + +//============================ +// BeginStoreKit +// This starts the purchasing process of the storekit framework +//============================= +#ifdef SPEARSTOREKIT +void BeginStoreKit() +{ + //only start the storekit API if it exists + if (isStorekitAvailable) + { + if (TestURLConnection()) //check URL connection again + { + menuState = IPM_STOREKIT; + Com_Printf("BeginStoreKit() called\n"); + PurchaseSOD(); + } + } + else + DisplayWrongVersionedOS(); +} +#endif + + +//============================ +// DownloadSOD +// starts the download process of SOD +// this is called after purchase of the SOD levels is confirmed +//============================= +void DownloadSOD() +{ + menuState = IPM_DOWNLOADPROGRESS; //change the menu to the download screen + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + //check if download.tgz already exists and delete if it does + //create/open file for saving + NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/downloadedfile.tgz"]; + NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath]; + + if (file) //file exists... delete it, we do not care to append to a pre-exisiting file + { + if( remove( [fileatpath UTF8String] ) != 0 ) + Com_Printf("Error deleting buffer\n"); + else + Com_Printf("Deleted buffer\n"); + } + + //TODO: change this url to what will eventually be the permanent location + OpenURLConnection("http://gregory.hodges.googlepages.com/spearMaps.tgz"); + + //after this the control automatically goes back to the appDelegate where it receives the packets of downloaded information +} + +unsigned int dataAmount = 0; +unsigned int dataTotalAmount = 0; +extern unsigned int totalDownloaded; +//int hasBeenMessaged = 0; + +//============================ +// AppendData +// adds a packet of data directly to file +//============================ +void AppendDataToFile(NSData* data) +{ + NSUInteger length = [data length]; + + dataAmount = (unsigned int)length; + dataTotalAmount += dataAmount; + totalDownloaded = dataTotalAmount; //update the download screen with the total downloaded + + //get documents directory + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + //create/open file for saving + NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/downloadedfile.tgz"]; + NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath]; + + if (!file) //file does not exist... create and append file + { + NSLog(@"open file failed\ncreating file with path: %@\n", fileatpath); + [[NSFileManager defaultManager] createFileAtPath:fileatpath + contents:data + attributes:nil]; + return; + } + + //seek to end of file and append data + [file seekToEndOfFile]; + [file writeData:data]; + [file closeFile]; +} + + + +//=========================== +// DecompressData +// Calls into untgz.c to start data inflation +// this function should not be getting called +//============================ +void DecompressData() +{ + Com_Printf("Starting DecompressData"); + + char path[1024]; + my_snprintf(path, sizeof(path), "%s/downloadedfile.tgz", iphoneDocDirectory); +} + +//================================ +// IsSpearPurchased +// returns 1 if Spear was purchased +//================================ +int IsSpearPurchased() +{ + //get documents directory + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + //create/open file for saving + NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/SpearPurchased.log"]; + NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath]; + + if (file) + return 1; + + return 0; +} + +//================================ +// IsSpearInstalled +// returns 1 if Spear is installed +//================================ +int IsSpearInstalled() +{ + //get documents directory + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + //create/open file for saving + NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/SpearInstalled.log"]; + NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath]; + + if (file) + return 1; + + return 0; +} + +//================================ +// WriteDownloadLog +// records that we've finished installing SOD +// but haven't completed the purchase +//================================ +void WriteInstallLog() +{ + char *buffer = "useless data"; + NSData *data = [[NSData alloc] initWithBytes: (void *)buffer length: strlen(buffer)]; + + //get documents directory + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + //create/open file for saving + NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/SpearInstalled.log"]; + NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath]; + + if (!file) //file does not exist... create and append file + { + NSLog(@"open file failed\ncreating file with path: %@\n", fileatpath); + [[NSFileManager defaultManager] createFileAtPath:fileatpath + contents:data + attributes:nil]; + return; + } + +} + +//================================ +// FinalizeDownload +// Installs the needed files for SOD and +// removes any unwanted data +//================================ +extern void iphoneWriteConfig(); +void FinalizeDownload() +{ + // get the documents directory + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *fileName = [documentsDirectory stringByAppendingString:@"/downloadedfile.tgz"]; + + //inflate the data and store in its appropriate directory + DecompressData(); + + //TODO: After inflating data... we should delete the downloadedfile.tgz + if( remove( [fileName UTF8String] ) != 0 ) + Com_Printf( "Error deleting downloadedfile.tgz\n" ); + else + Com_Printf( "downloadedfile.tgz successfully deleted\n" ); + + + iphoneKillMessageBox(); + + //write a file that lets wolf3d know that SOD is installed + WriteInstallLog(); + +#ifdef SPEARSTOREKIT + //start the storekit + BeginStoreKit(); +#endif +} diff --git a/wolf3d/code/iphone/iphone_downloadUserMap.m b/wolf3d/code/iphone/iphone_downloadUserMap.m new file mode 100644 index 0000000..1b1172b --- /dev/null +++ b/wolf3d/code/iphone/iphone_downloadUserMap.m @@ -0,0 +1,223 @@ +/* + * iphone_downloadUserMap.c + * wolf3d + * + * Created by Greg Hodges on 7/20/09. + * Copyright 2009 id software. All rights reserved. + * + */ +/* + + Copyright (C) 2009 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#import "../wolfiphone.h" +#import "wolf3dAppDelegate.h" +#import "iphone_alerts.h" + +#include +#include + +extern void Com_Printf(const char* fmt, ... ); +extern void my_snprintf( char *dest, size_t size, const char *format, ... ); + +extern char iphoneDocDirectory[1024]; +extern menuState_t menuState; + + +int inf(FILE *source, FILE *dest); +void zerr(int ret); + + +char mapName[1024];// = "/"; + +//this is used for determining if we have the correctly sized data +const unsigned int DownloadUserFileSize = 4096; //max size of maps? + + +//----------------------------- +// DownloadURLConnection +// This connects to a server and downloads the file located there +//----------------------------- +void DownloadURLConnection( char *url ) +{ + Com_Printf( "ConnectURL char *: %s\n", url ); + + int length = strlen(url); + if (length <= 4) + { + iphoneMessageBox("error", "url is not a valid map name. Maps must end in \".map\""); + return; + } + + length = strlen(url); + //acquire file name of map + int pos = length; + while (pos > 0) + { + --pos; + if (url[pos] == '/') + break; + } + ++pos; + strcpy(mapName, url + pos); + + //------------------------------------------------- + //check if this file already exists... if so, delete the old one + //get documents directory + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + //get maps directory + NSString *mapsDirectory = [documentsDirectory stringByAppendingString:@"/usermaps/"]; + + DIR *dp = opendir ([mapsDirectory UTF8String]); + if (dp != NULL) + { + struct dirent *ep; + while (ep = readdir (dp)) + { + //if you find a .DS_Store file... ignore it! + if ( strcmp(ep->d_name, ".DS_Store") == 0 ) + continue; + if ( strcmp(ep->d_name, ".") == 0 ) + continue; + if ( strcmp(ep->d_name, "..") == 0 ) + continue; + + if (strcmp(ep->d_name, mapName) == 0) + { + printf("found a file with name: %s\n", mapName); + printf("overwiting file\n"); + //TODO: delete this file + char buffer[2048]; + sprintf(buffer, "%s%s", [mapsDirectory UTF8String], mapName); + printf("removing at: %s\n", buffer); + remove(buffer); + } + } + } + //------------------------------------------------- + + + //convert url to nsstring + NSString *nssURL = [NSString stringWithUTF8String: url]; + + // create the request + NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:nssURL] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:60.0]; + + // create the connection with the request + // and start loading the data + NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest + delegate:(wolf3dAppDelegate *)[UIApplication sharedApplication].delegate]; + + if (!theConnection) + { + // inform the user that the download could not be made + Com_Printf("Connection failed... no download plausible\n"); + + //inform user + iphoneMessageBox("Connection Failed", "Can not download. Check your internet connection, file url and try again later."); + + //return to main menu + menuState = IPM_MAIN; + } + + menuState = IPM_DOWNLOADPROGRESS; +} + +unsigned int userDataAmount = 0; +unsigned int userDataTotalAmount = 0; +extern unsigned int totalDownloaded; + +//============================ +// AppendData +// adds a packet of data directly to file +//============================ +void AppendUserDataToFile(NSData* data) +{ + NSUInteger length = [data length]; + + userDataAmount = (unsigned int)length; + userDataTotalAmount += userDataAmount; + totalDownloaded = userDataTotalAmount; //update the download screen with the total downloaded + + //get documents directory + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + //get maps directory + NSString *mapsDirectory = [documentsDirectory stringByAppendingString:@"/usermaps/"]; + + //check if maps directory exists, if not create maps directory + mkdir([mapsDirectory UTF8String], 0755); + + //create/open file for saving + NSString *fileatpath = [mapsDirectory stringByAppendingString:[NSString stringWithUTF8String:mapName]]; + NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath]; + + if (!file) //file does not exist... create and append file + { + NSLog(@"open file failed\ncreating file with path: %@\n", fileatpath); + [[NSFileManager defaultManager] createFileAtPath:fileatpath + contents:data + attributes:nil]; + return; + } + + //seek to end of file and append data + [file seekToEndOfFile]; + [file writeData:data]; + [file closeFile]; +} + +//================================ +// FinalizeUserDownload +//================================ +extern int Level_VerifyMap( const char *levelname ); +extern int iphoneGetUserMapLevelByName(const char *mapName); +void FinalizeUserDownload() +{ + char buffer[1024]; + sprintf(buffer, "usermaps/%s", mapName); + + //we need to verify that this is a true .map file + if (Level_VerifyMap(buffer) == 0) + { + //it wasn't a valid map. Inform user and delete + iphoneMessageBox("invalid map", "downloaded file is an invalid map"); + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + char buffer2[2048]; + sprintf(buffer2, "%s/usermaps/%s", [documentsDirectory UTF8String], mapName); + remove(buffer2); + menuState = IPM_MAIN; + return; + } + + //start this map immediately! + menuState = IPM_EPISODE; + iphonePreloadBeforePlay(); + int level = iphoneGetUserMapLevelByName(mapName); + iphoneStartUserMap(10, level, currentMap.skill, mapName); +} diff --git a/wolf3d/code/iphone/iphone_loop.c b/wolf3d/code/iphone/iphone_loop.c index fd75703..2667547 100644 --- a/wolf3d/code/iphone/iphone_loop.c +++ b/wolf3d/code/iphone/iphone_loop.c @@ -120,8 +120,9 @@ brown plant cp 136.5551 ~/dev/iphone/wolf3d/base/sprites/013.5551 */ - +#include //gsh #include "../wolfiphone.h" +#include "arialGlyphRects.h" //gsh... cass made a nice fontimage helper. We might as well use it. currentMap_t currentMap; @@ -131,12 +132,16 @@ int iphoneFrameNum; int intermissionTriggerFrame; int slowAIFrame; +//gsh +int returnButtonFrameNum = 0; + // console mode int consoleActive; // the native iPhone code should set the following each frame: int numTouches; int touches[5][2]; // [0] = x, [1] = y in landscape mode, raster order with y = 0 at top +int isTouchMoving = 0; //gsh float tilt; // -1.0 to 1.0 float tiltPitch; @@ -150,6 +155,9 @@ int prevTouches[5][2]; texture_t *numberPics[10]; +//gsh +texture_t *arialFontTexture; + char *mugshotnames[ NUM_MUGSHOTS ] = { "iphone/FACE1APIC.tga", @@ -181,7 +189,11 @@ char *mugshotnames[ NUM_MUGSHOTS ] = "iphone/FACE7CPIC.tga", "iphone/FACE8APIC.tga", -"iphone/GOTGATLINGPIC.tga" +"iphone/GOTGATLINGPIC.tga", + +"iphone/GODMODEFACE0PIC.tga", +"iphone/GODMODEFACE1PIC.tga", +"iphone/GODMODEFACE2PIC.tga", }; int damageflash; @@ -308,6 +320,439 @@ int iphoneCenterText( int x, int y, const char *str ) { return l * step; } +//gsh +void iphoneCenterTextWithColor(int x, int y, const char *str, colour4_t color ) { + + pfglColor4f(color[0], color[1], color[2], color[3]); + + iphoneCenterText(x, y, str); + + pfglColor4f(1, 1, 1, 1); +} +/* + ================== + iphoneDrawArialText + left justified arial text + gsh + Returns the width in pixels + ================== + */ +int iphoneDrawArialText( int x, int y, float scale, const char *str ) { + /* + int l = strlen( str ); + int i; + font_t *myfont = myfonts[0]; + // int scale; + int step = 10; + + // scale = 16; + int left_margin = x; + */ + texture_t *gl; + + gl = TM_FindTexture( "iphone/arialImageLAL_white-alpha.tga", TT_Pic ); + if( ! gl ) { + Com_Printf( "Can't find pic: %s\n", "iphone/arialImageLAL_white-alpha.tga" ); + return 0; + } + + R_Bind( gl->texnum ); + + +// float fx = x; +// float fy = y; + +// int scale = 1;//16; +// float scale = 0.9f; + + pfglBegin( GL_QUADS ); + + while ( *str ) { + int i = *str; + if ( i >= ' ' && i < 128 ) { + GlyphRect *glyph = &glyphRects[i-32]; + + // the glyphRects don't include the shadow outline + float x0 = ( glyph->x0 - 2 ) / 256.0; + float y0 = ( glyph->y0 - 2 ) / 256.0; + float x1 = ( glyph->x1 + 3 ) / 256.0; + float y1 = ( glyph->y1 + 3 ) / 256.0; + + + float width = ( x1 - x0 ) * 256 * scale; + float height = ( y1 - y0 ) * 256 * scale; + +// float xoff = ( glyph->xoff - 1 ) * scale; + float yoff = ( glyph->yoff - 1 ) * scale; + + if (i == 'l' || i == 'I' || i == 'h' || i == 'i') + yoff += 1; + + pfglTexCoord2f( x0, y0 ); +// pfglVertex2f( fx + xoff, fy + yoff ); + pfglVertex2i( x, y + yoff); + + pfglTexCoord2f( x1, y0 ); +// pfglVertex2f( fx + xoff + width, fy + yoff ); + pfglVertex2i( x+width, y + yoff); + + pfglTexCoord2f( x1, y1); +// pfglVertex2f( fx + xoff + width, fy + yoff + height ); + pfglVertex2i( x+width, y+height + yoff ); + + pfglTexCoord2f( x0, y1); +// pfglVertex2f( fx + xoff, fy + yoff + height ); + pfglVertex2i( x, y+height + yoff); + + // with our default texture, the difference is negligable +// fx += glyph->xadvance * scale; + x += glyph->xadvance * scale; + // fx += ceil(glyph->xadvance); // with the outline, ceil is probably the right thing + } + str++; + } + + pfglEnd(); + + return x; +} +/* + ================== + iphoneCenterArialText + center justified arial text + gsh + Returns the width in pixels + ================== + */ +int iphoneCenterArialText( int x, int y, float scale, const char *str ) +{ + const char *strcopy = str; + float width = 0; + while ( *str ) + { + int i = *str; + if ( i >= ' ' && i < 128 ) { + + GlyphRect *glyph = &glyphRects[i-32]; + width += glyph->xadvance * scale; + } + ++str; + } + + return iphoneDrawArialText( x - width/2, y, scale, strcopy ); +} +/* + ================== + iphoneDrawArialTextInBox + center justified arial text + gsh + Returns the width in pixels + ================== + */ +int iphoneDrawArialTextInBox( rect_t paragraph, int lineLength, const char *str, rect_t boxRect ) { + int l = strlen( str ); + int i; + + if (paragraph.x > boxRect.x + boxRect.width) + return 0; + if (paragraph.x + lineLength < boxRect.x) + return 0; + + int x = paragraph.x; + int y = paragraph.y; +// Com_Printf("y value: %i\n", y); +// int width = paragraph.width; //font width +// int height = paragraph.height; //font height + + const int left_margin = x+5; + int step = 10; + + texture_t *gl; + + gl = TM_FindTexture( "iphone/arialImageLAL_white-alpha.tga", TT_Pic ); + if( ! gl ) { + Com_Printf( "Can't find pic: %s\n", "iphone/arialImageLAL_white-alpha.tga" ); + return 0; + } + + R_Bind( gl->texnum ); + pfglBegin( GL_QUADS ); + + int lengthOfNextWord = 0; + float scale = 0.65f;//0.9f; + + for ( i = 0 ; i < l ; i++/*, x += step*/ ) { + int m = str[i]; + GlyphRect *glyph = &glyphRects[m-32]; + + float x0 = ( glyph->x0 - 2 ) / 256.0; + float y0 = ( glyph->y0 - 2 ) / 256.0; + float x1 = ( glyph->x1 + 3 ) / 256.0; + float y1 = ( glyph->y1 + 3 ) / 256.0; + + float width = ( x1 - x0 ) * 256 * scale; + float height = ( y1 - y0 ) * 256 * scale; + + // float xoff = ( glyph->xoff - 1 ) * scale; + float yoff = ( glyph->yoff - 1 ) * scale; + + + //int row, col; + //float frow, fcol; + int num = str[i]; + + //check when to new-line + if ( num == ' ' ) { + float w = 0; + int n = i + 1; + while ( str[n] != ' ' && str[n] != '\0' && str[n] != '\n') { + //++n; + int m = str[n]; + GlyphRect *glyph2 = &glyphRects[m-32]; + w += glyph2->xadvance * scale; + ++n; + } + lengthOfNextWord = n - i - 1; +// Com_Printf("length of word: %i\n", n - i - 1); +// Com_Printf("length of word pixels: %f\n",w); + + if ( w + x > lineLength + left_margin ) { + y += 30*scale; + x = left_margin; + } + else + x += 10*scale; + //whil + //x += 10*scale; + continue; + } + if (num == '\n') { + y += 30*scale; + x = left_margin; + continue; + }/* + if (x + glyph->xadvance * scale > left_margin + lineLength) { + y += 30*scale; + x = left_margin;// + width; + }*/ + + //check rendering boundaries + if (x < boxRect.x+10) { + x += glyph->xadvance * scale + 1; + continue; + } + if (x + glyph->xadvance * scale > boxRect.x + boxRect.width) { + x += glyph->xadvance * scale + 1; + continue; + } + + if (y > boxRect.y + boxRect.height) + break; + + pfglTexCoord2f( x0, y0 ); + pfglVertex2i( x, y + yoff); + + pfglTexCoord2f( x1, y0 ); + pfglVertex2i( x+width, y + yoff); + + pfglTexCoord2f( x1, y1); + pfglVertex2i( x+width, y+height + yoff ); + + pfglTexCoord2f( x0, y1); + pfglVertex2i( x, y+height + yoff); + + x += glyph->xadvance * scale + 1; + + } + + pfglEnd(); + + return l * step; +} + + + +int iphoneDrawText( int x, int y, int width, int height, const char *str ) { + int l = strlen( str ); + int i; + font_t *myfont = myfonts[0]; +// int scale; + int step = 10; + +// scale = 16; + int left_margin = x; + + R_Bind( myfont->texfont->texnum ); + //R_Bind(arialFontTexture->texnum ); + pfglBegin( GL_QUADS ); + + for ( i = 0 ; i < l ; i++, x += step ) { + int row, col; + float frow, fcol; + int num = str[i]; + + if ( num == ' ' ) { + continue; + } + if (num == '\n') { + y += height; + x = left_margin; + } + + row = (num >> 4) - 2; + col = num & 15; + + frow = row * myfont->hFrac; + fcol = col * myfont->wFrac; + + pfglTexCoord2f( fcol, frow ); + pfglVertex2i( x, y ); + + pfglTexCoord2f( fcol+myfont->wFrac, frow ); + pfglVertex2i( x+width, y ); + + pfglTexCoord2f( fcol+myfont->wFrac, frow+myfont->hFrac ); + pfglVertex2i( x+width, y+height ); + + pfglTexCoord2f( fcol, frow+myfont->hFrac ); + pfglVertex2i( x, y+height ); + } + + pfglEnd(); + + return l * step; +} + +/* + ================== + iphoneDrawTextWithColor + gsh + ================== + */ +void iphoneDrawTextWithColor( rect_t rect, const char *str, float colors[4] ) { + + pfglColor4f(colors[0], colors[1], colors[2], colors[3]); + iphoneDrawText(rect.x, rect.y, rect.width, rect.height, str); + pfglColor4f(1, 1, 1, 1); +} + +/* + ================== + iphoneDrawMapName + gsh + ================== + */ +void iphoneDrawMapName( rect_t rect, const char *str ) { + + rect.y += 25; + rect.x += 110;//80; + /* + float colors[4] = { 0, 0, 0, 1 }; + iphoneDrawTextWithColor(RectMake(rect.x+1, rect.y+1, rect.width, rect.height), str, colors); + iphoneDrawTextWithColor(RectMake(rect.x+2, rect.y+2, rect.width, rect.height), str, colors); + + colors[0] = 225.0f/255; + colors[1] = 166.0f/255; + iphoneDrawTextWithColor(rect, str, colors); + */ + + pfglColor4f(0, 0, 0, 1); + iphoneDrawArialText(rect.x + 1, rect.y + 1, 0.9f, str); + iphoneDrawArialText(rect.x + 2, rect.y + 2, 0.9f, str); + pfglColor4f(225.0f/255, 166.0f/255, 0, 1); + pfglColor4f(225.0f/255, 242.0f/255, 0, 1); + iphoneDrawArialText(rect.x, rect.y, 0.9f, str); + pfglColor4f(1, 1, 1, 1); +} + +/* + ================== + iphoneDrawTextInBox + gsh + Returns the width in pixels + ================== + */ +int iphoneDrawTextInBox( rect_t paragraph, int lineLength, const char *str, rect_t boxRect ) { + int l = strlen( str ); + int i; + font_t *myfont = myfonts[0]; + + int x = paragraph.x; + int y = paragraph.y; + int width = paragraph.width; //font width + int height = paragraph.height; //font height + + int left_margin = x; + int step = 10; + + R_Bind( myfont->texfont->texnum ); + pfglBegin( GL_QUADS ); + + int lengthOfNextWord = 0; + + for ( i = 0 ; i < l ; i++, x += step ) { + int row, col; + float frow, fcol; + int num = str[i]; + + //check when to new-line + if ( num == ' ' ) { + int n = i+1; + while (str[n] != ' ' && str[n] != '\0' && str[n] != '\n') { + ++n; + } + lengthOfNextWord = n - i;// - 1; + if (x + lengthOfNextWord*step > left_margin + lineLength) { + y += height; + x = left_margin; + } + continue; + } + if (num == '\n') { + y += height; + x = left_margin; + continue; + } + if (x + width > left_margin + lineLength) { + y += height; + x = left_margin + width; + } + + //check rendering boundaries + if (x < boxRect.x) + continue; + if (x + width > boxRect.x + boxRect.width) + continue; + if (y < boxRect.y) + continue; + if (y + height > boxRect.y + boxRect.height) + continue; + + row = (num >> 4) - 2; + col = num & 15; + + frow = row * myfont->hFrac; + fcol = col * myfont->wFrac; + + pfglTexCoord2f( fcol, frow ); + pfglVertex2i( x, y ); + + pfglTexCoord2f( fcol+myfont->wFrac, frow ); + pfglVertex2i( x+width, y ); + + pfglTexCoord2f( fcol+myfont->wFrac, frow+myfont->hFrac ); + pfglVertex2i( x+width, y+height ); + + pfglTexCoord2f( fcol, frow+myfont->hFrac ); + pfglVertex2i( x, y+height ); + } + + pfglEnd(); + + return l * step; +} + + /* ================== @@ -358,7 +803,7 @@ int TouchReleased( int x, int y, int w, int h ) { } if ( !downPrev ) { - if ( downNow ) { + if ( downNow && !isTouchMoving ) { Sound_StartLocalSound( "iphone/bdown_01.wav" ); } // wasn't down the previous frame @@ -370,14 +815,16 @@ int TouchReleased( int x, int y, int w, int h ) { return 0; } - if ( numTouches == numPrevTouches ) { + if ( numTouches == numPrevTouches && !isTouchMoving ) { // finger dragged off Sound_StartLocalSound( "iphone/baborted_01.wav" ); return 0; } - // released - Sound_StartLocalSound( "iphone/baction_01.wav" ); + if ( !isTouchMoving ) { //gsh, added the if !isTouchMoving check + // released + Sound_StartLocalSound( "iphone/baction_01.wav" ); + } return 1; } @@ -652,6 +1099,28 @@ PRIVATE void CreateIphoneUserCmd() if ( tiltFire->value > 0 && tiltPitch < tiltFire->value ) { cmd->buttons |= BUTTON_ATTACK; } + +#ifdef VOLUMHACK + //gsh... attempting a left/right click attack + if ( volumeFireUp->value ) { + + if ((int)volumeFireUpSetting->value) + cmd->buttons |= BUTTON_ATTACK; + else + cmd->buttons |= BUTTON_ALTERNATE_ATTACK; + + Cvar_Set("volumeFireUp", "0"); + } + else if ( volumeFireDown->value ) { + + if ((int)volumeFireDownSetting->value) + cmd->buttons |= BUTTON_ATTACK; + else + cmd->buttons |= BUTTON_ALTERNATE_ATTACK; + + Cvar_Set("volumeFireDown", "0"); + } +#endif // tapping the weapon issues the nextWeapon impulse if ( TouchReleased( 240 - 40, 320 - 80 - 64, 80, 64 ) ) { @@ -680,11 +1149,14 @@ iphoneHighlightPicWhenTouched Draw transparent except when touched ================= */ +//gsh TODO: change hud alphas +//TODO: make this cvar setable and adjustable in settings menu +//float alphaValueForHudControls = 1;//0.5f; void iphoneHighlightPicNumWhenTouched( int x, int y, int w, int h, int glTexNum ) { if ( TouchDown( x, y, w, h ) ) { pfglColor4f(1,1,1,1); } else { - pfglColor4f(1,1,1,0.5); + pfglColor4f(1,1,1,hudAlpha->value);//0.5); } iphoneDrawPicNum( x, y, w, h, glTexNum ); pfglColor4f(1,1,1,1); @@ -752,6 +1224,7 @@ void iphoneDrawNumber( int x, int y, int number, int charWidth, int charHeight ) for( i = 0 ; i < length ; i++ ) { int digit = string[i] - '0'; tex = numberPics[digit]; + R_Bind( tex->texnum ); pfglBegin( GL_QUADS ); @@ -828,6 +1301,10 @@ void iphoneDrawFace() { h = 0; } pic = mugshotnames[ 3*((100-h)/16)+Player.faceframe ]; + + //gsh + if ((Player.flags & FL_GODMODE)) + pic = mugshotnames[ 23+Player.faceframe ]; } } else @@ -901,11 +1378,79 @@ void iphoneDrawNotifyText() { } } + --notifyFrameNum; //gsh + +// pfglColor4f( 1, 1, 1, f ); + //iphoneCenterText( 240, 5, notifyText ); +// iphoneDrawArialText( 200, 20, 0.7f, notifyText ); //gsh + pfglColor4f( 0, 0, 0, f ); + iphoneCenterArialText( 240+1, 20+1, 0.8f, notifyText); //gsh + iphoneCenterArialText( 240+2, 20+2, 0.8f, notifyText); //gsh + iphoneCenterArialText( 240+3, 20+3, 0.8f, notifyText); //gsh pfglColor4f( 1, 1, 1, f ); - iphoneCenterText( 240, 5, notifyText ); + iphoneCenterArialText( 240, 20, 0.8f, notifyText); //gsh pfglColor4f( 1, 1, 1, 1 ); } +/* + ================== + iphoneDrawReturnButton + + Displays a button that allows the player to return to the map screen. + But it only displays for a few seconds. + ================== + */ +void iphoneDrawReturnButton() { + + if (returnButtonFrameNum <= 0) + return; + + // display for three seconds, then fade over 0.3 + float f = iphoneFrameNum - returnButtonFrameNum - 80; + if ( f < 0 ) { + f = 1.0; + } else { + f = 1.0 - f * 0.1f; + if ( f < 0 ) { + returnButtonFrameNum = 0; + return; + } + } + + //always be semi-transparent + if ( f > 0.5f ) + f = 0.5f; + + pfglColor4f( 1, 1, 1, f ); + if (iphoneDrawPicWithTouch( 240-32, 32, 64, 48, "iphone/button_back.tga")) {//int x, int y, int w, int h, const char *pic )) { + menuState = IPM_MAPS; + returnButtonFrameNum = 0; + + //if it's a spear map, it needs special attention + if (currentMap.episode > 5 && currentMap.episode < 10) + { + //get the level number + int levelNum = currentMap.episode*10 + currentMap.map; + + if (levelNum == 78 || (levelNum >= 60 && levelNum < 65)) { + episode->value = 6; + } + else if (levelNum == 79 || (levelNum >= 65 && levelNum < 70)) { + episode->value = 7; + } + else if (levelNum >= 70 && levelNum < 76) { + episode->value = 8; + } + else if (levelNum == 76 || levelNum == 77 || levelNum == 80) { + episode->value = 9; + } + } + } + pfglColor4f( 1, 1, 1, 1 ); + + --returnButtonFrameNum; +} + void iphoneStartBonusFlash() { bonusFrameNum = iphoneFrameNum; } @@ -936,14 +1481,14 @@ void iphoneSetAttackDirection( int dir ) { attackDirTime[1] = iphoneFrameNum; } } - +//gsh... note to self: this is where the controls are drawn void iphoneDrawHudControl( hudPic_t *hud ) { if ( hud->hudFlags & HF_DISABLED ) { return; } iphoneHighlightPicNumWhenTouched( hud->x, hud->y, hud->width, hud->height, hud->glTexNum ); } - +//gsh... note to self: this is where menu/map buttons are drawn int iphoneDrawHudButton( hudPic_t *hud ) { if ( hud->hudFlags & HF_DISABLED ) { return 0; @@ -1007,7 +1552,7 @@ iphoneFrame ================== */ void iphoneFrame() { - unsigned char blendColor[4]; + unsigned char blendColor[4] = { 0, 0, 0, 0 }; iphoneFrameNum++; loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].enterFrame = Sys_Milliseconds(); @@ -1052,6 +1597,12 @@ void iphoneFrame() { //------------------ // normal gameplay //------------------ + + //this is a hack for "Floor 18, Part II: Death's Door" + //there's no gold key to leave the first room + //so we give it to the player here... gsh + if (currentMap.episode == 8 && !(Player.items & ITEM_KEY_1)) + Player.items |= ITEM_KEY_1; if( Player.playstate != ex_dead ) { @@ -1125,16 +1676,19 @@ void iphoneFrame() { blendColor[0] = 255; blendColor[1] = 0; blendColor[2] = 0; - blendColor[3] = deathFadeIntensity; + blendColor[3] = deathFadeIntensity; deathFadeIntensity += 2; if( deathFadeIntensity >= 240 ) { deathFadeIntensity = 0; PL_NewGame( &Player ); - iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill ); + if (currentMap.episode >=9) //gsh + iphoneStartUserMap( currentMap.episode, currentMap.map, currentMap.skill, NULL ); + else + iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill ); } } else { iphoneDrawWeapon(); - if( damageflash ) { + if( damageflash ) { blendColor[0] = 255; blendColor[1] = 0; blendColor[2] = 0; @@ -1160,6 +1714,9 @@ void iphoneFrame() { } iphoneDrawNotifyText(); + + //gsh + iphoneDrawReturnButton(); iphoneDrawMapView(); @@ -1180,7 +1737,7 @@ void iphoneFrame() { if ( iphoneDrawHudButton( &huds.map ) ) { iphoneOpenAutomap(); } - + Client_Screen_DrawConsole(); ShowTilt(); // debug tool @@ -1189,4 +1746,20 @@ void iphoneFrame() { iphoneSavePrevTouches(); SysIPhoneSwapBuffers(); // do the swapbuffers + } + +void iphoneDrawLoading() +{ + Com_Printf("Draw Loading!\n"); +// unsigned char blendColor[4]; + + iphoneSet2D(); + + //draw stuff here + iphoneDrawText(100, 100, 16, 16, "Drawing Loading!");//, <#int y#>, <#int width#>, <#int height#>, <#const char * str#>) + + SysIPhoneSwapBuffers(); // do the swapbuffers +} + + diff --git a/wolf3d/code/iphone/iphone_main.c b/wolf3d/code/iphone/iphone_main.c index e4e7461..b9c6991 100644 --- a/wolf3d/code/iphone/iphone_main.c +++ b/wolf3d/code/iphone/iphone_main.c @@ -29,7 +29,6 @@ #include "../wolfiphone.h" - cvar_t *controlScheme; cvar_t *sensitivity; cvar_t *stickTurnBase; @@ -42,6 +41,13 @@ cvar_t *tiltMove; cvar_t *tiltDeadBand; cvar_t *tiltAverages; cvar_t *tiltFire; +#ifdef VOLUMEHACK +cvar_t *volumeFireUp; //gsh +cvar_t *volumeFireDown; //gsh +cvar_t *volumeFireUpSetting; //gsh +cvar_t *volumeFireDownSetting; //gsh +#endif +cvar_t *hudAlpha; //gsh cvar_t *music; cvar_t *showTilt; cvar_t *showTime; @@ -56,6 +62,10 @@ cvar_t *autoFire; W32 sys_frame_time; +#ifdef STOREKIT +extern void CheckForStorekitExistence(); //gsh +#endif + void Sys_Error( const char *format, ... ) { va_list argptr; @@ -101,7 +111,12 @@ void Reset_f() { void iphoneStartup() { char *s; int start = Sys_Milliseconds(); - + +#ifdef STOREKIT + //check for storekit framework and set appropriate flags... gsh + CheckForStorekitExistence(); +#endif + // temporary const char *systemVersion = SysIPhoneGetOSVersion(); printf( "systemVersion = %s\n", systemVersion ); @@ -119,6 +134,7 @@ void iphoneStartup() { Con_Init(); FS_InitFilesystem(); + // We need to add the early commands twice, because // a basedir or cddir needs to be set before execing // config files, but we want other parms to override @@ -137,9 +153,7 @@ void iphoneStartup() { Cvar_Get( "version", s, CVAR_SERVERINFO | CVAR_NOSET ); Con_Init(); - Sound_Init(); - Game_Init(); // game and player init Cbuf_AddText( "exec config.cfg\n" ); @@ -165,6 +179,13 @@ void iphoneStartup() { tiltTurn = Cvar_Get( "tiltTurn", "0", CVAR_ARCHIVE ); tiltMove = Cvar_Get( "tiltMove", "0", CVAR_ARCHIVE ); tiltFire = Cvar_Get( "tiltFire", "0", CVAR_ARCHIVE ); +#ifdef VOLUMEHACK + volumeFireUp = Cvar_Get( "volumeFireUp", "0", 0 ); //gsh + volumeFireDown = Cvar_Get( "volumeFireDown", "0", 0 ); //gsh + volumeFireUpSetting = Cvar_Get( "volumeFireUpSetting", "1", CVAR_ARCHIVE ); //gsh // 1 = primary + volumeFireDownSetting = Cvar_Get( "volumeFireDownSetting", "0", CVAR_ARCHIVE ); //gsh // 0 = secondary +#endif + hudAlpha = Cvar_Get("hudAlpha", "1.0", CVAR_ARCHIVE); //gsh music = Cvar_Get( "music", "1", CVAR_ARCHIVE ); tiltDeadBand = Cvar_Get( "tiltDeadBand", "0.08", CVAR_ARCHIVE ); tiltAverages = Cvar_Get( "tiltAverages", "3", CVAR_ARCHIVE ); @@ -181,7 +202,8 @@ void iphoneStartup() { // make sure volume changes and incoming calls draw the right orientation SysIPhoneSetUIKitOrientation( revLand->value ); - + + /* //if we don't preload the ogg files then we have faster start ups... gsh // preload all the ogg FM synth sounds Com_Printf( "before ogg preload: %i msec\n", Sys_Milliseconds() - start ); @@ -210,7 +232,7 @@ void iphoneStartup() { Sound_RegisterSound( "lsfx/078.wav" ); Sound_RegisterSound( "lsfx/080.wav" ); Sound_RegisterSound( "lsfx/085.wav" ); - Sound_RegisterSound( "lsfx/086.wav" ); + Sound_RegisterSound( "lsfx/086.wav" );*/ // these should get overwritten by LoadTheGame memset( ¤tMap, 0, sizeof( currentMap ) ); @@ -218,12 +240,13 @@ void iphoneStartup() { currentMap.episode = 0; HudSetForScheme( 0 ); + Com_Printf( "before LoadTheGame: %i msec\n", Sys_Milliseconds() - start ); - + if ( !LoadTheGame() ) { PL_NewGame( &Player ); iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill ); - } + } // always start at main menu @@ -236,7 +259,7 @@ void iphoneStartup() { =================== iphonePreloadBeforePlay - This couold all be done at startup, but moving a bit of the delay + This could all be done at startup, but moving a bit of the delay to after pressing the resume button works a little better. =================== */ diff --git a/wolf3d/code/iphone/iphone_mapselector.c b/wolf3d/code/iphone/iphone_mapselector.c new file mode 100644 index 0000000..17bd86d --- /dev/null +++ b/wolf3d/code/iphone/iphone_mapselector.c @@ -0,0 +1,478 @@ +/* + * iphone_mapselector.c + * wolf3d + * + * Created by Greg Hodges on 7/2/09. + * Copyright 2009 id software. All rights reserved. + * + */ +#include "../wolfiphone.h" +#include + +const char levelNames[][29] = { +"E1 level 1", +"E1 level 2", +"E1 level 3", +#ifndef LITE +"E1 level 4", +"E1 level 5", +"E1 level 6", +"E1 level 7", +"E1 level 8", +"E1 Boss ", +"E1 Secret ", +"E2 level 1", +"E2 level 2", +"E2 level 3", +"E2 level 4", +"E2 level 5", +"E2 level 6", +"E2 level 7", +"E2 level 8", +"E2 Boss ", +"E2 Secret ", +"E3 level 1", +"E3 level 2", +"E3 level 3", +"E3 level 4", +"E3 level 5", +"E3 level 6", +"E3 level 7", +"E3 level 8", +"E3 Boss ", +"E3 Secret ", +"E4 level 1", +"E4 level 2", +"E4 level 3", +"E4 level 4", +"E4 level 5", +"E4 level 6", +"E4 level 7", +"E4 level 8", +"E4 Boss ", +"E4 Secret ", +"E5 level 1", +"E5 level 2", +"E5 level 3", +"E5 level 4", +"E5 level 5", +"E5 level 6", +"E5 level 7", +"E5 level 8", +"E5 Boss ", +"E5 Secret ", +"E5 level 1", +"E6 level 2", +"E6 level 3", +"E6 level 4", +"E6 level 5", +"E6 level 6", +"E6 level 7", +"E6 level 8", +"E6 Boss ", +"E6 Secret ", +"Floor 1: Tunnels 1 ", +"Floor 2: Tunnels 2 ", +"Floor 3: Tunnels 3 ", +"Floor 4: Tunnels 4 ", +"Floor 5: Tunnels Boss ", +"Floor 6: Dungeons 1 ", +"Floor 7: Dungeons 2 ", +"Floor 8: Dungeons 3 ", +"Floor 9: Dungeons 4 ", +"Floor 10: Dungeons Boss ", +"Floor 11: Castle 1 ", +"Floor 12: Castle 2 ", +"Floor 13: Castle 3 ", +"Floor 14: Castle 4 ", +"Floor 15: Castle 5 ", +"Floor 16: Castle Boss ", +"Floor 17: Ramparts ", +"Floor 18: Death Knight ", +"Floor 19: Secret 1 ", +"Floor 20: Secret 2 ", +"Floor 21: Angel of Death", +#endif +}; + +int dragVelocity = 0; //velocity for the scrolling maps +int dragPosition = 32; //position for the scrolling maps + +extern int BackButton(); +#ifdef SPEARSTOREKIT +extern void GetSpearOfDestiny( int x, int y ); +#endif +extern int iphoneDrawPicWithTouchAndColor( int x, int y, int w, int h, const char *pic, colour4_t color ); +extern void iphoneStartUserMap( int episodeNum, int mapNum, int skillLevel, char *mapName ); + + +#ifdef LITE +extern void GetMoreLevels( int x, int y ); +#endif + +//========================================== +// iphoneUpdateDrags() +// Updates the touches for the scrolling maps +//========================================== +void iphoneUpdateDrags(int numMaps, int skillSides, int height, int spacing, int numUserMaps) +{ + //Update drag/touch info + int x = 64; + int w = 480 - skillSides - 64; + int y = 0; + int h = 320; + + if (TouchDown(x, y, w, h)) + { + if (!numPrevTouches) + prevTouches[0][1] = touches[0][1]; + else if (numTouches == 1) + dragVelocity = prevTouches[0][1] - touches[0][1]; + } + + //boundary check the drags + int num = numMaps+1+6; + if (g_version-> value == SPEAROFDESTINY) + num = numMaps + 7; + + num += numUserMaps + 1; + + if (dragPosition < 320 - (height+spacing)*(num) - 20) + dragPosition < 320 - (height+spacing)*(num) - 20; + else if (dragPosition > 40) + dragPosition = 40; + + if (dragPosition < 320 - (height+spacing)*(num)) + dragVelocity = -1; + else if (dragPosition > 32) + dragVelocity = 1; + + //update the drags + dragPosition -= dragVelocity; + + //retard the velocity + if (dragVelocity > 0) + --dragVelocity; + else if (dragVelocity < 0) + ++dragVelocity; + +} + +//========================================== +// iphoneDrawRewards() +// Draws the rewards on each level +//========================================== +int forceDrawRewards = 0; +void iphoneDrawRewards(int m, int s, int x, int y) +{ + int ch = currentMap.mapFlags[s][m]; + // bit1 = attempted + // bit2 = completed + // bit3 = 100% kills + // bit4 = 100% secrets + // bit5 = 100% treasure + + //ch = 4+8+16+32; //used for testing proper placement + + x += 80; + int startX = x; + + //x += 66;//375; + y -= 27;//10; + + int width = 40;//22; + int height = 40;//22; + int spacing = -12; + // draw award shadows + iphoneDrawPic( x,y+23, width, height, "iphone/kills_shadow.tga" ); x += width + spacing; + iphoneDrawPic( x,y+23, width, height, "iphone/secrets_shadow.tga" ); x += width + spacing; + iphoneDrawPic( x,y+23, width, height, "iphone/treasure_shadow.tga" ); x += width + spacing; + iphoneDrawPic( x,y+23, width, height, "iphone/partime_shadow.tga" ); //x += width + 5; + + x = startX; + + // draw awards + if ( (ch & MF_KILLS) || forceDrawRewards) { + iphoneDrawPic( x,y+23, width, height, "iphone/kills.tga" ); + } + x += width + spacing; + if ( (ch & MF_SECRETS) || forceDrawRewards) { + iphoneDrawPic( x,y+23, width, height, "iphone/secrets.tga" ); + } + x += width + spacing; + if ( (ch & MF_TREASURE) || forceDrawRewards) { + iphoneDrawPic( x,y+23, width, height, "iphone/treasure.tga" ); + } + x += width + spacing; + if ( (ch & MF_TIME) || forceDrawRewards) { + iphoneDrawPic( x,y+23, width, height, "iphone/partime.tga" ); + } +} + +//========================================== +// iphoneDrawUserMaps() +// This function scans through the custom maps +// and displays the ones on screen +//========================================== +int iphoneDrawUserMaps(int Yoffset, int height, int spacing, int skillValue) +{ + int numMaps = 0; + + DIR *dp; + struct dirent *ep; + char mapBuffer[1024]; + + int length = strlen(iphoneDocDirectory); + strcpy(mapBuffer, iphoneDocDirectory); + strcpy(mapBuffer + length, "/usermaps/"); + + dp = opendir (mapBuffer); + + if (dp != NULL) + { + int y = Yoffset; + if (g_version->value != SPEAROFDESTINY) //make space for the purchase SOD button + y += height + spacing + spacing; + + //draw the custom map spacing + y += height + spacing; + iphoneDrawPic( 0, y, 480-80, height, "iphone/button_epSOD.tga"); + + + while (ep = readdir (dp)) + { + ++numMaps; + if (numMaps < 3) //skip the '.' and '..' + continue; + + y += height + spacing; + Com_Printf("value y: %i\n", y); + + //TODO: draw the names! + if ( y >= -height && y < 320 ) + { + + //draw maps and touch + int alpha = 128; + //colour4_t colorSecret = { 80, 0, 0, alpha }; + colour4_t colorNoTry = { 0, 0, 0, alpha }; + + if ( iphoneDrawPicWithTouchAndColor( 0, y, 480-80, height, "iphone/menu_bar.tga", colorNoTry) && dragVelocity == 0 )//&& isSecretAvailable ) + { + //reset the player to new + PL_NewGame( &Player ); + + //set episode and map numbers and load map + int e = 9; //9 will be used to show a custom map + Cvar_SetValue( episode->name, e ); + iphonePreloadBeforePlay(); //This prevents crashes when loading SOD maps + iphoneStartUserMap( e, numMaps - 3, skillValue, ep->d_name ); + } + + iphoneDrawText( 100, y + 16, 16, 16, ep->d_name ); + //iphoneCenterText( 160, y + 16, ep->d_name ); + + //draw the rewards + iphoneDrawRewards(numMaps-2+90, skillValue, 0, y); + } + } + closedir (dp); + + --numMaps; + --numMaps; + } + + Com_Printf("numMaps: %i\n", numMaps); + + return numMaps; +} + +//========================================== +// iphoneSelectMapMenu() +// A doom classic style map selector +//========================================== +void iphoneSelectMapMenu() +{ + int s; //skill + char str[64]; + + // highlight the current skill selection + int skillValue = (int)skill->value; + if (skillValue < 0) + skillValue = 0; + if (skillValue > 3) + skillValue = 3; + + int skillSides = 80; + + int e = 0; //episode + + int m, map; //mission/map + int height = 48; + int spacing = 10; + int y = 0; + + char strMission[80]; + strMission[79] = '\0'; + +#ifdef LITE + int numMaps = 3;//5; +#else + int numMaps = 60; + if (g_version->value == SPEAROFDESTINY) + numMaps = 60 + 21; +#endif + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + + //check for BackButton touches + if ( BackButton() ) { + menuState = IPM_MAIN; + return; + } + + //we want to use the menu selector bar + my_snprintf( str, sizeof( str ), "iphone/menu_bar.tga" ); + + //iterate through the maps... drawing only the visible maps + for (m = 0; m < numMaps; m++) + { + + //Draws the spacing between each episode + e = m/10; + if (e < 6) + { + y = dragPosition + ((height + spacing) * e*11);// + ((height + spacing) * (e+1)); + if ( y >= -height && y < 320 ) + { + my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", e+1 ); + iphoneDrawPic( 0, y, 480-80, height, str); + } + + y = dragPosition + ((height + spacing) * m) + ((height + spacing) * (e+1)); + } + else + { + y = dragPosition + ((height + spacing) * 6*11); + if ( y >= -height && y < 320 ) + { + my_snprintf( str, sizeof( str ), "iphone/button_epSOD.tga"); + iphoneDrawPic( 0, y, 480-80, height, str); + } + y = dragPosition + ((height + spacing) * m) + ((height + spacing) * 7); + } + + //we want to use the menu selector bar + my_snprintf( str, sizeof( str ), "iphone/menu_bar.tga" ); + + //only draw the maps that are currently viewable + if ( y >= -height && y < 320 ) + { + e = m/10; + map = m%10; + + //color maps + int ch = currentMap.mapFlags[skillValue][m]; + + int alpha = 128; + colour4_t colorSecret = { 80, 0, 0, alpha }; + colour4_t colorNoTry = { 0, 0, 0, alpha }; + colour4_t colorTried = { 80, 80, 0, alpha }; + colour4_t colorCompleted = { 0, 80, 0, alpha }; + colour4_t colorBlink = { 80, 80, 80, alpha }; + + unsigned char *color = colorNoTry; + bool isSecretAvailable = true; + + if ( map == 9 && !( ch & MF_TRIED ) && e < 6) //if it's the 9th and not SOD + { + color = colorSecret; + isSecretAvailable = false; + } + else if ( (m == 79 || m == 78) && !(ch & MF_TRIED) ) //if it's the secret SOD levels + { + color = colorSecret; + isSecretAvailable = false; + } else if ( ch & MF_COMPLETED ) { + color = colorCompleted; + } else if ( ch & MF_TRIED ) { + color = colorTried; + } else { + color = colorNoTry; + } + + //blink the level you're currently on + if ( ( iphoneFrameNum & 8 ) && map == currentMap.map && e == currentMap.episode ) + color = colorBlink; + + //draw maps and touch + if ( iphoneDrawPicWithTouchAndColor( 0, y, 480-80, height, str, color) && dragVelocity == 0 && isSecretAvailable ) + { + //reset the player to new + PL_NewGame( &Player ); + + //set episode and map numbers and load map + Cvar_SetValue( episode->name, e ); + iphonePreloadBeforePlay(); //This prevents crashes when loading SOD maps + iphoneStartMap( e, map, skillValue ); + } + + //draw the rewards + iphoneDrawRewards(m, skillValue, 0, y); + + //draw the episode and map over the selection bar + my_snprintf( strMission, sizeof( strMission ), "%s", levelNames[m] ); + iphoneDrawText( 100, y + 16, 16, 16, strMission ); +// iphoneCenterText( 160, y + 16, strMission ); + } + } + + int numUserMaps = 0; + +#ifdef LITE + //buy more episodes button + GetMoreLevels( 0, dragPosition + (height + spacing) * (m+1) ); +#else +#if 0 + //buy more episodes button + if (g_version->value != SPEAROFDESTINY) + GetSpearOfDestiny( 0, dragPosition + (height + spacing) * (m+6) ); +#endif + //TODO: Draw user maps + numUserMaps = iphoneDrawUserMaps(y, height, spacing, skillValue); +#endif + + //Update the scrolling drags + iphoneUpdateDrags(numMaps, skillSides, height, spacing, numUserMaps); + + + //Draw/choose the skills on the right side of the screen + for ( s = 0 ; s < 4 ; s++ ) + { + my_snprintf( str, sizeof( str ), "iphone/button_skill%i.tga", s+1 ); + + if ( s != (int)skill->value ) { + pfglColor3f( 0.5, 0.5, 0.5 ); + } + if ( iphoneDrawPicWithTouch( 480 - skillSides, skillSides*s, skillSides, skillSides, str ) ) { + Cvar_SetValue( skill->name, s ); + skillValue = s; + break; + } + pfglColor3f( 1, 1, 1 ); + } + + + + //Draw a bar that covers empty space + iphoneDrawPic(0, 0, 480-80, 32, "iphone/menu_bar.tga"); + + //levels header + iphoneDrawPic(240-64, 0, 128, 32, "iphone/header_levels.tga"); + + BackButton(); //this is kinda cheap... + //we want the back button to render on top + //but we also want it to check for touches before the maps + //so we call this function twice + //(at the beginning for touches; the end for rendering) +} diff --git a/wolf3d/code/iphone/iphone_menus.c b/wolf3d/code/iphone/iphone_menus.c index daf99fa..b47f789 100644 --- a/wolf3d/code/iphone/iphone_menus.c +++ b/wolf3d/code/iphone/iphone_menus.c @@ -17,6 +17,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +//gsh +//#define NUM_TOUCHFRAME 10 #include "../wolfiphone.h" @@ -27,6 +29,83 @@ menuState_t menuState; colour4_t highlightColor = { 128, 128, 128, 255 }; colour4_t colorPressed = { 128, 128, 0, 255 }; +//------------- +// These are for the download progress menu +extern unsigned int dataAmount; //gsh... provides us information with the amount of data we've downloaded +unsigned int totalDownloaded = 0; +extern const unsigned int DownloadFileSize; +extern unsigned int userDataAmount; //gsh... provides us information with the amount of data we've downloaded +extern const unsigned int DownloadUserFileSize; +//-------------- +//gsh +int wasDLInstructionsCalledFromEpisodeMenu = 0; +int wasCalledFromDownloadInstructionsMenu = 0; +/* + ========================= + iphoneSetLevelNotifyText + gsh + ========================= + */ +void iphoneSetLevelNotifyText() +{ + char str[128]; + + if (currentMap.episode < 6) + sprintf( str, "Entering level E%iM%i", currentMap.episode+1, currentMap.map+1 ); + else if (currentMap.episode < 10) { + int currentLevel = currentMap.episode * 10 + currentMap.map; + switch (currentLevel) { + case 60: case 61: case 62: case 63: case 64: + sprintf( str, "Entering Tunnels %i", currentLevel-60+1); + break; + case 78: + sprintf( str, "Entering Tunnels Secret");//, 6); + break; + case 65: case 66: case 67: case 68: case 69: + sprintf( str, "Entering Dungeons %i", currentLevel-65+1); + break; + case 70: case 71: case 72: case 73: case 74: case 75: + sprintf( str, "Entering Castle %i", currentLevel - 70 + 1); + break; + case 79: + sprintf( str, "Entering Castle Secret");//, 6); + break; + case 76: + sprintf( str, "Entering Ramparts"); + break; + case 77: + sprintf( str, "Entering Death Knight"); + break; + case 80: + sprintf( str, "Entering Dungeon Dimension"); + break; + default: + sprintf( str, " "); + break; + } + } + else + sprintf( str, "Entering level custom %i", /*currentMap.episode+1,*/ currentMap.map+1 ); + + iphoneSetNotifyText( str ); +} + +/* + ================== + RectMake + gsh + ================== + */ +rect_t RectMake(int x, int y, int width, int height) +{ + rect_t rect; + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + return rect; +} + /* ================== iphoneDrawPicNum @@ -71,6 +150,72 @@ void iphoneDrawPic( int x, int y, int w, int h, const char *pic ) { pfglEnd(); } +//gsh +void iphoneDrawPicInBox( rect_t drawRect, const char *pic, rect_t boxRect ) +{ + texture_t *gl; + + gl = TM_FindTexture( pic, TT_Pic ); + if( ! gl ) { + Com_Printf( "Can't find pic: %s\n", pic ); + return; + } + + + int newX = drawRect.x; + int newY = drawRect.y; + int newW = drawRect.width; + int newH = drawRect.height; + + float u0 = 0; + float u1 = gl->maxS; + float v0 = 0; + float v1 = gl->maxT; + + + if (drawRect.x > boxRect.x + boxRect.width) + return; //we're not in box... //newX = boxX + boxW; + if (drawRect.x + drawRect.width < boxRect.x) + return; + if (drawRect.y > boxRect.y + boxRect.height) + return; + if (drawRect.y + drawRect.height < boxRect.y) + return; + + if (drawRect.x < boxRect.x) { + newX = boxRect.x; + u0 = gl->maxS * ((float)(boxRect.x - drawRect.x))/((float)drawRect.width); + newW = drawRect.width - (boxRect.x - drawRect.x); + } + if (drawRect.x + drawRect.width > boxRect.x + boxRect.width) { + newW = boxRect.x + boxRect.width - drawRect.x; + u1 = gl->maxS * ((float)(newW))/((float)drawRect.width); + } + if (drawRect.y < boxRect.y) { + newY = boxRect.y; + v0 = gl->maxT * ((float)(boxRect.y - drawRect.y))/((float)drawRect.height); + newH = drawRect.height - (boxRect.y - drawRect.y); + } + if (drawRect.y + drawRect.height > boxRect.y + boxRect.height) { + newH = boxRect.y + boxRect.height - drawRect.y; + v1 = gl->maxT * ((float)(newH))/((float)drawRect.height); + } + + + R_Bind( gl->texnum ); + pfglBegin( GL_QUADS ); + + //float u, v; + //u = ((float)newX)/((float)x); + //v = ((float)newY)/((float)y); + pfglTexCoord2f( u0, v0 ); pfglVertex2i( newX, newY ); + pfglTexCoord2f( u1, v0 ); pfglVertex2i( newX+newW, newY ); + pfglTexCoord2f( u1, v1 ); pfglVertex2i( newX+newW, newY+newH ); + pfglTexCoord2f( u0, v1 ); pfglVertex2i( newX, newY+newH ); + + pfglEnd(); +} + /* ================== iphoneDrawPicWithTouch @@ -93,6 +238,243 @@ int iphoneDrawPicWithTouch( int x, int y, int w, int h, const char *pic ) { return r; } +//gsh +int iphoneDrawPicWithTouchSpecified( rect_t drawRect, rect_t touchRect, const char *pic) {//int x, int y, int w, int h, int touchX, int touchY, int touchW, int touchH, const char *pic ) { + int r = TouchReleased( touchRect.x, touchRect.y, touchRect.width, touchRect.height ); + + if ( r ) { + // make sure it is full intensity if it is touch-released, even if + // it wasn't active previously + pfglColor3f( 1, 1, 1 ); + } + iphoneDrawPic( drawRect.x, drawRect.y, drawRect.width, drawRect.height, pic ); + if ( TouchDown( touchRect.x, touchRect.y, touchRect.width, touchRect.height ) ) { + colour4_t color = { 255, 255, 255, 64 }; + R_Draw_Blend( drawRect.x, drawRect.y, drawRect.width, drawRect.height, color ); + } + return r; +} +//gsh +int iphoneDrawPicInBoxWithTouchSpecified( rect_t drawRect, rect_t touchRect, const char *pic, rect_t boundingRect ) { + + //make sure touches are in drawing bounds + if (touchRect.x < boundingRect.x) { + touchRect.width -= boundingRect.x - touchRect.x; + touchRect.x = boundingRect.x; + } + if (touchRect.x + touchRect.width > boundingRect.x + boundingRect.width) + touchRect.width = boundingRect.x + boundingRect.width - touchRect.x; + if (touchRect.y < boundingRect.y) { + touchRect.height -= boundingRect.y - touchRect.y; + touchRect.y = boundingRect.y; + } + if (touchRect.y + touchRect.height > boundingRect.y + boundingRect.height) + touchRect.height = boundingRect.y + boundingRect.height - touchRect.y; + + int r = TouchReleased( touchRect.x, touchRect.y, touchRect.width, touchRect.height ); + + if ( r ) { + // make sure it is full intensity if it is touch-released, even if + // it wasn't active previously + pfglColor3f( 1, 1, 1 ); + } +// iphoneDrawPic( x, y, w, h, pic ); +// iphoneDrawPicInBox( x, y, w, h, pic, boxX, boxY, boxW, boxH ); + iphoneDrawPicInBox( drawRect, pic, boundingRect ); +// iphoneDrawPicInBox( int x, int y, int w, int h, const char *pic, int boxX, int boxY, int boxW, int boxH ) + if ( TouchDown( touchRect.x, touchRect.y, touchRect.width, touchRect.height ) ) { + colour4_t color = { 255, 255, 255, 64 }; + R_Draw_Blend( touchRect.x, touchRect.y, touchRect.width, touchRect.height, color ); + } + return r; +} + +//gsh +int iphoneDrawPicInBoxWithTouchAndVelocity( rect_t drawRect, rect_t touchRect, const char *pic, rect_t boundingRect, int dragVelocity ) { + + //make sure touches are in drawing bounds + if (touchRect.x < boundingRect.x) { + touchRect.width -= boundingRect.x - touchRect.x; + touchRect.x = boundingRect.x; + } + if (touchRect.x + touchRect.width > boundingRect.x + boundingRect.width) + touchRect.width = boundingRect.x + boundingRect.width - touchRect.x; + if (touchRect.y < boundingRect.y) { + touchRect.height -= boundingRect.y - touchRect.y; + touchRect.y = boundingRect.y; + } + if (touchRect.y + touchRect.height > boundingRect.y + boundingRect.height) + touchRect.height = boundingRect.y + boundingRect.height - touchRect.y; + + int r = TouchReleased( touchRect.x, touchRect.y, touchRect.width, touchRect.height ); + + //if the object is moving, then it shouldn't be selectable + if ( dragVelocity ) + r = 0; + + if ( r ) { + // make sure it is full intensity if it is touch-released, even if + // it wasn't active previously + pfglColor3f( 1, 1, 1 ); + } + // iphoneDrawPic( x, y, w, h, pic ); + // iphoneDrawPicInBox( x, y, w, h, pic, boxX, boxY, boxW, boxH ); + iphoneDrawPicInBox( drawRect, pic, boundingRect ); + // iphoneDrawPicInBox( int x, int y, int w, int h, const char *pic, int boxX, int boxY, int boxW, int boxH ) + if ( TouchDown( touchRect.x, touchRect.y, touchRect.width, touchRect.height ) && !dragVelocity) { + colour4_t color = { 255, 255, 255, 64 }; + R_Draw_Blend( touchRect.x, touchRect.y, touchRect.width, touchRect.height, color ); + } + return r; +} + + +//gsh +int iphoneDrawPicInBoxWithTouchSpecifiedAndColor( rect_t drawRect, rect_t touchRect, const char *pic, rect_t boundingRect, colour4_t color ) { + + //make sure touches are in drawing bounds + if (touchRect.x < boundingRect.x) { + touchRect.width -= boundingRect.x - touchRect.x; + touchRect.x = boundingRect.x; + } + if (touchRect.x + touchRect.width > boundingRect.x + boundingRect.width) + touchRect.width = boundingRect.x + boundingRect.width - touchRect.x; + if (touchRect.y < boundingRect.y) { + touchRect.height -= boundingRect.y - touchRect.y; + touchRect.y = boundingRect.y; + } + if (touchRect.y + touchRect.height > boundingRect.y + boundingRect.height) + touchRect.height = boundingRect.y + boundingRect.height - touchRect.y; + + int r = TouchReleased( touchRect.x, touchRect.y, touchRect.width, touchRect.height ); + + if ( r ) { + // make sure it is full intensity if it is touch-released, even if + // it wasn't active previously + pfglColor3f( 1, 1, 1 ); + } + // iphoneDrawPic( x, y, w, h, pic ); + // iphoneDrawPicInBox( x, y, w, h, pic, boxX, boxY, boxW, boxH ); + iphoneDrawPicInBox( drawRect, pic, boundingRect ); + R_Draw_Blend( touchRect.x, touchRect.y, touchRect.width, touchRect.height, color ); + // iphoneDrawPicInBox( int x, int y, int w, int h, const char *pic, int boxX, int boxY, int boxW, int boxH ) + if ( TouchDown( touchRect.x, touchRect.y, touchRect.width, touchRect.height ) ) { + colour4_t colorWhite = { 255, 255, 255, 64 }; + R_Draw_Blend( touchRect.x, touchRect.y, touchRect.width, touchRect.height, colorWhite ); + } + return r; +} + +//gsh +int iphoneDrawPicInBoxWithTouchColorAndVelocity( rect_t drawRect, rect_t touchRect, const char *pic, rect_t boundingRect, colour4_t color, int dragVelocity ) { + + //make sure touches are in drawing bounds + if (touchRect.x < boundingRect.x) { + touchRect.width -= boundingRect.x - touchRect.x; + touchRect.x = boundingRect.x; + } + if (touchRect.x + touchRect.width > boundingRect.x + boundingRect.width) + touchRect.width = boundingRect.x + boundingRect.width - touchRect.x; + if (touchRect.y < boundingRect.y) { + touchRect.height -= boundingRect.y - touchRect.y; + touchRect.y = boundingRect.y; + } + if (touchRect.y + touchRect.height > boundingRect.y + boundingRect.height) + touchRect.height = boundingRect.y + boundingRect.height - touchRect.y; + + int r = TouchReleased( touchRect.x, touchRect.y, touchRect.width, touchRect.height ); + + if (dragVelocity) + r = 0; + + if ( r ) { + // make sure it is full intensity if it is touch-released, even if + // it wasn't active previously + pfglColor3f( 1, 1, 1 ); + } + // iphoneDrawPic( x, y, w, h, pic ); + // iphoneDrawPicInBox( x, y, w, h, pic, boxX, boxY, boxW, boxH ); + iphoneDrawPicInBox( drawRect, pic, boundingRect ); + R_Draw_Blend( touchRect.x, touchRect.y, touchRect.width, touchRect.height, color ); + // iphoneDrawPicInBox( int x, int y, int w, int h, const char *pic, int boxX, int boxY, int boxW, int boxH ) + if ( TouchDown( touchRect.x, touchRect.y, touchRect.width, touchRect.height ) && !dragVelocity ) { + colour4_t colorWhite = { 255, 255, 255, 64 }; + R_Draw_Blend( touchRect.x, touchRect.y, touchRect.width, touchRect.height, colorWhite ); + } + return r; +} + + + + +/* + ================== + iphoneDrawPicWithTouchAndColor + gsh + ================== + */ +int iphoneDrawPicWithTouchAndColor( int x, int y, int w, int h, const char *pic, colour4_t color ) { + int r = TouchReleased( x, y, w, h ); + + if ( r ) { + // make sure it is full intensity if it is touch-released, even if + // it wasn't active previously +// pfglColor3f( 1, 1, 1 ); + } +// glColor4f( 0.5f, 0.5f, 1, 0 ); + iphoneDrawPic( x, y, w, h, pic ); + R_Draw_Blend( x, y, w, h, color ); + if ( TouchDown( x, y, w, h ) ) { + colour4_t color = { 255, 255, 255, 64 }; + R_Draw_Blend( x, y, w, h, color ); + } +// glColor4f( 1, 1, 1, 1 ); + return r; +} + +/* + ================== + iphoneDrawPicInBoxWithTouchAndColor + gsh + ================== + */ +int iphoneDrawPicInBoxWithTouchAndColor( rect_t drawRect, const char *pic, colour4_t color, rect_t boxRect ) { + int r = TouchReleased(drawRect.x, drawRect.y, drawRect.width, drawRect.height) + & TouchReleased(boxRect.x, boxRect.y, boxRect.width, boxRect.height); //touch must be inside both boxes! + + if ( r ) { + // make sure it is full intensity if it is touch-released, even if + // it wasn't active previously + // pfglColor3f( 1, 1, 1 ); + } + + iphoneDrawPicInBox( drawRect, pic, boxRect ); + + if (drawRect.x + drawRect.width < boxRect.x) + return 0; + if (drawRect.x > boxRect.x + boxRect.width) + return 0; + if (drawRect.y + drawRect.height < boxRect.y) + return 0; + if (drawRect.y > boxRect.y + boxRect.height) + return 0; + + if (drawRect.x < boxRect.x) { drawRect.x = boxRect.x; } + if (drawRect.x + drawRect.width > boxRect.x + boxRect.width) { drawRect.width = boxRect.x + boxRect.width - drawRect.x; } + if (drawRect.y < boxRect.y) { drawRect.y = boxRect.y; } + if (drawRect.y + drawRect.height > boxRect.y + boxRect.height) { drawRect.height = boxRect.y + boxRect.height - drawRect.y; } + + R_Draw_Blend( drawRect.x, drawRect.y, drawRect.width, drawRect.height, color ); + if ( TouchDown( drawRect.x, drawRect.y, drawRect.width, drawRect.height ) ) { + colour4_t color = { 255, 255, 255, 64 }; + R_Draw_Blend( drawRect.x, drawRect.y, drawRect.width, drawRect.height, color ); + } + // glColor4f( 1, 1, 1, 1 ); + return r; +} + + + /* @@ -115,12 +497,12 @@ void iphoneSlider( int x, int y, int w, int h, const char *title, cvar_t *cvar, } // draw the background - iphoneDrawPic( x, y, w, h, "iphone/stat_bar_2.tga" ); + iphoneDrawPic( x, y, w, h, "iphone/slider_bar_underlay.tga");//stat_bar_2.tga" ); // draw the current range texture_t *gl; - gl = TM_FindTexture( "iphone/stat_bar_1.tga", TT_Pic ); + gl = TM_FindTexture( "iphone/slider_bar.tga", TT_Pic );//stat_bar_1.tga", TT_Pic ); assert( gl ); R_Bind( gl->texnum ); pfglBegin( GL_QUADS ); @@ -132,9 +514,24 @@ void iphoneSlider( int x, int y, int w, int h, const char *title, cvar_t *cvar, pfglEnd(); + //gsh... draw the finger catch + iphoneDrawPic( x+w*f-12, y, 24, h, "iphone/slider_knob.tga" );//finger_catch.tga" ); + + // draw the title and fraction sprintf( str, "%s : %i%%", title, (int)(f*100) ); - iphoneCenterText( x+ w/2, y+h/2-8, str ); + //colour4_t color = {0, 0, 0, 1}; + pfglColor4f(0, 0, 0, 1); //gsh +// y -= 3; + iphoneDrawArialText(x + w/6 + 1, y+h*8/10 + 1, 0.9f, str); + iphoneDrawArialText(x + w/6 + 2, y+h*8/10 + 2, 0.9f, str); + iphoneDrawArialText(x + w/6 + 3, y+h*8/10 + 3, 0.9f, str); + //iphoneCenterTextWithColor(x+ w/2 +1, y+h/2-8 +1, str, color); + //iphoneCenterTextWithColor(x+ w/2 +2, y+h/2-8 +2, str, color); + //iphoneCenterTextWithColor(x+ w/2 +3, y+h/2-8 +3, str, color); + //iphoneCenterText( x+ w/2, y+h/2-8, str ); + pfglColor4f(1, 1, 1, 1); + iphoneDrawArialText(x + w/6, y+h*8/10, 0.9f, str); // check for touches if ( numTouches > 0 && touches[0][0] >= x && touches[0][0] < x + w @@ -171,12 +568,44 @@ void iphoneSlider( int x, int y, int w, int h, const char *title, cvar_t *cvar, ================== */ int BackButton() { - if ( iphoneDrawPicWithTouch( 0, 0, 64, 32, "iphone/button_back.tga" ) ) { + if ( iphoneDrawPicWithTouch( 0, 0, 64, 36, "iphone/button_back.tga" ) ) { return 1; } return 0; } +//gsh... a back button on the other side of the screen +int BackButton2() { + if ( iphoneDrawPicWithTouch( 480-64, 0, 64, 36, "iphone/button_back.tga" ) ) { + return 1; + } + return 0; +} + +//gsh +int BackButton3( int x, int y ) { + if ( iphoneDrawPicWithTouch( x, y, 64, 36, "iphone/button_back.tga" ) ) { + return 1; + } + return 0; +} + +/* + ================== + MenuButton + gsh + ================== + */ +int MenuButton() { + if ( iphoneDrawPicWithTouch( 480-64, 0, 64, 36, "iphone/menu.tga" ) ) { +// if ( iphoneDrawPicWithTouch( 64, 0, 64, 36, "iphone/menu.tga" ) ) { +// if ( iphoneDrawPicWithTouch( 64, 0, 64, 36, "iphone/button_menu_yellow.tga" ) ) { + return 1; + } + return 0; +} + + void GetMoreLevels( int x, int y ) { if ( iphoneDrawPicWithTouch( x, y, 128, 64, "iphone/button_levels.tga" ) ) { // directly to the app store for more levels @@ -184,7 +613,58 @@ void GetMoreLevels( int x, int y ) { } } +//gsh +#if 0 +extern void DownloadSOD(); +extern void BeginStoreKit(); +extern void DisplayWrongVersionedOS(); +extern int TestURLConnection();//const char *url); +extern bool isStorekitAvailable; +//extern int IsSpearInstalled(); +//extern void iphoneActivateConsole(); +#endif +//================================= +// GetSpear +//gsh +//=================================== +#if 0 +void GetSpear(void) +{ + if (isStorekitAvailable) + { + if (TestURLConnection()) //check URL connection + { + /* //it's been decided to pre-package spear of destiny with wolf3d + //however users will need to in-app purchase it to unlock + //only download the data if doesn't exist, otherwise just enter the storekit + if (!IsSpearInstalled()) + DownloadSOD(); + else*/ + BeginStoreKit(); + } + } + else + DisplayWrongVersionedOS(); +} +#endif +//================================= +// GetSpearOfDestiny +//gsh +//=================================== +#if 0 +void GetSpearOfDestiny( int x, int y ) +{ + if ( iphoneDrawPicWithTouch( x, y, 128, 64, "iphone/button_levels.tga" ) ) + { + totalDownloaded = 0; //reset the totalDownload to zero + + Com_Printf("GetSpearOfDestiny called\n"); + + GetSpear(); + } +} +#endif /* ================== SaveTheGame @@ -265,6 +745,9 @@ int LoadTheGame() { return 0; } + + Com_Printf("episode: %i\nmap: %i\n", currentMap.episode, currentMap.map); + // load the huds fread( &huds, 1,sizeof(huds), f); @@ -273,7 +756,11 @@ int LoadTheGame() { PL_NewGame( &Player ); oldCompleted = currentMap.levelCompleted; - iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill ); + if (currentMap.episode < 9) //gsh... added the episode check + iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill ); + else + iphoneStartUserMap(currentMap.episode, currentMap.map, currentMap.skill, NULL); + currentMap.levelCompleted = oldCompleted; // load modifiactions on top @@ -303,15 +790,142 @@ int LoadTheGame() { return 1; } +/* + ================== + iphoneGetUserMapName + + This matches the incoming mapNumber with the correct + map name in the maps directory. Returns 1 if successful + and 0 if failed + gsh + ================== + */ +int iphoneGetUserMapName(int mapNumber, char *mapName) +{ + int numMaps = 0; + int returnValue = 0; + + DIR *dp; + struct dirent *ep; + char mapBuffer[1024]; + + int length = strlen(iphoneDocDirectory); + strcpy(mapBuffer, iphoneDocDirectory); + strcpy(mapBuffer + length, "/usermaps/"); + + dp = opendir (mapBuffer); + + if (dp != NULL) + { + while (ep = readdir (dp)) + {/* + //if you find a .DS_Store file... ignore it! + if ( strcmp(ep->d_name, ".DS_Store") == 0 ) + continue; + + if ( strcmp(ep->d_name, ".") == 0 ) + continue; + + if ( strcmp(ep->d_name, "..") == 0 ) + continue; + */ + ++numMaps; + if (numMaps < 3) //skip the '.' and '..' + continue; + + if (mapNumber == (numMaps - 3)) + { + strcpy(mapName, ep->d_name); + returnValue = 1; + break; + } + + } + //(void) closedir (dp); + closedir (dp); + } + + Com_Printf("numMaps: %i\n", numMaps); + + return returnValue; +} /* ================== - iphoneStartMap + iphoneGetUserMapName + This matches the incoming mapNumber with the correct + map name in the maps directory. Returns 1 if successful + and 0 if failed + gsh + ================== + */ +int iphoneGetUserMapLevelByName(const char *mapName) +{ + int numMaps = 0; + int returnValue = 0; + + DIR *dp; + struct dirent *ep; + char mapBuffer[1024]; + + int length = strlen(iphoneDocDirectory); + strcpy(mapBuffer, iphoneDocDirectory); + strcpy(mapBuffer + length, "/usermaps/"); + + dp = opendir (mapBuffer); + + if (dp != NULL) + { + while (ep = readdir (dp)) + { + if (strcmp(ep->d_name, mapName) == 0) + { + return numMaps-3+1; + } + + /* + //if you find a .DS_Store file... ignore it! + if ( strcmp(ep->d_name, ".DS_Store") == 0 ) + continue; + + if ( strcmp(ep->d_name, ".") == 0 ) + continue; + + if ( strcmp(ep->d_name, "..") == 0 ) + continue; + */ + ++numMaps; + /* + if (numMaps < 3) //skip the '.' and '..' + continue; + + if (mapNumber == (numMaps - 3)) + { + strcpy(mapName, ep->d_name); + returnValue = 1; + break; + }*/ + + } + //(void) closedir (dp); + closedir (dp); + } + + Com_Printf("numMaps: %i\n", numMaps); + + return returnValue; +} + + +/* + ================== + iphoneStartUserMap + gsh This does not reset the player, so call PL_NewGame( &Player ) if it is a new start. ================== */ -void iphoneStartMap( int episodeNum, int mapNum, int skillLevel ) { +void iphoneStartUserMap( int episodeNum, int mapNum, int skillLevel, char *mapName ) { char command[128]; int levelNum = episodeNum*10+mapNum; @@ -319,7 +933,7 @@ void iphoneStartMap( int episodeNum, int mapNum, int skillLevel ) { // get the sound playing Sound_Update( vnull, vnull, vnull, vnull ); - + // clean up game feedback damageflash = 0; bonusFrameNum = 0; @@ -328,16 +942,100 @@ void iphoneStartMap( int episodeNum, int mapNum, int skillLevel ) { // note that this has been tried now currentMap.mapFlags[currentMap.skill][levelNum] |= MF_TRIED; - + // start the game currentMap.episode = episodeNum; currentMap.map = mapNum; currentMap.skill = skillLevel; currentMap.levelCompleted = 0; - + Cvar_SetValue( skill->name, skillLevel ); Cvar_SetValue( episode->name, episodeNum ); - sprintf( command, "w%i%i", currentMap.episode, currentMap.map ); + + Com_Printf("episode: %i\nmap: %i\n", currentMap.episode, currentMap.map); + + if (episodeNum >= 10 && mapName) + { + sprintf( command, "usermaps/%s", mapName ); + Com_Printf("command: %s\n", command); + } + else if (episodeNum >= 10) //mapName was null... we must find what it's called + { + Com_Printf("episode number check true\n"); + mapName = (char *)malloc(sizeof(char)*1024); //sizeof(char) should just be 1 byte + if (iphoneGetUserMapName(mapNum, mapName)) + { + sprintf(command, "usermaps/%s", mapName); + } + else + { + Com_Printf("iphoneGetUserMapName failed"); + currentMap.episode = 0; + currentMap.map = 0; + sprintf( command, "w%i%i", currentMap.episode, currentMap.map ); //load first map if mapName not found + } + free(mapName); + } + else if (episodeNum >= 6) + { + FS_InitFilesystem(); //is this really needed? + sprintf( command, "maps/s%i%i", currentMap.episode - 6, currentMap.map); + } + else + { + sprintf( command, "w%i%i", currentMap.episode, currentMap.map ); + } + Com_Printf("command: %s\n", command); + Client_PrepRefresh( command ); + + menuState = IPM_GAME; +} + +/* + ================== + iphoneStartMap + + This does not reset the player, so call PL_NewGame( &Player ) if it is a new start. + ================== + */ +void iphoneStartMap( int episodeNum, int mapNum, int skillLevel ) { + char command[128]; + int levelNum = episodeNum*10+mapNum; + + Com_Printf( "iphoneStartMap( %i, %i, %i )\n", episodeNum, mapNum, skillLevel ); + + // get the sound playing + Sound_Update( vnull, vnull, vnull, vnull ); + + // clean up game feedback + damageflash = 0; + bonusFrameNum = 0; + attackDirTime[0] = 0; + attackDirTime[1] = 0; + + // note that this has been tried now + currentMap.mapFlags[currentMap.skill][levelNum] |= MF_TRIED; + + // start the game + currentMap.episode = episodeNum; + currentMap.map = mapNum; + currentMap.skill = skillLevel; + currentMap.levelCompleted = 0; + + Cvar_SetValue( skill->name, skillLevel ); + Cvar_SetValue( episode->name, episodeNum ); + + //added by gsh 6/9/2009... load the SOD maps if they were chosen + if (episodeNum >= 6) + { + // FS_InitFilesystem(); + sprintf( command, "maps/s%i%i", currentMap.episode - 6, currentMap.map); + } + else + { + sprintf( command, "w%i%i", currentMap.episode, currentMap.map ); + } + Com_Printf("command: %s\n", command); Client_PrepRefresh( command ); menuState = IPM_GAME; @@ -349,22 +1047,31 @@ void iphoneStartMap( int episodeNum, int mapNum, int skillLevel ) { ================== */ +extern int notifyFrameNum; //gsh void iphoneMainMenu() { char str[80]; float scale = 40 / 32.0; - iphoneDrawPic( 480-256, 0, 256, 128, "iphone/wolf_logo.tga" ); + //iphoneDrawPic( 480-256, 0, 256, 128, "iphone/wolf_logo.tga" ); + //iphoneDrawPic( 0, 0, 480, 320, "iphone/background_main.tga" ); //gsh + iphoneDrawPic(0, 0, 264, 250, "iphone/wolfplatinum_logo.tga"); + /*gsh #ifdef LITE iphoneDrawPic( -20, 0, 256, 64, "iphone/ep_1.tga" ); GetMoreLevels( 0, 96 ); #else iphoneDrawPic( -20, 0, 256, 64, "iphone/ep_1_6.tga" ); -#endif + if (g_version->value != SPEAROFDESTINY) //gsh + GetSpearOfDestiny( 0, 96 ); + else + iphoneDrawPic( 10, 100, 200, 100, "iphone/spear_logo.tga" ); //gsh +#endif*/ // we don't need the logo here now that we have a splash screen // iphoneDrawPic( 0, 320 - 128, 128, 128, "iphone/id_logo.tga" ); - if ( iphoneDrawPicWithTouch( 300 - 64*scale, 80, 128*scale, 64*scale, "iphone/button_resume.tga" ) ) { +// if ( iphoneDrawPicWithTouch( 300 - 64*scale, 80, 128*scale, 64*scale, "iphone/button_resume.tga" ) ) { + if ( iphoneDrawPicWithTouch( 360 - 64*scale, 20, 128*scale, 32*scale, "iphone/button_resume.tga" ) ) { //gsh iphonePreloadBeforePlay(); // if the game was saved at the intermission screen, immediately @@ -372,32 +1079,58 @@ void iphoneMainMenu() { if ( currentMap.levelCompleted ) { iphoneStartIntermission( 0 ); } else { + //reset the notification so that we can see which level we've loaded.. gsh + iphoneSetLevelNotifyText(); + iphoneFrameNum = 0; + notifyFrameNum = 60; menuState = IPM_GAME; } } - sprintf( str, "E%iM%i", currentMap.episode+1, currentMap.map+1 ); - iphoneCenterText( 300, 80+34*scale, str ); - if ( iphoneDrawPicWithTouch( 300 - 64*scale, 170, 128*scale, 32*scale, "iphone/button_control.tga" ) ) { + //gsh + if (currentMap.episode < 9) + sprintf( str, "E%iM%i", currentMap.episode+1, currentMap.map+1 ); + else + sprintf( str, "custom %i", currentMap.map+1 ); + +// iphoneCenterText( 300, 80+34*scale, str ); +// iphoneCenterText( 360, 34*scale, str ); //gsh + +// if ( iphoneDrawPicWithTouch( 300 - 64*scale, 170, 128*scale, 32*scale, "iphone/button_control.tga" ) ) { + if ( iphoneDrawPicWithTouch( 360 - 64*scale, 120, 128*scale, 32*scale, "iphone/button_settings.tga" ) ) { //gsh menuState = IPM_CONTROLS; } - if ( iphoneDrawPicWithTouch( 300 - 64*scale, 220, 128*scale, 32*scale, "iphone/button_new.tga" ) ) { - menuState = IPM_SKILL; +// if ( iphoneDrawPicWithTouch( 300 - 64*scale, 220, 128*scale, 32*scale, "iphone/button_new.tga" ) ) { + if ( iphoneDrawPicWithTouch( 360 - 64*scale, 70, 128*scale, 32*scale, "iphone/button_new.tga" ) ) { //gsh + menuState = IPM_SKILL;//IPM_MAPSELECTOR;//IPM_SKILL; //gsh + } +// if ( iphoneDrawPicWithTouch( 300 - 64*scale, 270, 128*scale, 32*scale, "iphone/button_web.tga" ) ) { + if ( iphoneDrawPicWithTouch( 100 - 64*scale, 250, 64, 64, "iphone/id_logo.tga" ) ) { //gsh + wasCalledFromDownloadInstructionsMenu = 0; + iphoneYesNoBox("Website", "This will navigate you to idsoftware.com. Continue?"); +// SysIPhoneOpenURL( "http://www.idsoftware.com/wolfenstein3dclassic/" ); } - if ( iphoneDrawPicWithTouch( 300 - 64*scale, 270, 128*scale, 32*scale, "iphone/button_web.tga" ) ) { - SysIPhoneOpenURL( "http://www.idsoftware.com/wolfenstein3dclassic/" ); + //gsh +// if (iphoneDrawPicWithTouch(100 - 64*scale, 270, 128*scale, 32*scale, "iphone/button_control.tga" ) ) { + if (iphoneDrawPicWithTouch(360 - 64*scale, 220, 128*scale, 32*scale, "iphone/button_more.tga" ) ) { //gsh + menuState = IPM_MORE;//IPM_TRIVIA; } + int x = 360; + int y = 170; if ( SysIPhoneOtherAudioIsPlaying() ) { - iphoneDrawPic( 480 - 64, 220, 64, 64, "iphone/music_off.tga" ); +// iphoneDrawPic( 480 - 64, 220, 64, 64, "iphone/music_off.tga" ); + iphoneDrawPic( x - 64*scale, y, 128*scale, 32*scale, "iphone/music_off.tga" ); //gsh } else { if ( music->value ) { - if ( iphoneDrawPicWithTouch( 480 - 64, 220, 64, 64, "iphone/music_on.tga" ) ) { + //if ( iphoneDrawPicWithTouch( 480 - 64, 220, 64, 64, "iphone/music_on.tga" ) ) { + if ( iphoneDrawPicWithTouch( x - 64*scale, y, 128*scale, 32*scale, "iphone/music_on.tga" ) ) { //gsh Cvar_SetValue( music->name, 0 ); Sound_StopBGTrack(); } } else { - if ( iphoneDrawPicWithTouch( 480 - 64, 220, 64, 64, "iphone/music_off.tga" ) ) { + //if ( iphoneDrawPicWithTouch( 480 - 64, 220, 64, 64, "iphone/music_off.tga" ) ) { + if ( iphoneDrawPicWithTouch( x - 64*scale, y, 128*scale, 32*scale, "iphone/music_off.tga" ) ) { //gsh Cvar_SetValue( music->name, 1 ); Sound_StartBGTrack( levelData.musicName, levelData.musicName ); } @@ -408,7 +1141,47 @@ void iphoneMainMenu() { iphoneCenterText( 460, 300, str ); } - +//========================================== +// iphoneUpdateControlDrags() +// Updates the touches for the scrolling maps +//========================================== +void iphoneUpdateControlDrags(int numPresets, int x, int y, int w, int h, int spacing, int *dragPosition, int *dragVelocity) +{ + //Update drag/touch info +// int x = 0; +// int w = 480;// - skillSides - 64; + /* + if (TouchDown(x, y, w, h)) + { + if (!numPrevTouches) + prevTouches[0][0] = touches[0][0]; + else if (numTouches == 1) + *dragVelocity = touches[0][0] - prevTouches[0][0]; + }*/ + + //update the drags + *dragPosition += *dragVelocity; + /* + //int rightBoundary = 240 - 2*width;//480/2 - (numPresets*width/2 + spacing); + if (*dragPosition < -270-10)//(numPresets*(width+spacing))/2 ) + *dragPosition = -270-10;//(numPresets*(width+spacing))/2; + else if (*dragPosition > 70+10)//rightBoundary) + *dragPosition = 70+10;//rightBoundary; + + if (*dragPosition < -270) + *dragVelocity = 2; + else if (*dragPosition > 70) + *dragVelocity = -2; + */ + + //retard the velocity + if (*dragVelocity > 0) + --*dragVelocity; + else if (*dragVelocity < 0) + ++*dragVelocity; + +} +#if 0 /* ================== iphoneControlMenu @@ -418,50 +1191,432 @@ void iphoneMainMenu() { void iphoneControlMenu() { int i; + int x = 0; + int y = 0; + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + if ( BackButton() ) { menuState = IPM_MAIN; } - if ( iphoneDrawPicWithTouch( 480-128, 0, 128, 32, "iphone/advanced_button.tga" ) ) { + + + x = 480-128*9/10; + if ( iphoneDrawPicWithTouch( x, y, 128*9/10, 36/*32*9/10*/, "iphone/advanced_button.tga" ) ) { Cvar_SetValue( controlScheme->name, -1 ); iphonePreloadBeforePlay(); // make sure all the hud textures are loaded menuState = IPM_HUDEDIT; } + x = 240-108*9/10; + iphoneDrawPic(x, y, 217*9/10, 50*9/10, "iphone/header_settings.tga"); + + //update the drags + int startPosition = 70; + static int dragPosition = 70; + static int dragVelocity = 0; + + y = 20; + x = 0; + + if (iphoneDrawPicWithTouch(9, y+60, 64, 64, "iphone/button_left.tga") ) + dragVelocity = -20;//-18; + if (iphoneDrawPicWithTouch(411, y+60, 64, 64, "iphone/button_right.tga") ) + dragVelocity = 20;//18; + + int size = 160;//180;//110; + //iphoneUpdateControlDrags(4, 70, y+25, size*2, size - 53, 10, &dragPosition, &dragVelocity ); + + //update the drags + dragPosition += dragVelocity; + + //retard the drags + if (dragVelocity > 0) + --dragVelocity; + else if (dragVelocity < 0) + ++dragVelocity; + + //stop dragging when we're slow and close to a node + if ((dragVelocity < 10 && dragVelocity > 0) || (dragVelocity > -10 && dragVelocity < 0)) + { + if (abs((dragPosition-startPosition)%(size+10)) < 7) + { + dragVelocity = 0; + int tx = dragPosition - startPosition; + int n = tx/(size+10);//480; + dragPosition = n*(size+10) + startPosition; + + } + } + if (dragVelocity == 0) + { + int spacing = 10; + int height = size; + int n = (dragPosition - startPosition) / (height+spacing); + + int nodePosition = n*(height+spacing) + startPosition; + if (nodePosition != dragPosition) + { + int nodePositionPlus = nodePosition + (height+spacing); + int nodePositionMinus = nodePosition - (height+spacing); + int distMinus = abs(nodePositionMinus - dragPosition); + int distPlus = abs(nodePositionPlus - dragPosition); + int dist = abs(nodePosition - dragPosition); + + + int diff = nodePosition - dragPosition; + + if (distMinus < distPlus && distMinus < dist) + diff = nodePositionMinus - dragPosition; + else if (distPlus < dist && distPlus < distMinus) + diff = nodePositionPlus - dragPosition; + + if (diff < 0) { + dragVelocity -= 5; + } + else { + dragVelocity += 5; + } + } + } + + + //draw the preset layouts for ( i = 0 ; i < 4 ; i++ ) { char str[128]; int remap[4] = { 3,4,1,2}; // artist named them differently than intended... - sprintf( str, "iphone/layout_%i.tga", remap[i] ); + sprintf( str, "iphone/iphone_preset_%i.tga", remap[i] ); if ( i != controlScheme->value ) { pfglColor3f( 0.5, 0.5, 0.5 ); } - if ( iphoneDrawPicWithTouch( 5 + 120 * i, 40, 110, 110, str ) ) { + int thisX = 5 + (size+10) * i + dragPosition; + + //wrap presets around in a circle + if (thisX > 70 + 480 -140) + thisX -= (size+10) * 4; + + if (thisX < 70 - 480 + 140) + thisX += (size+10) * 4; + + if (dragPosition > 70 + (size+10) * 4 ) + dragPosition = 70; + + if (dragPosition < 70 - (size+10) * 4 ) + dragPosition = 70; + + if ( iphoneDrawPicInBoxWithTouchSpecified( RectMake(thisX, y+50, size, size/2), + RectMake(thisX, y + 25, size, size - 53), + str, + RectMake(70, 0, 480-140, 320) ) + && !dragVelocity) + { Cvar_SetValue( controlScheme->name, i ); HudSetForScheme( i ); } pfglColor3f( 1, 1, 1 ); + + char buffer[32]; + sprintf(buffer, "Preset %i", i+1); + + pfglColor3f( 0, 0, 0 ); + iphoneDrawTextInBox( RectMake(thisX+35+1, y+125+1, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); + iphoneDrawTextInBox( RectMake(thisX+35+2, y+125+2, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); + iphoneDrawTextInBox( RectMake(thisX+35+3, y+125+3, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); + pfglColor3f( 1, 1, 1 ); + iphoneDrawTextInBox( RectMake(thisX+35, y+125, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); } + + + int sliderHeight = 25;//35; + int sliderSpacing = 10; + int sliderY = y + size;// - 13;//190;//170; + int sliderX = 80;//20; + int sliderWidth = 320;//440; - iphoneSlider( 20, 170, 440, 40, "sensitivity", sensitivity, 0, 1 ); + //sensitivity slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "sensitivity", sensitivity, 0, 1 ); + sliderY += sliderHeight + sliderSpacing; - iphoneSlider( 20, 220, 440, 40, "tilt move speed", tiltMove, 5000, 30000 ); + //tilt move speed slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "tilt move speed", tiltMove, 5000, 30000 ); + sliderY += sliderHeight + sliderSpacing; if ( tiltMove->value == 5000 ) { Cvar_SetValue( tiltMove->name, 0 ); } if ( tiltMove->value ) { Cvar_SetValue( tiltTurn->name, 0 ); } - iphoneSlider( 20, 270, 440, 40, "tilt turn speed", tiltTurn, 500, 3000 ); + + //tilt turn speed slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "tilt turn speed", tiltTurn, 500, 3000 ); + sliderY += sliderHeight + sliderSpacing; if ( tiltTurn->value == 500 ) { Cvar_SetValue( tiltTurn->name, 0 ); } if ( tiltTurn->value ) { Cvar_SetValue( tiltMove->name, 0 ); } + + //hud alpha slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "hud alpha", hudAlpha, 0, 1 ); + sliderY += sliderHeight + sliderSpacing; - //iphoneSlider( 20, 280, 440, 40, "tilt fire", tiltFire, 0, 1 ); + y = 0; + x = 480-74; + if (revLand->value) + { + y = 320-32; + x = 74-64; + } + +#ifdef VOLUMEHACK + //Draw volume up/down settings... gsh + + if ( iphoneDrawPicWithTouch( x, y, 64, 32, "iphone/button_pistol.tga" ) ) { + if ((int)volumeFireUpSetting->value) + Cvar_Set("volumeFireUpSetting", "0"); + else + Cvar_Set("volumeFireUpSetting", "1"); + } + if ((int)volumeFireUpSetting->value) + iphoneDrawPic(x, y, 64, 32, "iphone/button_pistol.tga"); + else + iphoneDrawPic(x, y, 64, 32, "iphone/button_knife.tga"); + + x = 480-145; + if (revLand->value) + x = 145-64; + + if ( iphoneDrawPicWithTouch( x, y, 64, 32, "iphone/button_pistol.tga" ) ) { + if ((int)volumeFireDownSetting->value) + Cvar_Set("volumeFireDownSetting", "0"); + else + Cvar_Set("volumeFireDownSetting", "1"); + } + + if ((int)volumeFireDownSetting->value) + iphoneDrawPic(x, y, 64, 32, "iphone/button_pistol.tga"); + else + iphoneDrawPic(x, y, 64, 32, "iphone/button_knife.tga"); +#endif } +#endif +/* + ================== + iphoneControlMenu + gsh... different from above + ================== + */ +void iphoneControlMenu() { + int i; + + int x = 0; + int y = 0; + + iphoneDrawPic(x, y, 480, 320, "iphone/submenus_background_image.tga"); + + if ( BackButton() ) { + menuState = IPM_MAIN; + } + + x = 480-128*9/10; + if ( iphoneDrawPicWithTouch( x, y, 128*9/10, 36, "iphone/advanced_button.tga" ) ) { + Cvar_SetValue( controlScheme->name, -1 ); + iphonePreloadBeforePlay(); // make sure all the hud textures are loaded + menuState = IPM_HUDEDIT; + } + + x = 240-108*9/10; + iphoneDrawPic(x, y, 217*9/10, 50*9/10, "iphone/header_settings.tga"); + + //update the position of the control settings + const int startPosition = 70; + static int currentPreset = 0; + int numPresets = 4; + + //update the drags + static int Position = 70; + + y = 20; + x = 0; + + static int moveRight = 0; + + //move right or left, depending on button pushed + if (iphoneDrawPicWithTouch(9, y+60, 64, 64, "iphone/button_left.tga") ) { + moveRight = 0; + ++currentPreset; + if (currentPreset > numPresets-1) { + currentPreset = 0;//1; + + } + } + if (iphoneDrawPicWithTouch(411, y+60, 64, 64, "iphone/button_right.tga") ) { + moveRight = 1; + --currentPreset; + if (currentPreset < 0) { + currentPreset = numPresets-1;//2; + } + } + + + int width = 160;//305; + int spacing = 10;//215;//175; + + int size = width;// + spacing; + + int destinationPosition = startPosition - currentPreset*(width+spacing); + + //if we are not where we are supposed to be... get us there + if (Position != destinationPosition) + { + int oldPosition = Position; + int deltaPos = destinationPosition - Position; + + //move entities + int moveDistance = 8; + if ( moveRight ) + { + Position += moveDistance; + if (destinationPosition < Position && destinationPosition > oldPosition) + Position = destinationPosition; + } + else //move left + { + Position -= moveDistance; + if (destinationPosition > Position && destinationPosition < oldPosition) + Position = destinationPosition; + } + + //check if the current position has crossed over the destination position + if ( abs(deltaPos) <= 16) + Position = destinationPosition; + } + + + //draw the preset layouts + for ( i = 0 ; i < 4 ; i++ ) { + char str[128]; + int remap[4] = { 3,4,1,2}; // artist named them differently than intended... + sprintf( str, "iphone/iphone_preset_%i.tga", remap[i] ); + if ( i != controlScheme->value ) { + pfglColor3f( 0.5, 0.5, 0.5 ); + } + int thisX = 5 + (size+10) * i + Position; + + //wrap presets around in a circle + if (thisX > 70 + 480 -140) + thisX -= (size+10) * 4; + + if (thisX < 70 - 480 + 140) + thisX += (size+10) * 4; + + if (Position > 70)//70 + (size+10) * 4 ) + Position = 70 - (size+10)*4; + + if (Position < 70 - (size+10) * 4 ) + Position = 70; + + if ( iphoneDrawPicInBoxWithTouchSpecified( RectMake(thisX, y+50, size, size/2), + RectMake(thisX, y + 25, size, size - 53), + str, + RectMake(70, 0, 480-140, 320) ) ) + { + Cvar_SetValue( controlScheme->name, i ); + HudSetForScheme( i ); + } + pfglColor3f( 1, 1, 1 ); + + char buffer[32]; + sprintf(buffer, "Preset %i", i+1); + + pfglColor3f( 0, 0, 0 ); + iphoneDrawTextInBox( RectMake(thisX+35+1, y+125+1, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); + iphoneDrawTextInBox( RectMake(thisX+35+2, y+125+2, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); + iphoneDrawTextInBox( RectMake(thisX+35+3, y+125+3, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); + pfglColor3f( 1, 1, 1 ); + iphoneDrawTextInBox( RectMake(thisX+35, y+125, 16, 16), 480, buffer, RectMake(70, 0, 480-140+10, 320) ); + } + + + int sliderHeight = 25;//35; + int sliderSpacing = 10; + int sliderY = y + size;// - 13;//190;//170; + int sliderX = 80;//20; + int sliderWidth = 320;//440; + + //sensitivity slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "sensitivity", sensitivity, 0, 1 ); + sliderY += sliderHeight + sliderSpacing; + + //tilt move speed slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "tilt move speed", tiltMove, 5000, 30000 ); + sliderY += sliderHeight + sliderSpacing; + if ( tiltMove->value == 5000 ) { + Cvar_SetValue( tiltMove->name, 0 ); + } + if ( tiltMove->value ) { + Cvar_SetValue( tiltTurn->name, 0 ); + } + + //tilt turn speed slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "tilt turn speed", tiltTurn, 500, 3000 ); + sliderY += sliderHeight + sliderSpacing; + if ( tiltTurn->value == 500 ) { + Cvar_SetValue( tiltTurn->name, 0 ); + } + if ( tiltTurn->value ) { + Cvar_SetValue( tiltMove->name, 0 ); + } + + //hud alpha slider + iphoneSlider( sliderX, sliderY, sliderWidth, sliderHeight, "hud alpha", hudAlpha, 0, 1 ); + sliderY += sliderHeight + sliderSpacing; + + y = 0; + x = 480-74; + if (revLand->value) + { + y = 320-32; + x = 74-64; + } + +#ifdef VOLUMEHACK + //Draw volume up/down settings... gsh + + if ( iphoneDrawPicWithTouch( x, y, 64, 32, "iphone/button_pistol.tga" ) ) { + if ((int)volumeFireUpSetting->value) + Cvar_Set("volumeFireUpSetting", "0"); + else + Cvar_Set("volumeFireUpSetting", "1"); + } + + if ((int)volumeFireUpSetting->value) + iphoneDrawPic(x, y, 64, 32, "iphone/button_pistol.tga"); + else + iphoneDrawPic(x, y, 64, 32, "iphone/button_knife.tga"); + + + x = 480-145; + if (revLand->value) + x = 145-64; + + if ( iphoneDrawPicWithTouch( x, y, 64, 32, "iphone/button_pistol.tga" ) ) { + if ((int)volumeFireDownSetting->value) + Cvar_Set("volumeFireDownSetting", "0"); + else + Cvar_Set("volumeFireDownSetting", "1"); + } + + if ((int)volumeFireDownSetting->value) + iphoneDrawPic(x, y, 64, 32, "iphone/button_pistol.tga"); + else + iphoneDrawPic(x, y, 64, 32, "iphone/button_knife.tga"); +#endif +} + /* ================== @@ -473,6 +1628,12 @@ void iphoneSkillMenu() { int s; char str[64]; + //gsh + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + + //gsh + iphoneDrawPic(0, 0, 480, 48, "iphone/header_how_tough_are_you.tga"); + if ( BackButton() ) { menuState = IPM_MAIN; } @@ -487,7 +1648,8 @@ void iphoneSkillMenu() { if ( s != (int)skill->value ) { pfglColor3f( 0.5, 0.5, 0.5 ); } - if ( iphoneDrawPicWithTouch( 112, 40+64*s, 256, 64, str ) ) { + //if ( iphoneDrawPicWithTouch( 112, 40+64*s, 256, 64, str ) ) { + if ( iphoneDrawPicWithTouch( 112, 60+64*s, 256, 64, str ) ) { Cvar_SetValue( skill->name, s ); menuState = IPM_EPISODE; } @@ -495,6 +1657,7 @@ void iphoneSkillMenu() { } } + /* ================== iphoneEpisodeMenu @@ -508,32 +1671,936 @@ void iphoneEpisodeMenu() { int numE = 1; #else int numE = 6; + //gsh + if (g_version->value == SPEAROFDESTINY) + numE = 9; #endif - if ( BackButton() ) { - menuState = IPM_SKILL; + if ( BackButton() ) { + menuState = IPM_SKILL; + } + + // 96 x 48 images + for ( e = 0 ; e < numE ; e++ ) { + + //gsh... added the if and button_epSOD + if (e < 6) + my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", e+1 ); + else + my_snprintf(str, sizeof( str), "iphone/button_epSOD.tga"); + + if ( e != (int)episode->value ) { + pfglColor3f( 0.5, 0.5, 0.5 ); + } + int height = 32;//48;//gsh... 96x32 + if ( iphoneDrawPicWithTouch( 48, 32+height*e, 384, height, str ) ) { + Cvar_SetValue( episode->name, e ); + menuState = IPM_MAPS; + }/*gsh + if ( iphoneDrawPicWithTouch( 48, 32+48*e, 384, 48, str ) ) { + Cvar_SetValue( episode->name, e ); + menuState = IPM_MAPS; + }*/ + pfglColor3f( 1, 1, 1 ); + } + +#ifdef LITE + // buy more episodes button + GetMoreLevels( 240 - 64, 200 ); +#else + #if 0 + if (g_version->value != SPEAROFDESTINY) //gsh + GetSpearOfDestiny( 240 - 64, 232 ); + #endif +#endif +} + +/* + ================== + iphoneUpdateScrollingDrags + gsh + ================== + */ +//int scrollingFlags = 0; +void iphoneUpdateScrollingDrags(int *dragPosition, int *dragVelocity, int upperLimit, int lowerLimit, int padding, rect_t touchRect) +{ + static int oldVelocity = 0; + + + //if Touch is in touchable area +// if (TouchDown(touchRect.x, touchRect.y, touchRect.width, touchRect.height)) + if (TouchDown( 0, 0, 480, 320) )//|| isTouchMoving) + { + if (!numPrevTouches) + prevTouches[0][1] = touches[0][1]; + else if (numTouches == 1) + *dragVelocity = touches[0][1] - prevTouches[0][1]; + + //if (*dragVelocity < 3) + // isTouchMoving = 0; + + /* + Com_Printf("update drags: Touch is down!\n"); + Com_Printf("dragVelocity: %i\n", *dragVelocity); + Com_Printf("prevTouch: %i\n", prevTouches[0][1]); + Com_Printf("touch: %i\n", touches[0][1]); + */ + } +// else if (*dragVelocity == 0) //this returns the position to a node position + else if (abs(*dragVelocity) < 5) //this returns the position to a node position + { + int startPosition = 70 - 10; + int height = 48; + int spacing = 20; + int nodePosition = upperLimit + padding; + + + int n = (*dragPosition - startPosition) / (height+spacing); + + nodePosition = n*(height+spacing) + startPosition;// - 5; +/* if (nodePosition != *dragPosition) + {/* + int nodePositionPlus = nodePosition + (height+spacing); + int nodePositionMinus = nodePosition - (height+spacing); + int distMinus = abs(nodePositionMinus - *dragPosition); + int distPlus = abs(nodePositionPlus - *dragPosition); + int dist = abs(nodePosition - *dragPosition); + + + int diff = nodePosition - *dragPosition; + + if (distMinus < distPlus && distMinus < dist) + diff = nodePositionMinus - *dragPosition; + else if (distPlus < dist && distPlus < distMinus) + diff = nodePositionPlus - *dragPosition; + + if (diff < 0) + --*dragVelocity; + else + ++*dragVelocity; + * + if (oldVelocity > 0) + ++*dragVelocity; + else if (oldVelocity < 0) + --*dragVelocity; + }*/ + + //let's try a different way to continue our path + if (nodePosition != *dragPosition && oldVelocity > 0) + { + int minSpeed = 5; + if (oldVelocity > 0) { + *dragVelocity = minSpeed; + int newPosition = *dragPosition + *dragVelocity; + + Com_Printf("newPosition: %i\n", newPosition); + Com_Printf("nodePosition: %i\n", nodePosition); + Com_Printf("dragPosition: %i\n\n\n", *dragPosition); + + if ( newPosition > nodePosition ) { + *dragPosition = nodePosition; + *dragVelocity = 0; + } + }/* + else if (oldVelocity < 0) { + *dragVelocity = -minSpeed; + int newPosition = *dragPosition + *dragVelocity; + + Com_Printf("newPosition: %i\n", newPosition); + Com_Printf("nodePosition: %i\n", nodePosition); + Com_Printf("dragPosition: %i\n\n\n", *dragPosition); + + if ( newPosition < nodePosition - height ){//(height + spacing)) { + *dragPosition = nodePosition; + *dragVelocity = 0; + } + }*/ + } + + nodePosition = (n-1)*(height+spacing) + startPosition;// - 10;//5; +// if (nodePosition - (height + spacing - 5) != *dragPosition && oldVelocity < 0) + if (nodePosition != *dragPosition && oldVelocity < 0) + { + int minSpeed = 5; + + //else if (oldVelocity < 0) { + *dragVelocity = -minSpeed; + int newPosition = *dragPosition + *dragVelocity; +// nodePosition -= height + spacing - 5; + + Com_Printf("newPosition: %i\n", newPosition); + Com_Printf("nodePosition: %i\n", nodePosition); + Com_Printf("dragPosition: %i\n\n\n", *dragPosition); + + if ( newPosition < nodePosition /*- height*/ ){//(height + spacing)) { + *dragPosition = nodePosition; + *dragVelocity = 0; + } + //} + + } + } + + + oldVelocity = *dragVelocity; + + + //update the drags + *dragPosition += *dragVelocity; + + //boundary check our drags + if (*dragPosition < lowerLimit - padding) + *dragPosition = lowerLimit - padding; + if (*dragPosition > upperLimit + padding) + *dragPosition = upperLimit + padding; + + if (*dragPosition < lowerLimit) + *dragVelocity = 2; + if (*dragPosition > upperLimit) + *dragVelocity = -2; + + //retard the velocity + if (*dragVelocity > 0) + --*dragVelocity; + else if (*dragVelocity < 0) + ++*dragVelocity; + + +// if (abs(*dragVelocity) < 5) +// *dragVelocity = 0; + +} + +/* + ================== + iphoneScrollingEpisodeMenu + gsh + ================== + */ +void iphoneScrollingEpisodeMenu() { + int e; + char str[64]; + int doesUserMapsExist = 0; + + //used for preventing accidental touches + //user must hold touch down for 10 frames in order to load episode + static int touchedFrameNum = 0; + static int lastTouchFrame = 0; + +#ifdef LITE + int numE = 1; +#else + int numE = 11;//10; + + //check for user maps + DIR *dp; + char mapBuffer[1024]; + + int length = strlen(iphoneDocDirectory); + strcpy(mapBuffer, iphoneDocDirectory); + strcpy(mapBuffer + length, "/usermaps/"); + + dp = opendir (mapBuffer); + + + if (dp) { + doesUserMapsExist = 1; + //numE = 11; + closedir(dp); + } + + //Com_Printf("number of episodes: %i\n", numE); + //gsh + //if (g_version->value == SPEAROFDESTINY) + // numE = 9; +#endif + + + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + + iphoneDrawPic( 0, 0, 480, 48, "iphone/header_episodes.tga"); + + if ( BackButton() ) { + menuState = IPM_SKILL; + } + + static int dragPosition = 70; + static int dragVelocity = 0; + +// Com_Printf("dragPosition: %i dragVelocity: %i\n", dragPosition, dragVelocity ); + +/* int height=(320-48)/2; + //iphoneDrawPic( 480-64, 60, 64, 64, "iphone/button_back.tga"); + if (iphoneDrawPicWithTouch( 480-64, 48, 64, height, "iphone/button_back.tga"))//TouchDown(480-64, 60, 64, 64)) + dragVelocity = -25; + //iphoneDrawPic( 480-64, 60+64, 64, 64, "iphone/button_back.tga"); + if ( iphoneDrawPicWithTouch( 480-64, height+48, 64, height, "iphone/button_back.tga"))//TouchDown(480-64, 60+64, 64, 64)) + dragVelocity = 25; +*/ + int lowerLimit = -320; + lowerLimit = 70-(11-4)*(48+20); + iphoneUpdateScrollingDrags(&dragPosition, &dragVelocity, 55, lowerLimit, 0, RectMake(0, 48, 480-48, 320-64)); + + // 96 x 48 images + for ( e = 0 ; e < numE ; e++ ) { + + my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", e+1 ); + + //light the episode we are currently on + if (currentMap.episode > 5 && currentMap.episode < 10) + { + //int tempEpisode = 6; + int levelNum = currentMap.episode*10 + currentMap.map; + + //check for spear of destiny episodes + if (levelNum == 78 || (levelNum >= 60 && levelNum < 65)) + { + if ( e != 6 ) + pfglColor3f( 0.5, 0.5, 0.5 ); + } + else if (levelNum >= 65 && levelNum < 70) + { + if ( e != 7 ) + pfglColor3f( 0.5, 0.5, 0.5 ); + } + else if ((levelNum >= 70 && levelNum < 76) || levelNum == 79) + { + if ( e != 8 ) + pfglColor3f( 0.5, 0.5, 0.5 ); + } + else if (levelNum == 76 || levelNum == 77 || levelNum == 80) + { + if ( e != 9 ) + pfglColor3f( 0.5, 0.5, 0.5 ); + } + + } + else if ( e != (int)episode->value ) { + pfglColor3f( 0.5, 0.5, 0.5 ); + } + + //Com_Printf("isTouchMoving value: %i\n", isTouchMoving); + + + int height = 48; + int spacing = 20;//10; + //if ( iphoneDrawPicInBoxWithTouch( 48, dragPosition+(height+spacing)*e, 384, height, str ) && !dragVelocity ) { +/* if (iphoneDrawPicInBoxWithTouchSpecified(RectMake(0, dragPosition+(height+spacing)*e, 480, height), + RectMake(0, dragPosition+(height+spacing)*e, 480, height), + str, + RectMake(0, 48, 480, 320-48) )//RectMake(0, 42, 480, 238) ) + && !dragVelocity + && !isTouchMoving )//touchedFrameNum >= NUM_TOUCHFRAME ) //must hold finger down for 10 frames +*/// iphoneDrawPicInBoxWithTouchAndVelocity + if (iphoneDrawPicInBoxWithTouchAndVelocity(RectMake(0, dragPosition+(height+spacing)*e, 480, height), + RectMake(0, dragPosition+(height+spacing)*e, 480, height), + str, + RectMake(0, 48, 480, 320-48), dragVelocity | isTouchMoving ) )//RectMake(0, 42, 480, 238) ) + //&& !dragVelocity + //&& !isTouchMoving ) + { + //if they haven't downloaded any custom maps, but choose custom maps, goto the more menu + if (e == 10 && !doesUserMapsExist) + { + wasDLInstructionsCalledFromEpisodeMenu = 1; + menuState = IPM_DOWNLOADINSTRUCTIONS; + pfglColor3f( 1, 1, 1 ); + break; + } + Cvar_SetValue( episode->name, e ); + menuState = IPM_MAPS; + } + pfglColor3f( 1, 1, 1 ); + } + + //update the number of frames the touch is down + if ( TouchDown(0, 0, 480, 320) ) { + int dframe = iphoneFrameNum - lastTouchFrame; + touchedFrameNum += dframe; + } + else { + touchedFrameNum = 0; + } + lastTouchFrame = iphoneFrameNum; + +#ifdef LITE + // buy more episodes button + GetMoreLevels( 240 - 64, 200 ); +#else +#ifdef SPEARSTOREKIT + if (g_version->value != SPEAROFDESTINY) //gsh + GetSpearOfDestiny( 240 - 64, 232 ); +#endif +#endif + + if ( MenuButton() ) { + menuState = IPM_MAIN; + } +} +//gsh +extern void iphoneDrawRewards(int m, int s, int x, int y); +//gsh +extern int returnButtonFrameNum; +/* +//gsh... this is for the map selections +colour4_t colorSecret = { 80, 0, 0, 100 }; +//colour4_t colorNoTry = { 0, 0, 0, 100 }; +colour4_t colorNoTry = { 0, 0, 0, 0 }; +colour4_t colorTried = { 120, 120, 0, 100 }; +colour4_t colorCompleted = { 0, 0, 120, 80 }; +*/ +colour4_t colorSecret = { 120, 0, 60, 100 }; +//colour4_t colorNoTry = { 0, 0, 0, 100 }; +colour4_t colorNoTry = { 0, 0, 0, 150 }; +colour4_t colorTried = { 80, 80, 80, 40 }; +colour4_t colorCompleted = { 0, 120, 0, 80 }; + +/* + ======================== + iphoneDrawWolf3dMaps + gsh + ======================== + */ +void iphoneDrawWolf3dMaps(int dragPosition, int dragVelocity, int e, int s, int height, int spacing, int touchedFrameNum) +{ + char str[64]; + /* + colour4_t colorSecret = { 64, 0, 0, 100 }; + colour4_t colorNoTry = { 0, 0, 0, 100 }; + colour4_t colorTried = { 80, 80, 0, 100 }; + colour4_t colorCompleted = { 0, 80, 0, 100 }; + */ + + + + // draw the individual maps + for ( int m = 0 ; m < 10; m++ ) { + int y; + + switch(m) { + case 9: sprintf( str, "SECRET" ); break; + case 8: sprintf( str, "BOSS" ); break; + default: sprintf( str, "LEVEL %i", m+1 ); break; + } + + y = m*(height + spacing) + dragPosition; + + unsigned char *color = colorNoTry; + // decide on the background color + int levelNum = e*10+m; + int ch = currentMap.mapFlags[s][levelNum]; + + // bit1 = attempted + // bit2 = completed + // bit3 = 100% kills + // bit4 = 100% secrets + // bit5 = 100% treasure + if ( m == 9 && !( ch & MF_TRIED ) ) { + color = colorSecret; + } else if ( ch & MF_COMPLETED ) { + color = colorCompleted; + } else if ( ch & MF_TRIED ) { + color = colorTried; + } else { + color = colorNoTry; + } + + // blink the level you are currently on + if ( ( iphoneFrameNum & 8 ) && m == currentMap.map && e == currentMap.episode ) { + color = colorNoTry; + } + /* + //TODO: delete this switch statement + switch (m%4){ + case 0: color = colorSecret; break; + case 1: color = colorTried; break; + case 2: color = colorCompleted; break; + case 3: color = colorNoTry; break; + }*/ + + rect_t box = RectMake(0, 48, 480, 320-48); + int borderWidth = 40; +/* if (iphoneDrawPicInBoxWithTouchSpecifiedAndColor(RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + "iphone/menu_bar.tga", + box, + color) && !dragVelocity + && !isTouchMoving)//touchedFrameNum >= 10) +*/ if (iphoneDrawPicInBoxWithTouchColorAndVelocity(RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + "iphone/menu_bar.tga", + box, + color, dragVelocity | isTouchMoving) )// && !dragVelocity + //&& !isTouchMoving) + { + // don't let them go to the secret level unless they earned it + if ( m == 9 && !( ch & MF_TRIED ) ) + continue; + + PL_NewGame( &Player ); + iphoneStartMap( e, m, s ); + iphoneFrameNum = 0; + returnButtonFrameNum = 100; + iphonePreloadBeforePlay(); + } + + //draw the rewards + iphoneDrawRewards(e*10+m, s, 0, y); + + //iphoneCenterText( x, y, str ); +// iphoneDrawTextInBox(RectMake(100, y, 16, 16), 500, str, box); +// iphoneDrawText(100, y, 16, 16, str); +// pfglColor4ub(0xE1, 0xA6, 0x0, 0xFF); +// iphoneDrawText( 100, y , 16, 16, str ); +// pfglColor4ub(0xFF, 0xFF, 0xFF, 0xFF); + iphoneDrawMapName( RectMake(100, y, 16, 16), str); +// iphoneDrawMapName( RectMake(100, y, 32, 32), str); +// iphoneFrameNum = 0; +// returnButtonFrameNum = 100;//60; + } +} + +/* + ================== + iphoneDrawSpearMaps + gsh + ================== + */ + +void iphoneDrawSpearMaps(int dragPosition, int dragVelocity, int fakeEpisode, int s, int height, int spacing, int touchedFrameNum) +{ + char str[64]; + /* + colour4_t colorSecret = { 64, 0, 0, 100 }; + colour4_t colorNoTry = { 0, 0, 0, 100 }; + colour4_t colorTried = { 80, 80, 0, 100 }; + colour4_t colorCompleted = { 0, 80, 0, 100 }; + * + //TODO: change these colors!!!! + colour4_t colorSecret = { 80, 0, 0, 100 }; + colour4_t colorNoTry = { 0, 0, 0, 100 }; + colour4_t colorTried = { 120, 120, 0, 100 }; + colour4_t colorCompleted = { 0, 0, 120, 80 }; + */ + int numMaps = 0; + switch (fakeEpisode) { + case 6: numMaps = 6; break; //tunnels maps 1-5, 19 + //case 7: numMaps = 6; break; //dungeon maps 6-10, 20 + //case 8: numMaps = 6; break; //castle maps 11-16 + case 7: numMaps = 5; break; //dungeon maps 6-10 + case 8: numMaps = 7; break; //castle maps 11-16, 20 + case 9: numMaps = 3; break; //final maps 17, 18 and 21 + default: break; + } + + //the real episode & map values + int e = 6; + int m = 0; + + // draw the individual maps + for ( int fakeMap = 0; fakeMap < numMaps; fakeMap++ ) { + int y; + + if (fakeEpisode == 9) + { + switch(fakeMap) { + case 0: sprintf( str, "Ramparts" ); break; + case 1: sprintf( str, "Death Knight" ); break; + case 2: sprintf( str, "Dungeon Dimension" ); break; + default: sprintf( str, "LEVEL %i", fakeMap+1 ); break; + } + } + else + { + switch(fakeMap) { + case 6: if (fakeEpisode == 8) sprintf(str, "SECRET"); break; + case 5: if (fakeEpisode == 8) sprintf( str, "BOSS" ); else sprintf( str, "SECRET" ); break; + case 4: if (fakeEpisode != 8){ sprintf( str, "BOSS" ); break; } + default: sprintf( str, "LEVEL %i", fakeMap+1 ); break; + } + } + + //get the real episode and map and store in e, m + e = fakeEpisode; + m = fakeMap; + switch (fakeEpisode) + { + case 6: + if (fakeMap == 5) { + e = 7; + m = 8; + } + break; + case 7: + e = 6; + m += 5; + break; + case 8: + e = 7; + if (fakeMap == 6) + m = 9; + break; + case 9: + if ( fakeMap == 0) { e = 7; m = 6; } + if ( fakeMap == 1) { e = 7; m = 7; } + if ( fakeMap == 2) { e = 8; m = 0; } + break; + default: + break; + } + + Com_Printf("fakeEpisode: %i fakeMap: %i\n", fakeEpisode, fakeMap); + Com_Printf("e: %i m: %i\n", e, m); + + y = fakeMap*(height + spacing) + dragPosition; + + // decide on the background color + unsigned char *color = colorNoTry; + int levelNum = e*10+m; + int ch = currentMap.mapFlags[s][levelNum]; + + // bit1 = attempted + // bit2 = completed + // bit3 = 100% kills + // bit4 = 100% secrets + // bit5 = 100% treasure + if ( (levelNum == 78 || levelNum == 79) && !( ch & MF_TRIED ) ) { + color = colorSecret; + } else if ( ch & MF_COMPLETED ) { + color = colorCompleted; + } else if ( ch & MF_TRIED ) { + color = colorTried; + } else { + color = colorNoTry; + } + + //blink the level you are currently on + if ( ( iphoneFrameNum & 8 ) && m == currentMap.map && e == currentMap.episode ) { + color = colorNoTry; + } + + rect_t box = RectMake(0, 48, 480, 320-48); + int borderWidth = 40; +/* if (iphoneDrawPicInBoxWithTouchSpecifiedAndColor(RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + "iphone/menu_bar.tga", + box, + color) && !dragVelocity + && !isTouchMoving)//touchedFrameNum >= NUM_TOUCHFRAME) +*/ if (iphoneDrawPicInBoxWithTouchColorAndVelocity(RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + "iphone/menu_bar.tga", + box, + color, dragVelocity | isTouchMoving ) ) + //&& !isTouchMoving) + { + //diagnostic info + Com_Printf("fakeEpisode: %i fakeMap: %i\n", fakeEpisode, fakeMap); + Com_Printf("e: %i m: %i\n", e, m); + + // don't let them go to the secret level unless they earned it + if ( (levelNum == 78 || levelNum == 79) && !( ch & MF_TRIED ) ) + continue; + + PL_NewGame( &Player ); + iphonePreloadBeforePlay(); + iphoneStartMap(e, m, s); + iphoneFrameNum = 0; + returnButtonFrameNum = 100; + break; //break the loop... no need to keep looping + } + + //draw the rewards + iphoneDrawRewards(levelNum, s, 0, y); + + //draw map name + iphoneDrawMapName( RectMake(100, y, 16, 16), str); + } +} + +/* + ================== + iphoneDrawUserCreatedMaps + gsh + ================== + */ +int iphoneDrawUserCreatedMaps(int dragPosition, int dragVelocity, /*int fakeEpisode,*/ int skillValue, int height, int spacing, int touchedFrameNum) +{ + int numMaps = 0; + + DIR *dp; + struct dirent *ep; + char mapBuffer[1024]; + + int length = strlen(iphoneDocDirectory); + strcpy(mapBuffer, iphoneDocDirectory); + strcpy(mapBuffer + length, "/usermaps/"); + + dp = opendir (mapBuffer); + + if (dp != NULL) + { + /* + //colour4_t colorSecret = { 64, 0, 0, 100 }; + colour4_t colorNoTry = { 0, 0, 0, 100 }; + colour4_t colorTried = { 80, 80, 0, 100 }; + colour4_t colorCompleted = { 0, 80, 0, 100 }; + */ + unsigned char *color = colorNoTry; + + int y = dragPosition;//Yoffset; + + //draw the custom map spacing + //y += height + spacing; + iphoneDrawPic( 0, 0, 480, 48, "iphone/header_ep10.tga"); + + Com_Printf("y: %i\n", y); + + while (ep = readdir (dp)) + { + //if you find a .DS_Store file... ignore it! + if ( strcmp(ep->d_name, ".DS_Store") == 0 ) + continue; + + ++numMaps; + if (numMaps < 3) //skip the '.' and '..' + continue; + + //Com_Printf("y: %i\n", y); + + //draw the names! + if ( y >= 0 && y < 320 ) + { + //grab map info + int levelNum = numMaps-3 + 100; + int ch = currentMap.mapFlags[skillValue][levelNum]; + + // bit1 = attempted + // bit2 = completed + // bit3 = 100% kills + // bit4 = 100% secrets + // bit5 = 100% treasure + if ( ch & MF_COMPLETED ) { + color = colorCompleted; + } else if ( ch & MF_TRIED ) { + color = colorTried; + } else { + color = colorNoTry; + } + + //comment to display completed user maps + color = colorNoTry; + + //blink the level you are currently on + if ( ( iphoneFrameNum & 8 ) && (currentMap.map+10*currentMap.episode)==levelNum ) { + //color = colorNoTry; + color = colorTried; + } + + int borderWidth = 40; + rect_t box = RectMake(0, 48, 480, 320-48); + if (iphoneDrawPicInBoxWithTouchColorAndVelocity(RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + RectMake(borderWidth, y - 9, 480-2*borderWidth, height), + "iphone/menu_bar.tga", + box, + color, dragVelocity | isTouchMoving) ) + { + //reset the player to new + PL_NewGame( &Player ); + + //set episode and map numbers and load map + int e = 10; //10 will be used to show a custom map + Cvar_SetValue( episode->name, e ); + iphonePreloadBeforePlay(); //make sure all necessary textures are loaded + iphoneStartUserMap( e, numMaps - 3, skillValue, ep->d_name ); + iphoneFrameNum = 0; + returnButtonFrameNum = 100; + break; //no point in continuing the loop + } + + + pfglColor4f(0, 0, 0, 1); + iphoneCenterArialText( 240+1, y +25+1, 0.9f, ep->d_name ); + iphoneCenterArialText( 240+2, y +25+2, 0.9f, ep->d_name ); + pfglColor4f(225.0f/255, 166.0f/255, 0, 1); + pfglColor4f(225.0f/255, 242.0f/255, 0, 1); + iphoneCenterArialText( 240, y +25, 0.9f, ep->d_name ); + pfglColor4f(1, 1, 1, 1); + + //draw the rewards + //uncomment to display rewards + //iphoneDrawRewards(numMaps-2+90, skillValue, 0, y); + } + + y += height + spacing; + } + closedir (dp); + + --numMaps; + --numMaps; + } + + return numMaps; +} + +/* + ================== + iphoneScrollingMapMenu + gsh + ================== + */ +extern int forceDrawRewards; +void iphoneScrollingMapMenu() +{ +#ifdef LITE +# define NUM_MAPS 3 +#else +# define NUM_MAPS 10 +#endif + + + //used for preventing accidental touches + //user must hold touch down for 10 frames in order to load map + static int touchedFrameNum = 0; + static int lastTouchFrame = 0; + + int e, s; + char str[64]; + + int height = 48; + int spacing = 20;//10; + + static int dragPosition = 70; + static int dragVelocity = 0; + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); +/* + //static int forceDrawRewards = 0; + //This is only for debugging/testing out the look of the medals + //TODO: delete or comment out + if (iphoneDrawPicWithTouch(0, 320-40, 40, 40, "iphone/button_back.tga")) + { + if (forceDrawRewards == 0) + forceDrawRewards = 1; + else + forceDrawRewards = 0; + } + +*/ + // draw the level selection + e = episode->value; + if ( e < 0 ) { + e = 0; + } + + if ( e > 10 ) //gsh + e = 10; + + s = skill->value; + if ( s < 0 ) { + s = 0; + } + if ( s > 3 ) { + s = 3; + } + + //gsh + int numlevels = 10; + if ( e == 8 ) + numlevels = 1; + + + + //---------------------------- + //Update Drags +/* height=(320-48)/2; + if (iphoneDrawPicWithTouch( 480-64, 48, 64, height, "iphone/button_back.tga")) + dragVelocity = -25; + if ( iphoneDrawPicWithTouch( 480-64, 48+height, 64, height, "iphone/button_back.tga")) + dragVelocity = 25; +*/ height = 48; + + static int lowerLimit = 65; + /* + if ( e < 6) + lowerLimit = -250; + else if ( e < 9) + lowerLimit = -20; + else if ( e < 10) + lowerLimit = 65; + */ + if ( e < 6) { + //lowerLimit = -250; + lowerLimit = 70 - (10-4)*(height+spacing); //startPosition - (numberMaps - numberOnScreen)*(height + spacing) } + else { + switch (e) { + case 6: //tunnels + lowerLimit = -20; + lowerLimit = 70 - (6-4)*(height+spacing); + break; + case 7: //dungeons + lowerLimit = 20; + lowerLimit = 70 - (5-4)*(height+spacing); + break; + case 8: //castle + lowerLimit = -85; + lowerLimit = 70 - (7-4)*(height+spacing); + break; + case 9: //ramparts + lowerLimit = 65; + break; + } + } + /* + if ( e == 7 ) + lowerLimit = 20; - // 96 x 48 images - for ( e = 0 ; e < numE ; e++ ) { - my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", e+1 ); + if ( e == 8 ) + lowerLimit = -85; + */ + iphoneUpdateScrollingDrags(&dragPosition, &dragVelocity, 65, lowerLimit, 0, RectMake(0, 48, 480-48, 320-64)); + //---------------------------- + + if ( e < 6 ) + iphoneDrawWolf3dMaps(dragPosition, dragVelocity, e, s, height, spacing, touchedFrameNum); + else if ( e < 10 ) + iphoneDrawSpearMaps(dragPosition, dragVelocity, e, s, height, spacing, touchedFrameNum); + else { + int numMaps = iphoneDrawUserCreatedMaps(dragPosition, dragVelocity, s, height, spacing, touchedFrameNum); - if ( e != (int)episode->value ) { - pfglColor3f( 0.5, 0.5, 0.5 ); + lowerLimit = 65; + if (numMaps > 4) { + //lowerLimit = 269 - (numMaps-1)*(spacing + height); + //lowerLimit = 65 - (numMaps - 4)*(spacing + height) + 30; + lowerLimit = 70 - (numMaps-4)*(height+spacing); } - if ( iphoneDrawPicWithTouch( 48, 32+48*e, 384, 48, str ) ) { - Cvar_SetValue( episode->name, e ); - menuState = IPM_MAPS; - } - pfglColor3f( 1, 1, 1 ); } -#ifdef LITE - // buy more episodes button - GetMoreLevels( 240 - 64, 200 ); -#endif -} + + //update the number of frames the touch is down + if ( TouchDown(0, 0, 480, 320) ) { + int dframe = iphoneFrameNum - lastTouchFrame; + touchedFrameNum += dframe; + } + else { + touchedFrameNum = 0; + } + lastTouchFrame = iphoneFrameNum; + + // draw the header for the episode + my_snprintf( str, sizeof( str ), "iphone/header_ep%i.tga", e+1 ); + iphoneDrawPic( 0, 0, 480, 48, str ); + + if ( BackButton() ) { + menuState = IPM_EPISODE; + } + if ( MenuButton() ) { + menuState = IPM_MAIN; + } +} /* ================== iphoneMapMenu @@ -557,10 +2624,18 @@ void iphoneMapMenu() { e = episode->value; if ( e < 0 ) { e = 0; - } + }/*gsh if ( e > 5 ) { e = 5; - } + }*/ + if ( e > 8 ) //gsh + e = 8; + //if player chose SOD maps... draw all 21 SOD maps.. gsh + /* if ( e >= 6 ){ + iphoneDrawSODMaps(); //this function didn't seem to be working out + return; + } + */ s = skill->value; if ( s < 0 ) { s = 0; @@ -569,6 +2644,11 @@ void iphoneMapMenu() { s = 3; } + //gsh + int numlevels = 10; + if ( e == 8 ) + numlevels = 1; + // draw the episode selection my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", e+1 ); iphoneDrawPicWithTouch( 96, 0, 384, 48, str ); @@ -600,6 +2680,8 @@ void iphoneMapMenu() { // decide on the background color int levelNum = e*10+m; int ch = currentMap.mapFlags[s][levelNum]; + + Com_Printf("Map: %i ch: %i\n", levelNum, ch); // bit1 = attempted // bit2 = completed // bit3 = 100% kills @@ -763,26 +2845,108 @@ void DrawRatio( int y, int got, int total, const char *bonusPic ) { void DrawIntermissionStats() { char str[128]; - iphoneDrawPic( 0, 0, 480, 320, "iphone/intermission_256.tga" ); + //gsh +// iphoneDrawPic( 0, 0, 480, 320, "iphone/intermission_256.tga" ); + iphoneDrawPic( 0, 0, 480, 320, "iphone/intermission.tga" ); // episode - my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", currentMap.episode+1 ); - iphoneDrawPic( 0, 0, 384, 48, str ); + //if (currentMap.episode < 10)//6) //gsh added the check for SOD +// my_snprintf( str, sizeof( str ), "iphone/button_ep%i.tga", currentMap.episode+1 ); + + //display the correct episode header + if (currentMap.episode < 6) + my_snprintf( str, sizeof( str ), "iphone/header_ep%i.tga", currentMap.episode+1 ); + else if (currentMap.episode < 10) { + int currentLevel = currentMap.episode * 10 + currentMap.map; + switch (currentLevel) { + case 60: case 61: case 62: case 63: case 64: case 78: + my_snprintf( str, sizeof( str ), "iphone/header_ep7.tga" ); + break; + case 65: case 66: case 67: case 68: case 69: case 79: + my_snprintf( str, sizeof( str ), "iphone/header_ep8.tga" ); + break; + case 70: case 71: case 72: case 73: case 74: case 75: + my_snprintf( str, sizeof( str ), "iphone/header_ep9.tga" ); + break; + case 76: case 77: case 80: + my_snprintf( str, sizeof( str ), "iphone/header_ep10.tga" ); + break; +/* case 77: + my_snprintf( str, sizeof( str ), "iphone/header_ep10.tga" ); + break; + case 80: + my_snprintf( str, sizeof( str ), "iphone/header_ep10.tga" ); + break; +*/ default: + sprintf( str, " "); + break; + } + } + else + my_snprintf( str, sizeof( str ), "iphone/header_ep11.tga" ); + //else + // my_snprintf( str, sizeof( str ), "iphone/button_epSOD.tga"); + +// iphoneDrawPic( 0, 0, 384, 48, str ); +// iphoneDrawPic( -104, 0, 480, 48, str ); //gsh + iphoneDrawPic( 0, 0, 480, 48, str ); //gsh // level - iphoneDrawNumber( 430, 0, currentMap.map + 1, 48, 48 ); +// iphoneDrawNumber( 430, 0, currentMap.map + 1, 48, 48 ); +// iphoneDrawNumber( 430-48, 50, currentMap.map + 1, 48, 48 ); //gsh + + //display the appropriate mission number + if (currentMap.episode < 6) + iphoneDrawNumber( 430-48, 50, currentMap.map + 1, 48, 48 ); + else if (currentMap.episode < 10) { + int currentLevel = currentMap.episode * 10 + currentMap.map; + switch (currentLevel) { + case 60: case 61: case 62: case 63: case 64: + iphoneDrawNumber( 430-48, 50, currentLevel - 60 + 1, 48, 48 ); + break; + case 78: + iphoneDrawNumber( 430-48, 50, 6, 48, 48 ); + break; + case 65: case 66: case 67: case 68: case 69: + iphoneDrawNumber( 430-48, 50, currentLevel - 65 + 1, 48, 48 ); + break; + case 79: + iphoneDrawNumber( 430-48, 50, 6, 48, 48 ); + break; + case 70: case 71: case 72: case 73: case 74: case 75: + iphoneDrawNumber( 430-48, 50, currentLevel - 70 + 1, 48, 48 ); + break; + case 76: + iphoneDrawNumber( 430-48, 50, 1, 48, 48 ); + break; + case 77: + iphoneDrawNumber( 430-48, 50, 2, 48, 48 ); + break; + case 80: + iphoneDrawNumber( 430-48, 50, 3, 48, 48 ); + break; + default: + sprintf( str, " "); + break; + } + } + else + iphoneDrawNumber( 430-48, 50, currentMap.map + 1, 48, 48 ); + // par / time - DrawTime( 51, 63, levelstate.fpartime * 60 ); // fpartime is in minutes - DrawTime( 285, 63, levelstate.time / 60 ); // levelstate.time is in tics + int offset = 50; + DrawTime( 51, 63+offset, levelstate.fpartime * 60 ); // fpartime is in minutes + DrawTime( 285, 63+offset, levelstate.time / 60 ); // levelstate.time is in tics if ( levelstate.time/60 <= levelstate.fpartime * 60 ) { - iphoneDrawPic( 480 - 40, 63, 32, 32, "iphone/partime.tga" ); + iphoneDrawPic( 480 - 40, 63+offset, 32, 32, "iphone/partime.tga" ); } // ratios - DrawRatio( 124, levelstate.killed_monsters, levelstate.total_monsters, "iphone/kills.tga" ); - DrawRatio( 189, levelstate.found_secrets, levelstate.total_secrets, "iphone/secrets.tga" ); - DrawRatio( 255, levelstate.found_treasure, levelstate.total_treasure, "iphone/treasure.tga" ); + int correction = 8; + DrawRatio( 124+offset-1*correction, levelstate.killed_monsters, levelstate.total_monsters, "iphone/kills.tga" ); + DrawRatio( 189+offset-2*correction, levelstate.found_secrets, levelstate.total_secrets, "iphone/secrets.tga" ); + DrawRatio( 255+offset-3*correction, levelstate.found_treasure, levelstate.total_treasure, "iphone/treasure.tga" ); } /* @@ -816,9 +2980,34 @@ void iphoneIntermission() { PL_NextLevel( &Player ); - if( g_version->value == SPEAROFDESTINY ) { + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh) + { + //added all this leveling stuff... gsh + int currentLevel = currentMap.episode * 10 + currentMap.map; + nextLevel = currentLevel + 1; + switch (currentLevel) { + case 78: nextLevel = 64; break; //if tunnels secret was defeated goto tunnels boss +// case 79: nextLevel = 69; break; //if dungeons secret was defeated goto dungeons boss + case 79: nextLevel = 72; break; //if castle secret was defeated goto next castle map + default: break; + } + if (Player.playstate == ex_secretlevel) { + switch (currentLevel) { + case 63: nextLevel = 78; break; //if tunnels secret was earned goto tunnels secret + //case 68: nextLevel = 79; break; //if dungeons secret was earned goto dungeons secret + case 71: nextLevel = 79; break; //if castle secret was earned goto castle secret + default: break; + } + } + if (nextLevel >= 60 + 21) + { + // show ultimate victory + menuState = IPM_VICTORY; + Sound_StartBGTrack( "music/URAHERO.ogg", "music/URAHERO.ogg" ); + return; + } } - else + else if (currentMap.episode < 6) //gsh added the check if it's the original wolf3d episodes { int currentLevel = currentMap.episode * 10 + currentMap.map; @@ -864,6 +3053,14 @@ void iphoneIntermission() { } #endif } + else //they just defeated a custom map... gsh + { + // go back to the episode select screen + //menuState = IPM_VICTORY; + menuState = IPM_MAPS; + Sound_StartBGTrack( "music/URAHERO.ogg", "music/URAHERO.ogg" ); + return; + } iphoneStartMap( (nextLevel/10), (nextLevel%10), skill->value ); } @@ -880,6 +3077,7 @@ void iphoneVictory() { return; } menuState = IPM_EPISODE; +//gsh menuState = IPM_MAPSELECTOR; } /* @@ -1027,6 +3225,11 @@ void iphoneOpenAutomap() { } void iphoneAutomap() { + + //draw the new background... gsh + iphoneDrawPic(0, 0, 480, 320, "iphone/map_background.tga"); + + mapTile_t *mt; float px, py; float angle, c, s; @@ -1072,7 +3275,122 @@ void iphoneAutomap() { } - // todo -- double tap for center on player? + // gsh - double tap for center on player + static unsigned int timeTouchDown = 0; + static int numTaps = 0; + static unsigned int lastTapTime = 0; + static int tapX = 0; + static int tapY = 0; + static int zoom = 0; + static float TargetX = 0; + static float TargetY = 0; + static float TargetZoom = 0; + static int prevTapX = 0; + static int prevTapY = 0; + + //touch down + if ( numTouches == 1 && numPrevTouches == 0) { + timeTouchDown = Sys_Milliseconds(); + prevTapX = tapX; + prevTapY = tapY; + tapX = touches[0][0]; + tapY = touches[0][1]; + } + //touch up + if ( numTouches == 0 && numPrevTouches == 1 ) { + unsigned int currentTime = Sys_Milliseconds(); + + //check if time between last tap and current time is too long + if (Sys_Milliseconds() - lastTapTime > 500 || zoom) + numTaps = 0; + + //detect tap + if ( currentTime - timeTouchDown < 200 ) { + + //record tap time if first tap + if (numTaps < 1) + lastTapTime = Sys_Milliseconds(); + + ++numTaps; + /* + //center map on player + if (numTaps >= 2) { + numTaps = 0; + zoom = 1; + TargetX = Player.position.origin[0] / (float)TILEGLOBAL; + TargetY = Player.position.origin[1] / (float)TILEGLOBAL; + TargetZoom = scale; + }*/ + + //the taps need to be near each other to qualify as a double tap event + int dx = abs(tapX - prevTapX); + int dy = abs(tapY - prevTapY); + int maxTapSeparation = 60; + + //safari style double tap zoom on location! + if (numTaps >= 2 && dx < maxTapSeparation && dy < maxTapSeparation) { + numTaps = 0; + zoom = 1; + //need to translate tap/screen coordinate to map coordinate + + int Xrelative2screenorigin = tapX - 240; + int Yrelative2screenorigin = 160 - tapY; + float scaledX = Xrelative2screenorigin / scale; + float scaledY = Yrelative2screenorigin / scale; + float camSpaceX = scaledX + mapOrigin[0]; + float camSpaceY = scaledY + mapOrigin[1]; + + //mapOrigin[0] = camSpaceX; + //mapOrigin[1] = camSpaceY; + + TargetX = camSpaceX; + TargetY = camSpaceY; + + if (scale < 32) { //zoom half way in + //scale = 32; + TargetZoom = 32; + } + else { + //scale = 4; //zoom completely out + TargetZoom = 4; + } + + Cvar_SetValue( mapScale->name, scale ); + } + } + else { + //no tap... reset to 0 + numTaps = 0; + } + } + + if (zoom) + { + int invSpeed = 2;//3; + float dist = TargetX - mapOrigin[0]; + mapOrigin[0] += dist/invSpeed; + dist = TargetY - mapOrigin[1]; + mapOrigin[1] += dist/invSpeed; + + dist = TargetZoom - scale; + scale += dist/(2*invSpeed); //let's zoom a litle slower than we pan + + + Com_Printf("current: %f\n", mapOrigin[0]); + Com_Printf("target: %f\n", TargetX); + //Com_Printf("dist: %f\n\n", dist); + + float tolerance = 0.5f;//3; + if ( abs(mapOrigin[0] - TargetX) < tolerance && abs(mapOrigin[1] - TargetY) < tolerance && abs(scale - TargetZoom) < tolerance/2) + { + mapOrigin[0] = TargetX; + mapOrigin[1] = TargetY; + scale = TargetZoom; + zoom = 0; + } + + Cvar_SetValue( mapScale->name, scale ); + } // set up matrix for drawing in tile units @@ -1146,44 +3464,638 @@ void iphoneAutomap() { } // stats button for stats display - if ( iphoneDrawPicWithTouch( 480-64, 0, 64, 32, "iphone/stats.tga" ) ) { + //if ( iphoneDrawPicWithTouch( 64, 0, 64, 36, "iphone/stats.tga" ) ) { + if ( iphoneDrawPicWithTouch( 64, 0, 120, 36, "iphone/stats_large.tga" ) ) { menuState = IPM_STATS; } + //gsh + if ( MenuButton() ) { + menuState = IPM_MAIN; + } } void iphoneStats() { DrawIntermissionStats(); + + //gsh + if ( BackButton() ) { + menuState = IPM_AUTOMAP; + } + if ( MenuButton() ) { + menuState = IPM_MAIN; + } +} + +#if SPEARSTOREKIT +//========================== +// iphoneDownloadSpearProgressBar +//gsh +//========================== +void iphoneDownloadSpearProgressBar() +{ + char str[80]; + float scale = 40 / 32.0; + int barHeight = 30; + + //calculate the percentage of data received + unsigned int percentDownloaded = totalDownloaded * 100 / DownloadFileSize; - // require all touches off before the intermission can exit - if ( numTouches == 0 && hasReleased == 0 ) { - hasReleased = 1; - return; // don't let the TouchReleased immediately fire + int y = barHeight + 150 + 10; + my_snprintf( str, sizeof(str), "Downloading: %i", dataAmount); + iphoneDrawText( 100, y, 16, 16, str ); + y += 17*scale; + my_snprintf( str, sizeof(str), "Percent Download: %i\%", percentDownloaded ); + iphoneDrawText( 100, y, 16, 16, str ); + y += 17*scale; + my_snprintf( str, sizeof(str), "Total Downloaded: %i", totalDownloaded ); + iphoneDrawText( 100, y, 16, 16, str ); + y += 17*scale; + my_snprintf(str, sizeof(str), "SOD will download and install itself."); + iphoneDrawText( 50, y, 16, 16, str ); + y += 17*scale; + my_snprintf(str, sizeof(str), "You have not been charged at this time."); + iphoneDrawText( 50, y, 16, 16, str ); + y += 17*scale; + + //draw "Spear of Destiny" at the top + iphoneDrawPic(90, 20, 256, 128, "iphone/spear_logo.tga"); + + //draw the progress bar + iphoneDrawPic( 40, 150, 400, barHeight, "iphone/menu_bar.tga" ); + + //draw the progress + colour4_t color = { 255, 0, 0, 100 }; + R_Draw_Blend( 40, 150, 4*percentDownloaded, barHeight, color ); +} +#endif + +//========================== +// iphoneDownloadMenu +//gsh +//========================== +char urlbuffer[1024]; +void iphoneDownloadMenu() +{ + char str[80]; + float scale = 40 / 32.0; + int barHeight = 30; + + //draw the background + iphoneDrawPic(0, 0, 480, 320, "iphone/download_background.tga"); + + //draw the url + iphoneCenterText(240, 120, urlbuffer); + //iphoneDrawTextInBox(RectMake(0, 120, 16, 16), 480, urlbuffer, RectMake(0, 120, 480, 32)); + + int y = barHeight + 150 + 10; + my_snprintf( str, sizeof(str), "Packet Size: %i", userDataAmount); + iphoneDrawText( 100, y, 16, 16, str ); + y += 17*scale; + + my_snprintf( str, sizeof(str), "Total Downloaded: %i", totalDownloaded ); + iphoneDrawText( 100, y, 16, 16, str ); + y += 17*scale; + + static int iterator = 5; + static int pos = 230; + + //int width = 60; + pos += iterator; + + if (pos > 480) + pos = -60; + + //draw the barrel + iphoneDrawPic(0, 150, 480, 34, "iphone/download_progress_bar.tga"); + + //draw the bullet! + iphoneDrawPic(pos, 150+34/2-22/2, 60, 22, "iphone/download_bullet.tga"); +} + +/* +//========================================== +// iphoneUpdateTriviaDrags() +// Updates the touches for the scrolling maps + // gsh +//========================================== + //TODO: delete this +void iphoneUpdateTriviaAndInstructionsDrags(int numEnteries, int x, int y, int w, int h, int spacing, int *dragPosition, int *dragVelocity) +{ + //Update drag/touch info + // int x = 0; + // int w = 480;// - skillSides - 64; + /* + if (TouchDown(x, y, w, h)) + { + if (!numPrevTouches) + prevTouches[0][0] = touches[0][0]; + else if (numTouches == 1) + *dragVelocity = touches[0][0] - prevTouches[0][0]; + }* + + + + + //update the drags + *dragPosition += *dragVelocity; + /* + //int rightBoundary = 240 - 2*width;//480/2 - (numPresets*width/2 + spacing); + if (*dragPosition < -(numTrivia-1)*480-10)//270-10)//(numPresets*(width+spacing))/2 ) + *dragPosition = -(numTrivia-1)*480-10;//270-10;//(numPresets*(width+spacing))/2; + else if (*dragPosition > x+10)//rightBoundary) + *dragPosition = x+10;//rightBoundary; + + if (*dragPosition < -(numTrivia-1)*480 + x)//270) + *dragVelocity = 2; + else if (*dragPosition > x) + *dragVelocity = -2; + * + + //retard the velocity + if (*dragVelocity > 0) + --*dragVelocity; + else if (*dragVelocity < 0) + ++*dragVelocity; + +}*/ + +//---------------------------------- +// DrawBlendInBox +// gsh +//----------------------------------- +void DrawBlendInBox(int x, int y, int w, int h, colour4_t color, int boxX, int boxW) +{ + if ( x + w < boxX ) + return; + else if ( x > boxX + boxW) + return; + + if ( x < boxX ) { + w = x + w - boxX; + x = boxX; } - if ( !hasReleased ) { + if ( x + w > boxX + boxW ) + w = boxX + boxW - x; + + R_Draw_Blend( x, y, w, h, color ); +} + +//---------------------------------- +// iphoneTriviaMenu +// gsh +//----------------------------------- +#if 0 +// TODO: delete this implementation of iphoneTriviaMenu +void iphoneTriviaMenu() +{ + //int numTrivia = 15; + + static char triviaText[][1024] = { + " ORIGINAL WOLF:\n\nThe original release of Wolfenstein 3D only contained 3 Episodes. Episodes 4, 5, and 6 were sold separately as \"The Nocturnal Missions\", and were intended to act as a prequel to the original trilogy of Episodes. Subsequent releases of the game included all 6 Episodes together.", + " BJ, THE MAN:\n\nWilliam Joseph Blazkowicz was born August 15, 1911, to Polish immigrants. Blazkowicz was a top spy for the Allied Forces, eventually receiving the Congressional Medal of Honor.", + " BOX ART:\n\nKen Rieger was the talented illustrator who created the cover art for Spear of Destiny, Wolfenstein3D and Commander Keen.", + " THE REAL SPEAR:\n\nThe Spear of Destiny, also known as The Spear or The Holy Lance, is believed to have been the weapon used to pierce the side of Jesus Christ at the Crucifixion. The Spear soon became a symbol of God's favor and those who possessed it were believed to be invincible.", + " THE SPEAR AND HITLER:\n\nHitler is believed to have acquired the Spear at the beginning of WWII. Near the end of that war, it is rumored that General Patton discovered the Spear and that the downfall of Germany began that day. It is fabled that the U.S. was destined to succeed Germany as the New World Power once ownership of the Spear changed hands.", + " DEATH DIMENSION:\n\nIt is said that Hitler made a pact with the Angel of Death, promising the souls of his Nazi soldiers, to protect the Spear of Destiny.", + " GOD MODE:\n\nIn the game, if you can access god mode, BJ's eyes will glow with eerie golden light.", + " A PRINCE:\n\nRobert Prince, wrote the music for Commander Keen, Wolfenstein 3-D, and Doom.", + " DELAYED DEVELOPMENT:\n\nIt is rumored that work on Spear of Destiny was hindered by the development team's time spent playing Fatal Fury (which Jay Wilbur called 'Fatal Productivity'), and Street Fighter II.", + " A MATTER OF DEGREES:\n\nJohn Carmack is known for his innovations in 3D graphics and rocketry but what is less known is that this self-taught engineer has no degrees - he dropped out of school after one semester.", + " THE CARMACK:\n\nJohn Carmack, one of the founders of id Software, preferred to work at a pizza joint and make games rather than go to college. His favorite programming food is pizza and diet coke.", + " DREAMING IN DIGITAL:\n\nDoom was reported to cause gamers to dream in pixels and lower productivity.", + " KEEPING IT IN THE FAMILY:\n\nBJ is Commander Keen's grandfather.", + " WHAT'S IN A NAME:\n\nThe original name for Doom was \"It's Green and Pissed\"", + " GIBS:\n\nGibs, pronounced with a hard 'g', is sometimes confused as 'jibs' due to its pronunciation. The term came from the imagery of flying chicken giblets, or gibs for short.", + " WOLFENSTEIN 3D:\n\nThe game was originally designed to have more complex gameplay. Though dragging bodies, stealth kills and uniforms were already programmed, it was decided that they slowed down the pace of the game and were removed.", + " ORIGINAL WOLF:\n\nThe original release of Wolfenstein 3D only contained 3 Episodes. Episodes 4, 5, and 6 were sold separately as \"The Nocturnal Missions\", and were intended to act as a prequel to the original trilogy of Episodes. Subsequent releases of the game included all 6 Episodes together.", + }; + + //get number of trivia + int numTrivia = sizeof(triviaText)/(sizeof(char) * 1024); + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + iphoneDrawPic(240-108*9/10, 0, 217*9/10, 50*9/10, "iphone/header_trivia.tga"); + + if (BackButton()) { + menuState = IPM_MORE; return; } - if ( !TouchReleased( 0, 0, 480, 320 ) ) { + if (MenuButton()) { + menuState = IPM_MAIN; return; } - menuState = IPM_AUTOMAP; + int startPosition = 85; + + //update the drags + static int dragPosition = 85; + static int dragVelocity = 0; + //static int currentLocation = 0; + // int y = 30; + + int y = 20; + int x = 0; + //if (revLand->value) + // y = -20; + + if (iphoneDrawPicWithTouch(9, y+60+16, 64, 64, "iphone/button_left.tga") ){//&& !dragVelocity) { + dragVelocity += -25;//-18; + + if (dragVelocity < -50) + dragVelocity = -50; +/* ++currentLocation; + if (currentLocation >= numTrivia) + currentLocation = 0;//numTrivia-1; +*/ } + if (iphoneDrawPicWithTouch(411, y+60+16, 64, 64, "iphone/button_right.tga") ){//&& !dragVelocity) { + dragVelocity += 25;//18; + if (dragVelocity > 50) + dragVelocity = 50; +/* --currentLocation; + if (currentLocation < 0) + currentLocation = numTrivia-1;//0; +*/ } + + int width = 305; + int spacing = 100;//175; + int size = 160;//180;//110; + + iphoneUpdateTriviaAndInstructionsDrags(numTrivia, startPosition, y+25, size*2, size - 53, 10, &dragPosition, &dragVelocity ); //might as well use the same drag functionality in controlmenu + + int minSpeed = 20; + if ((dragVelocity < minSpeed && dragVelocity > 0) || (dragVelocity > -minSpeed && dragVelocity < 0)) + { + //Com_Printf("(dragPosition-startPosition)\%480 = %i\n", (dragPosition-startPosition)%480); + + if (abs((dragPosition-startPosition)%(width+spacing)) < 25) + { + dragVelocity = 0; + int tx = dragPosition - startPosition; + int n = tx/(width+spacing); + dragPosition = n*(width+spacing) + startPosition; + + } + else + { + if (dragVelocity < 0) + dragVelocity = -minSpeed; + else + dragVelocity = minSpeed; + } + //if ((dragPosition-startPosition)%480 == 0) + // dragVelocity = 0; + } + /* + if (dragVelocity == 0 ) + { + int diff = dragPosition - startPosition; + int n = diff/(width+spacing); + int nodePosition = n*(width+spacing); + + if ( diff != nodePosition ) + dragVelocity++; + }*/ + + //int upperLimit = startPosition + (numTrivia-1)*480; + int lowerLimit = startPosition - (numTrivia-1)*(width+spacing); + + + + + +// int x = 0; + y = 50; + int w = 305; + int h = 250; + colour4_t color = { 0, 0, 0, 255 }; + for (int i = 0; i < numTrivia; ++i) + {/* + if (i < currentLocation - 1) + continue; + if (i > currentLocation + 1) + continue;*/ +// x = dragPosition + 480*i; + /* + if (i == 0 && currentLocation == 0 && dragPosition < -480) + x = dragPosition + numTrivia*480; + else if (i == (numTrivia - 1) && currentLocation == (numTrivia - 1) && dragPosition > -480) + x = dragPosition - 480; + */ + /* + if ( x > upperLimit )//startPosition + (numTrivia-1)*480 ) + x -= numTrivia*480; + + if ( x < lowerLimit )//startPosition - (numTrivia-1)*480 ) + x += numTrivia*480; + */ + if (dragPosition > startPosition )//+480)//upperLimit )//startPosition + numTrivia*480) + dragPosition = lowerLimit;//startPosition; + + if (dragPosition < lowerLimit )//startPosition - numTrivia*480) + dragPosition = startPosition; + + x = dragPosition + (width+spacing)*i; + + if (x > 480 || x + width < 0) + continue; + + DrawBlendInBox( x, y, w, h, color, 71, 410-70); + //iphoneDrawTextInBox(RectMake(x, y+16, 16, 16), 410-70-32-16, triviaText[i], RectMake(71, 0, 320, 410-70)); + iphoneDrawArialTextInBox(RectMake(x, y+16, 16, 16), 410-70-32-16, triviaText[i], RectMake(71, 0, 320, 410-70)); + } +} +#endif + +//This is a different implementation of the one above +//gsh +void iphoneTriviaMenu() +{ + static int currentTrivia = 0; //this represents which trivia item we are currently supposed to be on + + static char triviaText[][1024] = { + " ORIGINAL WOLF:\n\nThe original release of Wolfenstein 3D only contained 3 Episodes. Episodes 4, 5, and 6 were sold separately as \"The Nocturnal Missions\", and were intended to act as a prequel to the original trilogy of Episodes. Subsequent releases of the game included all 6 Episodes together.", + " BJ, THE MAN:\n\nWilliam Joseph Blazkowicz was born August 15, 1911, to Polish immigrants. Blazkowicz was a top spy for the Allied Forces, eventually receiving the Congressional Medal of Honor.", + " BOX ART:\n\nKen Rieger was the talented illustrator who created the cover art for Spear of Destiny, Wolfenstein3D and Commander Keen.", + " THE REAL SPEAR:\n\nThe Spear of Destiny, also known as The Spear or The Holy Lance, is believed to have been the weapon used to pierce the side of Jesus Christ at the Crucifixion. The Spear soon became a symbol of God's favor and those who possessed it were believed to be invincible.", + " THE SPEAR AND HITLER:\n\nHitler is believed to have acquired the Spear at the beginning of WWII. Near the end of that war, it is rumored that General Patton discovered the Spear and that the downfall of Germany began that day. It is fabled that the U.S. was destined to succeed Germany as the New World Power once ownership of the Spear changed hands.", + " DEATH DIMENSION:\n\nIt is said that Hitler made a pact with the Angel of Death, promising the souls of his Nazi soldiers, to protect the Spear of Destiny.", + " GOD MODE:\n\nIn the game, if you can access god mode, BJ's eyes will glow with eerie golden light.", + " A PRINCE:\n\nRobert Prince, wrote the music for Commander Keen, Wolfenstein 3-D, and Doom.", + " DELAYED DEVELOPMENT:\n\nIt is rumored that work on Spear of Destiny was hindered by the development team's time spent playing Fatal Fury (which Jay Wilbur called 'Fatal Productivity'), and Street Fighter II.", + " A MATTER OF DEGREES:\n\nJohn Carmack is known for his innovations in 3D graphics and rocketry but what is less known is that this self-taught engineer has no degrees - he dropped out of school after one semester.", + " THE CARMACK:\n\nJohn Carmack, one of the founders of id Software, preferred to work at a pizza joint and make games rather than go to college. His favorite programming food is pizza and diet coke.", + " DREAMING IN DIGITAL:\n\nDoom was reported to cause gamers to dream in pixels and lower productivity.", + " KEEPING IT IN THE FAMILY:\n\nBJ is Commander Keen's grandfather.", + " WHAT'S IN A NAME:\n\nThe original name for Doom was \"It's Green and Pissed\"", + " GIBS:\n\nGibs, pronounced with a hard 'g', is sometimes confused as 'jibs' due to its pronunciation. The term came from the imagery of flying chicken giblets, or gibs for short.", + " WOLFENSTEIN 3D:\n\nThe game was originally designed to have more complex gameplay. Though dragging bodies, stealth kills and uniforms were already programmed, it was decided that they slowed down the pace of the game and were removed.", + " ORIGINAL WOLF:\n\nThe original release of Wolfenstein 3D only contained 3 Episodes. Episodes 4, 5, and 6 were sold separately as \"The Nocturnal Missions\", and were intended to act as a prequel to the original trilogy of Episodes. Subsequent releases of the game included all 6 Episodes together.", + }; + //get number of trivia + int numTrivia = sizeof(triviaText)/(sizeof(char) * 1024); + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + iphoneDrawPic(240-108*9/10, 0, 217*9/10, 50*9/10, "iphone/header_trivia.tga"); + + if (BackButton()) { + menuState = IPM_MORE; + return; + } + + if (MenuButton()) { + menuState = IPM_MAIN; + return; + } + + int startPosition = 85; + + //update the drags + static int Position = 85; + //static int Velocity = 0; + //static int currentLocation = 0; + // int y = 30; + + int y = 20; + int x = 0; + + static int moveRight = 0; + + //move right or left, depending on button pushed + if (iphoneDrawPicWithTouch(9, y+60+16, 64, 64, "iphone/button_left.tga") ) { + moveRight = 0; + ++currentTrivia; + if (currentTrivia > numTrivia-1) { + currentTrivia = 1; + + } + } + if (iphoneDrawPicWithTouch(411, y+60+16, 64, 64, "iphone/button_right.tga") ) { + moveRight = 1; + --currentTrivia; + if (currentTrivia < 0) { + currentTrivia = numTrivia-2; + } + } + + + int width = 305; + int spacing = 215;//175; + + int destinationPosition = startPosition - currentTrivia*(width+spacing); + int nearestTrivia = -(Position - startPosition)/(width+spacing); + + //if we are not where we are supposed to be... get us there + if (Position != destinationPosition) + { + Com_Printf("\n\nPosition: %i\n", Position); + Com_Printf("nearestTrivia: %i\n", nearestTrivia); + Com_Printf("currentTrivia: %i\n", currentTrivia); + Com_Printf("destinationPosition: %i\n", destinationPosition); + + + //now we must check for looping situations (where it would be faster to go backwards + + //this works great for traveling in a straight line without looping + + int oldPosition = Position; + int deltaPos = destinationPosition - Position; + /* + if (deltaPos > 0) + Position += 50; + else + Position -= 50; + */ + int moveDistance = 50; + + if ( moveRight )//!crossedOver )//currentTrivia - nearestTrivia >= 0)//abs(currentTrivia - nearestTrivia) > numTrivia/2) + { + //if (deltaPos < 0) + // moveDistance *= -1; + + Position += moveDistance; + + if (destinationPosition < Position && destinationPosition > oldPosition) + Position = destinationPosition; + } + else //if (currentTrivia - nearestTrivia < 0) + { + + //if (deltaPos > 0) + // moveDistance *= -1; + + Position -= moveDistance; + + if (destinationPosition > Position && destinationPosition < oldPosition) + Position = destinationPosition; + + } + + /* + //check if the current position has crossed over the destination position + if (destinationPosition < Position && destinationPosition > oldPosition) + Position = destinationPosition; + */ + + if ( abs(deltaPos) <= 100) + Position = destinationPosition; + } + + //int upperLimit = startPosition + (numTrivia-1)*480; + int lowerLimit = startPosition - (numTrivia-1)*(width+spacing); + + + + + + // int x = 0; + y = 50; + int w = 305; + int h = 250; + colour4_t color = { 0, 0, 0, 255 }; + colour4_t colorWhite = { 255, 255, 255, 255 }; + colour4_t colorGrey = { 100, 100, 100, 255 }; + for (int i = 0; i < numTrivia; ++i) + { + if (Position > startPosition )//+480)//upperLimit )//startPosition + numTrivia*480) + Position = lowerLimit;//startPosition; + + if (Position < lowerLimit )//startPosition - numTrivia*480) + Position = startPosition;// - (width+spacing); + + x = Position + (width+spacing)*i; + + if (x > 480 || x + width < 0) + continue; + + DrawBlendInBox( x-2, y-2, w+4, h+4, colorWhite, 71, 410-70); + DrawBlendInBox( x-1, y-1, w+2, h+2, colorGrey, 71, 410-70); + DrawBlendInBox( x, y, w, h, color, 71, 410-70); + //iphoneDrawTextInBox(RectMake(x, y+16, 16, 16), 410-70-32-16, triviaText[i], RectMake(71, 0, 320, 410-70)); + iphoneDrawArialTextInBox(RectMake(x, y+16, 16, 16), 410-70-32-16, triviaText[i], RectMake(71, 0, 320, 410-70)); + } +} + +//---------------------------------- +// iphoneMoreMenu +// gsh +//----------------------------------- +void iphoneMoreMenu() +{ + wasDLInstructionsCalledFromEpisodeMenu = 0; + + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + iphoneDrawPic(240-108*9/10, 0, 217*9/10, 50*9/10, "iphone/header_more.tga"); + + float scale = 40 / 32.0; + + if (BackButton()) { + menuState = IPM_MAIN; + } + + if (iphoneDrawPicWithTouch(240-64*scale, 120, 128*scale, 32*scale, "iphone/button_trivia.tga")) { + menuState = IPM_TRIVIA; + } + + if (iphoneDrawPicWithTouch(240-64*scale, 170, 128*scale, 32*scale, "iphone/button_downloads.tga")) { + menuState = IPM_DOWNLOADINSTRUCTIONS; + } +} + +//---------------------------------- +// iphoneDownloadInstructionsMenu +// gsh +//----------------------------------- +void iphoneDownloadInstructionsMenu() +{ + iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga"); + iphoneDrawPic(240-108*9/10, 0, 217*9/10, 50*9/10, "iphone/header_downloads.tga"); + + if (BackButton()) + { + menuState = IPM_MORE; + if (wasDLInstructionsCalledFromEpisodeMenu) + menuState = IPM_EPISODE; + + return; + } + + if (MenuButton()) { + menuState = IPM_MAIN; + return; + } + /* + if ( iphoneDrawPicWithTouch( 64, 0, 64, 36, "iphone/button_web.tga" ) ) { + wasCalledFromDownloadInstructionsMenu = 1; + iphoneYesNoBox("Website", "This will navigate you to idsoftware.com/iphone/wolf3dInstructions.html. Continue?"); + }*/ + + char instructions[] = "\nWolfenstein Platinum allows you to download additional game levels from the Internet." + //" For details, go to:\n\nhttp://www.idsoftware.com/iphone/\nwolf3dInstructions.html"; + " For details, go to:\n\nhttp://www.idsoftware.com/wolfenstein\n" + "-3d-classic-platinum/mapinstructions/"; + + int x = 20; + int y = 100; + int w = 480-40; + int h = 150; + colour4_t color = { 0, 0, 0, 255 }; + colour4_t colorGrey = { 100, 100, 100, 255 }; + colour4_t colorWhite = { 255, 255, 255, 255 }; + + + //draw a background, behind the text, with a white border + R_Draw_Blend( x-2, y-2, w+4, h+4, colorWhite); + R_Draw_Blend( x-1, y-1, w+2, h+2, colorGrey); + R_Draw_Blend( x, y, w, h, color); + + //draw arial text + iphoneDrawArialTextInBox(RectMake(x, y+16, 16, 16), 400, instructions, RectMake(10, 0, 480-40, 320)); + + //check for touch events on the text itself + int r = TouchReleased( x, y, w, h ); + if ( r ) { + wasCalledFromDownloadInstructionsMenu = 1; + iphoneYesNoBox("Website", "This will navigate you to idsoftware.com/wolfenstein-3d-classic-platinum/mapinstructions/ Continue?"); + } + if ( TouchDown( x, y, w, h ) ) { + colour4_t colorLight = { 255, 255, 255, 64 }; + R_Draw_Blend( x, y, w, h, colorLight ); + } } + + +//gsh +extern void iphoneSelectMapMenu(); +#if SPEARSTOREKIT +extern void iphoneStoreKit(); +#endif + void iphoneDrawMenus() { - iphoneDrawPic( 0, 0, 480, 320, "iphone/background_1.tga" ); +// iphoneDrawPic( 0, 0, 480, 320, "iphone/background_main_sepia.tga" ); + iphoneDrawPic( 0, 0, 480, 320, "iphone/background_main_hued.tga" ); //gsh switch ( menuState ) { case IPM_MAIN: iphoneMainMenu(); break; case IPM_SKILL: iphoneSkillMenu(); break; - case IPM_EPISODE: iphoneEpisodeMenu(); break; - case IPM_MAPS: iphoneMapMenu(); break; + case IPM_EPISODE: iphoneScrollingEpisodeMenu(); break;//gsh //iphoneEpisodeMenu(); break; + case IPM_MAPS: iphoneScrollingMapMenu(); break; //gsh iphoneMapMenu(); break; + // case IPM_MAPSELECTOR: iphoneSelectMapMenu(); break; //gsh case IPM_CONTROLS: iphoneControlMenu(); break; case IPM_INTERMISSION: iphoneIntermission(); break; case IPM_VICTORY: iphoneVictory(); break; case IPM_AUTOMAP: iphoneAutomap(); break; case IPM_STATS: iphoneStats(); break; - case IPM_HUDEDIT: HudEditFrame(); break; + case IPM_HUDEDIT: iphoneHudEditFrame(); break;//gsh HudEditFrame(); break; + case IPM_DOWNLOADPROGRESS: iphoneDownloadMenu(); break; //gsh +#if SPEARSTOREKIT + case IPM_STOREKIT: iphoneStoreKit(); break; //gsh +#endif +// case IPM_LOADING: iphoneLoadingMenu(); //gsh + case IPM_TRIVIA: iphoneTriviaMenu(); break;//gsh + case IPM_MORE: iphoneMoreMenu(); break;//gsh + case IPM_DOWNLOADINSTRUCTIONS: iphoneDownloadInstructionsMenu(); break; //gsh } } diff --git a/wolf3d/code/iphone/iphone_wolf.h b/wolf3d/code/iphone/iphone_wolf.h index ef1d43e..06f0290 100644 --- a/wolf3d/code/iphone/iphone_wolf.h +++ b/wolf3d/code/iphone/iphone_wolf.h @@ -23,7 +23,7 @@ //#define EPISODE_ONE_ONLY // this is the version number displayed on the menu screen -#define WOLF_IPHONE_VERSION 1.1 +#define WOLF_IPHONE_VERSION 1.2//1.1 extern viddef_t viddef; @@ -33,13 +33,19 @@ typedef enum menuState { IPM_SKILL, IPM_EPISODE, IPM_MAPS, + IPM_MAPSELECTOR, //gsh IPM_CONTROLS, IPM_INTERMISSION, IPM_VICTORY, IPM_AUTOMAP, IPM_STATS, - IPM_HUDEDIT - + IPM_HUDEDIT, + IPM_DOWNLOADPROGRESS, //gsh + IPM_STOREKIT, //gsh +// IPM_LOADING, //gsh + IPM_TRIVIA, //gsh + IPM_MORE, //gsh + IPM_DOWNLOADINSTRUCTIONS, //gsh } menuState_t; extern menuState_t menuState; @@ -51,7 +57,7 @@ void iphoneDrawMenus(); #define SAVEGAME_VERSION 108 #define MAX_SKILLS 4 -#define MAX_MAPS 60 +#define MAX_MAPS 81 //60 changed by gsh to allow for SOD levels #define MF_TRIED 1 #define MF_COMPLETED 2 @@ -69,15 +75,25 @@ typedef struct { int mapFlags[MAX_SKILLS][MAX_MAPS]; } currentMap_t; +//gsh +typedef struct { + int x; + int y; + int width; + int height; +} rect_t; +rect_t RectMake(int x, int y, int width, int height); + extern currentMap_t currentMap; void iphoneStartMap( int episodeNum, int mapNum, int skillLevel ); +void iphoneStartUserMap( int episodeNum, int mapNum, int skillLevel, char *mapName ); //gsh extern char iphoneDocDirectory[1024]; extern char iphoneAppDirectory[1024]; extern texture_t *numberPics[10]; -#define NUM_MUGSHOTS 23 +#define NUM_MUGSHOTS 26//23 extern char *mugshotnames[ NUM_MUGSHOTS ]; extern vec3_t vnull; @@ -100,6 +116,13 @@ extern cvar_t *tiltMove; extern cvar_t *tiltDeadBand; extern cvar_t *tiltAverages; extern cvar_t *tiltFire; +#ifdef VOLUMEHACK +extern cvar_t *volumeFireUp; //gsh +extern cvar_t *volumeFireDown; //gsh +extern cvar_t *volumeFireUpSetting; //gsh +extern cvar_t *volumeFireDownSetting; //gsh +#endif +extern cvar_t *hudAlpha; //gsh extern cvar_t *music; extern cvar_t *showTilt; extern cvar_t *showTime; @@ -115,6 +138,7 @@ extern cvar_t *autoFire; // the native iPhone code should set the following each frame: extern int numTouches; extern int touches[5][2]; // [0] = x, [1] = y in landscape mode, raster order with y = 0 at top +extern int isTouchMoving; //gsh extern float tilt; // -1.0 to 1.0 extern float tiltPitch; @@ -135,6 +159,14 @@ void LoadWallTexture( int wallPicNum ); int TouchDown( int x, int y, int w, int h ); int TouchReleased( int x, int y, int w, int h ); int iphoneCenterText( int x, int y, const char *str ); +void iphoneCenterTextWithColor( int x, int y, const char *str, colour4_t color ); //gsh +int iphoneDrawText( int x, int y, int width, int height, const char *str ); //gsh +int iphoneDrawArialText( int x, int y, float scale, const char *str ); //gsh +int iphoneCenterArialText( int x, int y, float scale, const char *str ); //gsh +int iphoneDrawArialTextInBox( rect_t paragraph, int lineLength, const char *str, rect_t boxRect ); //gsh +void iphoneDrawTextWithColor( rect_t rect, const char *str, float colors[4] ); //gsh +void iphoneDrawMapName( rect_t rect, const char *str ); //gsh +int iphoneDrawTextInBox( rect_t paragraph, int lineLength, const char *str, rect_t boxRect ); //gsh void iphoneDrawNumber( int x, int y, int number, int charWidth, int charHeight ); void iphoneDrawPic( int x, int y, int w, int h, const char *pic ); int iphoneDrawPicWithTouch( int x, int y, int w, int h, const char *pic ); @@ -166,6 +198,12 @@ typedef struct { int width, height; int glTexNum; int hudFlags; + int drawWidth, drawHeight; //from here down (in the struct) is from doom iphone... gsh + int touchWidth, touchHeight; + texture_t *texture; + bool drawAsLimit; + float touchState; + //struct touch_s *touch; } hudPic_t; //#define ALLOW_MAP_VIEW_HUD @@ -188,6 +226,7 @@ extern hud_t huds; void HudSetForScheme( int schemeNum ); void HudSetTexnums(); void HudEditFrame(); +void iphoneHudEditFrame(); @@ -199,6 +238,7 @@ void iphoneStartDamageFlash( int points ); void iphoneSetAttackDirection( int dir ); void iphoneStartIntermission( int framesFromNow ); void iphoneSetNotifyText( const char *str, ... ); +void iphoneSetLevelNotifyText(); //gsh //--------------------------------------- // interfaces to Objective-C land diff --git a/wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.mode1v3 b/wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.mode1v3 new file mode 100644 index 0000000..6f7c124 --- /dev/null +++ b/wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.mode1v3 @@ -0,0 +1,1409 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + ED0A8D011069AA54001E0547 + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-combo-popup + action + NSToolbarFlexibleSpaceItem + build-and-go + com.apple.ide.PBXToolbarStopButton + get-info + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 29B97315FDCFA39411CA2CEA + 29B97317FDCFA39411CA2CEA + 29B97323FDCFA39411CA2CEA + 19C28FACFE9D520D11CA2CBB + 1C37FBAC04509CD000000102 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 32 + 27 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 720}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 738}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 391 174 1010 779 0 0 1680 1028 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + Info.plist + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + Info.plist + _historyCapacity + 0 + bookmark + ED45402710B21F0900DCFA32 + history + + ED2E5C05106C886700F57B9D + ED2E5C06106C886700F57B9D + ED4AC98010742365000706D8 + EDDA5A7E107BA97F003F55D3 + EDDA5A80107BA97F003F55D3 + ED2754531085141B009C891E + ED0653B61087719F00E5450B + EDAFC5A2109A14EE002C3487 + ED845AB1109F5B3500F673AC + ED45402110B21F0900DCFA32 + ED45402210B21F0900DCFA32 + ED45402310B21F0900DCFA32 + ED845AB2109F5B3500F673AC + + prevStack + + ED3703CD106C20620059C5F8 + ED2E5C0A106C886700F57B9D + ED2E5C0B106C886700F57B9D + ED4AC98210742365000706D8 + ED4AC9AB10743318000706D8 + ED4AC9AC10743318000706D8 + EDDA5A82107BA97F003F55D3 + EDDA5A83107BA97F003F55D3 + EDDA5A84107BA97F003F55D3 + ED2754551085141B009C891E + ED2754561085141B009C891E + ED0653B81087719F00E5450B + ED45402410B21F0900DCFA32 + ED45402510B21F0900DCFA32 + ED45402610B21F0900DCFA32 + + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {802, 686}} + RubberWindowFrame + 391 174 1010 779 0 0 1680 1028 + + Module + PBXNavigatorGroup + Proportion + 686pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 691}, {802, 47}} + RubberWindowFrame + 391 174 1010 779 0 0 1680 1028 + + Module + XCDetailModule + Proportion + 47pt + + + Proportion + 802pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + ED45402810B21F0900DCFA32 + 1CE0B1FE06471DED0097A5F4 + ED45402910B21F0900DCFA32 + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.shortV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + /Users/greghodges/wolf3dplatinum/wolf3d/code/iphone/wolf3d.xcodeproj + + WindowString + 391 174 1010 779 0 0 1680 1028 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {500, 218}} + RubberWindowFrame + 56 488 500 500 0 0 1680 1028 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 223}, {500, 236}} + RubberWindowFrame + 56 488 500 500 0 0 1680 1028 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 459pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + ED0A8CF61069A9E0001E0547 + EDAFC5AA109A14EE002C3487 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowString + 56 488 500 500 0 0 1680 1028 + WindowToolGUID + ED0A8CF61069A9E0001E0547 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {316, 203}} + {{316, 0}, {378, 203}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 203}} + {{0, 203}, {694, 178}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 381}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 148 + + Frame + {{316, 0}, {378, 203}} + RubberWindowFrame + 150 519 694 422 0 0 1680 1028 + + RubberWindowFrame + 150 519 694 422 0 0 1680 1028 + + Module + PBXDebugSessionModule + Proportion + 381pt + + + Proportion + 381pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + EDAFC5AB109A14EE002C3487 + 1C162984064C10D400B95A72 + EDAFC5AC109A14EE002C3487 + EDAFC5AD109A14EE002C3487 + EDAFC5AE109A14EE002C3487 + EDAFC5AF109A14EE002C3487 + EDAFC5B0109A14EE002C3487 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 150 519 694 422 0 0 1680 1028 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.find + IsVertical + + Layout + + + Dock + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + iphone_menus.c + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {1122, 588}} + RubberWindowFrame + 450 88 1122 866 0 0 1680 1028 + + Module + PBXNavigatorGroup + Proportion + 1122pt + + + Proportion + 588pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{0, 593}, {1122, 232}} + RubberWindowFrame + 450 88 1122 866 0 0 1680 1028 + + Module + PBXProjectFindModule + Proportion + 232pt + + + Proportion + 825pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + + TableOfContents + + 1C530D57069F1CE1000CFCEE + EDAFC5B1109A14EE002C3487 + EDAFC5B2109A14EE002C3487 + 1CDD528C0622207200134675 + 1CD0528E0623707200166675 + + WindowString + 450 88 1122 866 0 0 1680 1028 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {650, 209}} + RubberWindowFrame + 450 704 650 250 0 0 1680 1028 + + Module + PBXDebugCLIModule + Proportion + 209pt + + + Proportion + 209pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + EDAFC5B3109A14EE002C3487 + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 450 704 650 250 0 0 1680 1028 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.0950012207031 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 743 379 452 308 0 0 1280 1002 + + + Identifier + windowTool.breakpoints + IsVertical + 0 + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 0 + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + WindowString + 315 424 744 409 0 0 1440 878 + WindowToolGUID + 1CDDB66807F98D9800BB5817 + WindowToolIsVisible + 1 + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + 1 + ToolbarConfiguration + xcode.toolbar.config.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {374, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 331}} + MembersFrame + {{0, 105}, {374, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 97 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 385 179 630 352 0 0 1440 878 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 1C0AD2B0069F1E9B00FABCE6 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 385 179 630 352 0 0 1440 878 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + 0 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.pbxuser b/wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.pbxuser new file mode 100644 index 0000000..839a542 --- /dev/null +++ b/wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.pbxuser @@ -0,0 +1,578 @@ +// !$*UTF8*$! +{ + 1D6058900D05DD3D006BFB54 /* wolf3d */ = { + activeExec = 0; + executables = ( + ED0A8CE41069A9CF001E0547 /* wolf3d */, + ); + }; + 29B97313FDCFA39411CA2CEA /* Project object */ = { + activeBuildConfigurationName = Release; + activeExecutable = ED0A8CE41069A9CF001E0547 /* wolf3d */; + activeSDKPreference = iphonesimulator2.0; + activeTarget = 1D6058900D05DD3D006BFB54 /* wolf3d */; + addToTargets = ( + 1D6058900D05DD3D006BFB54 /* wolf3d */, + ); + codeSenseManager = ED0A8CFA1069A9F5001E0547 /* Code sense */; + executables = ( + ED0A8CE41069A9CF001E0547 /* wolf3d */, + ); + perUserDictionary = { + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 563, + 20, + 48, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 523, + 60, + 20, + 48, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 280108689; + PBXWorkspaceStateSaveDate = 280108689; + }; + perUserProjectItems = { + ED0653B61087719F00E5450B /* PBXTextBookmark */ = ED0653B61087719F00E5450B /* PBXTextBookmark */; + ED0653B81087719F00E5450B /* PBXTextBookmark */ = ED0653B81087719F00E5450B /* PBXTextBookmark */; + ED2754531085141B009C891E /* PBXTextBookmark */ = ED2754531085141B009C891E /* PBXTextBookmark */; + ED2754551085141B009C891E /* PlistBookmark */ = ED2754551085141B009C891E /* PlistBookmark */; + ED2754561085141B009C891E /* PBXTextBookmark */ = ED2754561085141B009C891E /* PBXTextBookmark */; + ED2E5C05106C886700F57B9D /* PBXTextBookmark */ = ED2E5C05106C886700F57B9D /* PBXTextBookmark */; + ED2E5C06106C886700F57B9D /* PBXTextBookmark */ = ED2E5C06106C886700F57B9D /* PBXTextBookmark */; + ED2E5C0A106C886700F57B9D /* PBXTextBookmark */ = ED2E5C0A106C886700F57B9D /* PBXTextBookmark */; + ED2E5C0B106C886700F57B9D /* PBXTextBookmark */ = ED2E5C0B106C886700F57B9D /* PBXTextBookmark */; + ED3703CD106C20620059C5F8 /* PlistBookmark */ = ED3703CD106C20620059C5F8 /* PlistBookmark */; + ED45402110B21F0900DCFA32 /* PBXTextBookmark */ = ED45402110B21F0900DCFA32 /* PBXTextBookmark */; + ED45402210B21F0900DCFA32 /* PBXTextBookmark */ = ED45402210B21F0900DCFA32 /* PBXTextBookmark */; + ED45402310B21F0900DCFA32 /* PBXTextBookmark */ = ED45402310B21F0900DCFA32 /* PBXTextBookmark */; + ED45402410B21F0900DCFA32 /* PBXTextBookmark */ = ED45402410B21F0900DCFA32 /* PBXTextBookmark */; + ED45402510B21F0900DCFA32 /* PBXTextBookmark */ = ED45402510B21F0900DCFA32 /* PBXTextBookmark */; + ED45402610B21F0900DCFA32 /* PBXTextBookmark */ = ED45402610B21F0900DCFA32 /* PBXTextBookmark */; + ED45402710B21F0900DCFA32 /* PlistBookmark */ = ED45402710B21F0900DCFA32 /* PlistBookmark */; + ED4AC98010742365000706D8 /* PBXTextBookmark */ = ED4AC98010742365000706D8 /* PBXTextBookmark */; + ED4AC98210742365000706D8 /* PBXTextBookmark */ = ED4AC98210742365000706D8 /* PBXTextBookmark */; + ED4AC9AB10743318000706D8 /* PBXTextBookmark */ = ED4AC9AB10743318000706D8 /* PBXTextBookmark */; + ED4AC9AC10743318000706D8 /* PBXTextBookmark */ = ED4AC9AC10743318000706D8 /* PBXTextBookmark */; + ED845AB1109F5B3500F673AC /* PBXTextBookmark */ = ED845AB1109F5B3500F673AC /* PBXTextBookmark */; + ED845AB2109F5B3500F673AC /* PlistBookmark */ = ED845AB2109F5B3500F673AC /* PlistBookmark */; + EDAFC5A2109A14EE002C3487 /* PBXTextBookmark */ = EDAFC5A2109A14EE002C3487 /* PBXTextBookmark */; + EDDA5A7E107BA97F003F55D3 /* PBXTextBookmark */ = EDDA5A7E107BA97F003F55D3 /* PBXTextBookmark */; + EDDA5A80107BA97F003F55D3 /* PBXTextBookmark */ = EDDA5A80107BA97F003F55D3 /* PBXTextBookmark */; + EDDA5A82107BA97F003F55D3 /* PBXTextBookmark */ = EDDA5A82107BA97F003F55D3 /* PBXTextBookmark */; + EDDA5A83107BA97F003F55D3 /* PBXTextBookmark */ = EDDA5A83107BA97F003F55D3 /* PBXTextBookmark */; + EDDA5A84107BA97F003F55D3 /* PBXTextBookmark */ = EDDA5A84107BA97F003F55D3 /* PBXTextBookmark */; + }; + sourceControlManager = ED0A8CF91069A9F5001E0547 /* Source Control */; + userBuildSettings = { + }; + }; + 43AF6B940F996DA200777569 /* iphone_sys.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {852, 1050}}"; + sepNavSelRange = "{1419, 24}"; + sepNavVisRange = "{771, 1684}"; + }; + }; + 43CF03090F56D5C200E4A23D /* iphone_loop.c */ = { + uiCtxt = { + sepNavFolds = "{\n c = (\n {\n l = \"int y\";\n r = \"{41674, 9}\";\n s = 1;\n },\n {\n l = \"int width\";\n r = \"{41685, 13}\";\n s = 1;\n },\n {\n l = \"int height\";\n r = \"{41700, 14}\";\n s = 1;\n },\n {\n l = \"const char * str\";\n r = \"{41716, 20}\";\n s = 1;\n }\n );\n r = \"{0, 41792}\";\n s = 0;\n}"; + sepNavIntBoundsRect = "{{0, 0}, {1061, 24388}}"; + sepNavSelRange = "{27221, 8}"; + sepNavVisRange = "{26941, 622}"; + }; + }; + 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 5418}}"; + sepNavSelRange = "{1413, 4}"; + sepNavVisRange = "{970, 956}"; + }; + }; + 7229CC270F6B3222004123C5 /* wolf_actors.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 6398}}"; + sepNavSelRange = "{84, 0}"; + sepNavVisRange = "{0, 1418}"; + }; + }; + 7229CC8E0F6B3363004123C5 /* wolfiphone.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 1260}}"; + sepNavSelRange = "{1906, 27}"; + sepNavVisRange = "{812, 1122}"; + }; + }; + 7229CE460F6C89F8004123C5 /* EAGLView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {786, 6650}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{10594, 1878}"; + }; + }; + 7229CE480F6C89F8004123C5 /* wolf3dAppDelegate.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 654}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1205}"; + }; + }; + 7229CE490F6C89F8004123C5 /* wolf3dAppDelegate.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1074, 5012}}"; + sepNavSelRange = "{3930, 0}"; + sepNavVisRange = "{5119, 1271}"; + }; + }; + 72935B1E0F6B2D9D0085DD28 /* arch.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 3808}}"; + sepNavSelRange = "{2579, 0}"; + sepNavVisRange = "{2465, 1040}"; + }; + }; + 72935B630F6B2D9D0085DD28 /* tga.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 10822}}"; + sepNavSelRange = "{1562, 2}"; + sepNavVisRange = "{1162, 856}"; + }; + }; + 72A7E8F30F5F2001005B83C0 /* iphone_wolf.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 3850}}"; + sepNavSelRange = "{1009, 0}"; + sepNavVisRange = "{0, 1316}"; + }; + }; + 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {900, 56714}}"; + sepNavSelRange = "{66944, 0}"; + sepNavVisRange = "{62588, 1640}"; + }; + }; + ED0653B61087719F00E5450B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43AF6B940F996DA200777569 /* iphone_sys.m */; + name = "iphone_sys.m: 40"; + rLen = 24; + rLoc = 1419; + rType = 0; + vrLen = 1684; + vrLoc = 771; + }; + ED0653B81087719F00E5450B /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43AF6B940F996DA200777569 /* iphone_sys.m */; + name = "iphone_sys.m: 40"; + rLen = 24; + rLoc = 1419; + rType = 0; + vrLen = 1684; + vrLoc = 771; + }; + ED0A8CE41069A9CF001E0547 /* wolf3d */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 0; + configStateDict = { + }; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = wolf3d; + savedGlobals = { + }; + sourceDirectories = ( + ); + variableFormatDictionary = { + }; + }; + ED0A8CF91069A9F5001E0547 /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + }; + }; + ED0A8CFA1069A9F5001E0547 /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + ED0A8D0D1069ACA8001E0547 /* iphone_downloadSOD.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 7434}}"; + sepNavSelRange = "{1756, 0}"; + sepNavVisRange = "{1108, 1549}"; + }; + }; + ED0A8D0F1069ACA8001E0547 /* iphone_mapselector.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {948, 6706}}"; + sepNavSelRange = "{7865, 0}"; + sepNavVisRange = "{1577, 1229}"; + }; + }; + ED0A8D101069ACA8001E0547 /* iphone_store.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 654}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1253}"; + }; + }; + ED0A8D111069ACA8001E0547 /* iphone_store.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {741, 5964}}"; + sepNavSelRange = "{673, 17}"; + sepNavVisRange = "{0, 1394}"; + }; + }; + ED2754531085141B009C891E /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + name = "EAGLView.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1878; + vrLoc = 10594; + }; + ED2754551085141B009C891E /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + UIPrerenderedIcon, + ); + name = /Users/greghodges/wolf3dplatinum/wolf3d/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + ED2754561085141B009C891E /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE460F6C89F8004123C5 /* EAGLView.m */; + name = "EAGLView.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1878; + vrLoc = 10594; + }; + ED2E5C05106C886700F57B9D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED0A8D0D1069ACA8001E0547 /* iphone_downloadSOD.m */; + name = "iphone_downloadSOD.m: 61"; + rLen = 0; + rLoc = 1756; + rType = 0; + vrLen = 1549; + vrLoc = 1108; + }; + ED2E5C06106C886700F57B9D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED2E5C07106C886700F57B9D /* OpenTGA.c */; + name = "OpenTGA.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 722; + vrLoc = 12240; + }; + ED2E5C07106C886700F57B9D /* OpenTGA.c */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = OpenTGA.c; + path = /Users/greghodges/Desktop/MyTGAConverter/OpenTGA.c; + sourceTree = ""; + }; + ED2E5C0A106C886700F57B9D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED0A8D0D1069ACA8001E0547 /* iphone_downloadSOD.m */; + name = "iphone_downloadSOD.m: 61"; + rLen = 0; + rLoc = 1756; + rType = 0; + vrLen = 1549; + vrLoc = 1108; + }; + ED2E5C0B106C886700F57B9D /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED2E5C0C106C886700F57B9D /* OpenTGA.c */; + name = "OpenTGA.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 722; + vrLoc = 12240; + }; + ED2E5C0C106C886700F57B9D /* OpenTGA.c */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = OpenTGA.c; + path = /Users/greghodges/Desktop/MyTGAConverter/OpenTGA.c; + sourceTree = ""; + }; + ED3703CD106C20620059C5F8 /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = ED3703CE106C20620059C5F8; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + rLen = 0; + rLoc = 2147483647; + }; + ED3703CE106C20620059C5F8 = { + isa = PBXFileReference; + lastKnownFileType = folder; + sourceTree = ""; + }; + ED45402110B21F0900DCFA32 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CC270F6B3222004123C5 /* wolf_actors.c */; + name = "wolf_actors.c: 5"; + rLen = 0; + rLoc = 84; + rType = 0; + vrLen = 1418; + vrLoc = 0; + }; + ED45402210B21F0900DCFA32 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE490F6C89F8004123C5 /* wolf3dAppDelegate.m */; + name = "wolf3dAppDelegate.m: 124"; + rLen = 0; + rLoc = 3930; + rType = 0; + vrLen = 1271; + vrLoc = 5119; + }; + ED45402310B21F0900DCFA32 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE480F6C89F8004123C5 /* wolf3dAppDelegate.h */; + name = "wolf3dAppDelegate.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1205; + vrLoc = 0; + }; + ED45402410B21F0900DCFA32 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CC270F6B3222004123C5 /* wolf_actors.c */; + name = "wolf_actors.c: 5"; + rLen = 0; + rLoc = 84; + rType = 0; + vrLen = 1418; + vrLoc = 0; + }; + ED45402510B21F0900DCFA32 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE490F6C89F8004123C5 /* wolf3dAppDelegate.m */; + name = "wolf3dAppDelegate.m: 124"; + rLen = 0; + rLoc = 3930; + rType = 0; + vrLen = 1271; + vrLoc = 5119; + }; + ED45402610B21F0900DCFA32 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE480F6C89F8004123C5 /* wolf3dAppDelegate.h */; + name = "wolf3dAppDelegate.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1205; + vrLoc = 0; + }; + ED45402710B21F0900DCFA32 /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + UIPrerenderedIcon, + ); + name = /Users/greghodges/wolf3dplatinum/wolf3d/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + ED4AC98010742365000706D8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = EDD56B7E10740B7A007C0E16 /* ConvertTGA.c */; + name = "ConvertTGA.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1082; + vrLoc = 18055; + }; + ED4AC98210742365000706D8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = EDD56B7E10740B7A007C0E16 /* ConvertTGA.c */; + name = "ConvertTGA.c: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1082; + vrLoc = 18055; + }; + ED4AC9AB10743318000706D8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 7229CE490F6C89F8004123C5 /* wolf3dAppDelegate.m */; + name = "wolf3dAppDelegate.m: 124"; + rLen = 0; + rLoc = 3930; + rType = 0; + vrLen = 1417; + vrLoc = 3274; + }; + ED4AC9AC10743318000706D8 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 1111"; + rLen = 13; + rLoc = 31543; + rType = 0; + vrLen = 2083; + vrLoc = 30775; + }; + ED845AB1109F5B3500F673AC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; + name = "iphone_menus.c: 2407"; + rLen = 0; + rLoc = 66944; + rType = 0; + vrLen = 1640; + vrLoc = 62588; + }; + ED845AB2109F5B3500F673AC /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D1107310486CEB800E47090 /* Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + UIPrerenderedIcon, + ); + name = /Users/greghodges/wolf3dplatinum/wolf3d/code/iphone/Info.plist; + rLen = 0; + rLoc = 2147483647; + }; + EDAFC5A2109A14EE002C3487 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 50"; + rLen = 4; + rLoc = 1413; + rType = 0; + vrLen = 956; + vrLoc = 970; + }; + EDD56B7E10740B7A007C0E16 /* ConvertTGA.c */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = ConvertTGA.c; + path = /Users/greghodges/Desktop/MyTGAConverter/ConvertTGA.c; + sourceTree = ""; + }; + EDDA5A7E107BA97F003F55D3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 1226"; + rLen = 0; + rLoc = 28766; + rType = 0; + vrLen = 942; + vrLoc = 28216; + }; + EDDA5A80107BA97F003F55D3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED0A8D0F1069ACA8001E0547 /* iphone_mapselector.c */; + name = "iphone_mapselector.c: 341"; + rLen = 0; + rLoc = 7865; + rType = 0; + vrLen = 1229; + vrLoc = 1577; + }; + EDDA5A82107BA97F003F55D3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43CF03090F56D5C200E4A23D /* iphone_loop.c */; + name = "iphone_loop.c: 1226"; + rLen = 0; + rLoc = 28766; + rType = 0; + vrLen = 942; + vrLoc = 28216; + }; + EDDA5A83107BA97F003F55D3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43E8D2DF0F4FC61E003F09B2 /* iphone_main.c */; + name = "iphone_main.c: 272"; + rLen = 0; + rLoc = 7878; + rType = 0; + vrLen = 1550; + vrLoc = 7519; + }; + EDDA5A84107BA97F003F55D3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = ED0A8D0F1069ACA8001E0547 /* iphone_mapselector.c */; + name = "iphone_mapselector.c: 341"; + rLen = 0; + rLoc = 7865; + rType = 0; + vrLen = 1229; + vrLoc = 1577; + }; +} diff --git a/wolf3d/code/iphone/wolf3d.xcodeproj/project.pbxproj b/wolf3d/code/iphone/wolf3d.xcodeproj/project.pbxproj index 164064a..2192ff2 100644 --- a/wolf3d/code/iphone/wolf3d.xcodeproj/project.pbxproj +++ b/wolf3d/code/iphone/wolf3d.xcodeproj/project.pbxproj @@ -95,11 +95,17 @@ 72935BA20F6B2D9D0085DD28 /* zmem.c in Sources */ = {isa = PBXBuildFile; fileRef = 72935B720F6B2D9D0085DD28 /* zmem.c */; }; 72A7E8F70F5F2063005B83C0 /* iphone_menus.c in Sources */ = {isa = PBXBuildFile; fileRef = 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */; }; 72B5FF390F7E5C3D00C8A372 /* hud.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B5FF380F7E5C3D00C8A372 /* hud.c */; }; + ED0A8D121069ACA8001E0547 /* iphone_alerts.m in Sources */ = {isa = PBXBuildFile; fileRef = ED0A8D0C1069ACA8001E0547 /* iphone_alerts.m */; }; + ED0A8D131069ACA8001E0547 /* iphone_downloadSOD.m in Sources */ = {isa = PBXBuildFile; fileRef = ED0A8D0D1069ACA8001E0547 /* iphone_downloadSOD.m */; }; + ED0A8D141069ACA8001E0547 /* iphone_downloadUserMap.m in Sources */ = {isa = PBXBuildFile; fileRef = ED0A8D0E1069ACA8001E0547 /* iphone_downloadUserMap.m */; }; + ED0A8D151069ACA8001E0547 /* iphone_mapselector.c in Sources */ = {isa = PBXBuildFile; fileRef = ED0A8D0F1069ACA8001E0547 /* iphone_mapselector.c */; }; + ED0A8D161069ACA8001E0547 /* iphone_store.m in Sources */ = {isa = PBXBuildFile; fileRef = ED0A8D111069ACA8001E0547 /* iphone_store.m */; }; + ED3703B4106C1CD40059C5F8 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED3703B3106C1CD40059C5F8 /* SystemConfiguration.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 1D6058910D05DD3D006BFB54 /* wolf3dlite.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = wolf3dlite.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1D6058910D05DD3D006BFB54 /* wolf3d.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = wolf3d.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 28FD14FF0DC6FC520079059D /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; @@ -257,6 +263,15 @@ 72A7E8F60F5F2063005B83C0 /* iphone_menus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_menus.c; sourceTree = ""; }; 72B5FF380F7E5C3D00C8A372 /* hud.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hud.c; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + ED0A8D0A1069ACA8001E0547 /* arialGlyphRects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arialGlyphRects.h; sourceTree = ""; }; + ED0A8D0B1069ACA8001E0547 /* iphone_alerts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_alerts.h; sourceTree = ""; }; + ED0A8D0C1069ACA8001E0547 /* iphone_alerts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iphone_alerts.m; sourceTree = ""; }; + ED0A8D0D1069ACA8001E0547 /* iphone_downloadSOD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iphone_downloadSOD.m; sourceTree = ""; }; + ED0A8D0E1069ACA8001E0547 /* iphone_downloadUserMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iphone_downloadUserMap.m; sourceTree = ""; }; + ED0A8D0F1069ACA8001E0547 /* iphone_mapselector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iphone_mapselector.c; sourceTree = ""; }; + ED0A8D101069ACA8001E0547 /* iphone_store.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iphone_store.h; sourceTree = ""; }; + ED0A8D111069ACA8001E0547 /* iphone_store.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iphone_store.m; sourceTree = ""; }; + ED3703B3106C1CD40059C5F8 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -271,6 +286,7 @@ 4333CCE80F5CC23E00AE2B6F /* AudioToolbox.framework in Frameworks */, 43AE7E9F0F67387500B2F562 /* CoreGraphics.framework in Frameworks */, 720EBBAE0F82E0BB003F989A /* QuartzCore.framework in Frameworks */, + ED3703B4106C1CD40059C5F8 /* SystemConfiguration.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -280,7 +296,7 @@ 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( - 1D6058910D05DD3D006BFB54 /* wolf3dlite.app */, + 1D6058910D05DD3D006BFB54 /* wolf3d.app */, 4364BF3E0F5CB25900F29317 /* dist.plist */, ); name = Products; @@ -301,6 +317,14 @@ 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( + ED0A8D0A1069ACA8001E0547 /* arialGlyphRects.h */, + ED0A8D0B1069ACA8001E0547 /* iphone_alerts.h */, + ED0A8D0C1069ACA8001E0547 /* iphone_alerts.m */, + ED0A8D0D1069ACA8001E0547 /* iphone_downloadSOD.m */, + ED0A8D0E1069ACA8001E0547 /* iphone_downloadUserMap.m */, + ED0A8D0F1069ACA8001E0547 /* iphone_mapselector.c */, + ED0A8D101069ACA8001E0547 /* iphone_store.h */, + ED0A8D111069ACA8001E0547 /* iphone_store.m */, 72935B180F6B2D630085DD28 /* env */, 7229CC5A0F6B324A004123C5 /* tremor */, 72935B190F6B2D720085DD28 /* wolf */, @@ -337,6 +361,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + ED3703B3106C1CD40059C5F8 /* SystemConfiguration.framework */, 720EBBAD0F82E0BB003F989A /* QuartzCore.framework */, 4333CCE70F5CC23E00AE2B6F /* AudioToolbox.framework */, 43E8D4DF0F51B48B003F09B2 /* OpenAL.framework */, @@ -517,7 +542,7 @@ ); name = wolf3d; productName = wolf3d; - productReference = 1D6058910D05DD3D006BFB54 /* wolf3dlite.app */; + productReference = 1D6058910D05DD3D006BFB54 /* wolf3d.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -649,6 +674,11 @@ 7229CE550F6C8CDE004123C5 /* gles_glue.c in Sources */, 72B5FF390F7E5C3D00C8A372 /* hud.c in Sources */, 43AF6B950F996DA200777569 /* iphone_sys.m in Sources */, + ED0A8D121069ACA8001E0547 /* iphone_alerts.m in Sources */, + ED0A8D131069ACA8001E0547 /* iphone_downloadSOD.m in Sources */, + ED0A8D141069ACA8001E0547 /* iphone_downloadUserMap.m in Sources */, + ED0A8D151069ACA8001E0547 /* iphone_mapselector.c in Sources */, + ED0A8D161069ACA8001E0547 /* iphone_store.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -678,7 +708,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Cass Everitt"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = wolf3d_Prefix.pch; @@ -687,7 +717,7 @@ INFOPLIST_FILE = Info.plist; PRODUCT_NAME = wolf3d; PROFILE_PREFIX = nu.r3; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "94041F5C-2EDC-4F49-AF97-95ECE6BB398D"; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "156B7F53-1BDC-4116-B0CC-F8CB2252E722"; }; name = Release; }; @@ -766,12 +796,13 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; GCC_C_LANGUAGE_STANDARD = c99; GCC_THUMB_SUPPORT = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "156B7F53-1BDC-4116-B0CC-F8CB2252E722"; SDKROOT = iphoneos2.0; SYMROOT = ../../build; }; @@ -781,7 +812,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Cass Everitt"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = wolf3d_Prefix.pch; @@ -793,7 +824,7 @@ INFOPLIST_FILE = Info.plist; PRODUCT_NAME = wolf3dlite; PROFILE_PREFIX = nu.r3; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "94041F5C-2EDC-4F49-AF97-95ECE6BB398D"; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "156B7F53-1BDC-4116-B0CC-F8CB2252E722"; }; name = ReleaseLite; }; @@ -853,17 +884,51 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: John Carmack"; GCC_C_LANGUAGE_STANDARD = c99; GCC_THUMB_SUPPORT = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "156B7F53-1BDC-4116-B0CC-F8CB2252E722"; SDKROOT = iphoneos2.0; SYMROOT = ../../build; }; name = Release; }; + ED2751531083BE8C009C891E /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: id Software"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_THUMB_SUPPORT = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "31C73095-0DD9-4ABA-BB25-8D23F661F10F"; + SDKROOT = iphoneos2.0; + SYMROOT = ../../build; + }; + name = Distribution; + }; + ED2751541083BE8C009C891E /* Distribution */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: id Software"; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = wolf3d_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = IPHONE; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + PRODUCT_NAME = wolf3d; + PROFILE_PREFIX = nu.r3; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "31C73095-0DD9-4ABA-BB25-8D23F661F10F"; + }; + name = Distribution; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -876,6 +941,7 @@ 43AE7CA50F61EC4E00B2F562 /* ReleaseLite */, 4364BF490F5CB27300F29317 /* AdHocDist */, 431181710F994C5400FF9351 /* AdHocDistLite */, + ED2751541083BE8C009C891E /* Distribution */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -889,6 +955,7 @@ 43AE7CA40F61EC4E00B2F562 /* ReleaseLite */, 4364BF480F5CB27300F29317 /* AdHocDist */, 431181700F994C5400FF9351 /* AdHocDistLite */, + ED2751531083BE8C009C891E /* Distribution */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/wolf3d/code/iphone/wolf3dAppDelegate.h b/wolf3d/code/iphone/wolf3dAppDelegate.h index 96e6653..3a14087 100644 --- a/wolf3d/code/iphone/wolf3dAppDelegate.h +++ b/wolf3d/code/iphone/wolf3dAppDelegate.h @@ -24,10 +24,12 @@ @class EAGLView; -@interface wolf3dAppDelegate : NSObject { +@interface wolf3dAppDelegate : NSObject { UIWindow *window; EAGLView *glView; int lastAccelUpdateMsec; + +// UIAlertView *alertPurchaseSpear; } @property (nonatomic, retain) IBOutlet UIWindow *window; diff --git a/wolf3d/code/iphone/wolf3dAppDelegate.m b/wolf3d/code/iphone/wolf3dAppDelegate.m index 4c030e6..64073aa 100644 --- a/wolf3d/code/iphone/wolf3dAppDelegate.m +++ b/wolf3d/code/iphone/wolf3dAppDelegate.m @@ -22,6 +22,36 @@ #import "EAGLView.h" #import #include "../wolfiphone.h" +#include + +//added for downloading SOD content from the internet... added by gsh +extern void Com_Printf(const char* fmt, ... ); +//extern void AppendData(NSData* data); +extern void AppendDataToFile(NSData* data); +extern void AppendUserDataToFile(NSData* data); +//extern void SaveData(); + +//used for downloading custom made map +extern void FinalizeUserDownload(); + +#if SPEARSTOREKIT +//was used for storekit +extern void FinalizeDownload(); +extern int IsSpearPurchased(); +extern int IsSpearInstalled(); +extern void BeginStoreKit(); +extern void GetSpear(); +#endif + +extern void DownloadURLConnection(char *url); + +extern int wasCalledFromDownloadInstructionsMenu; +extern void iphoneSet2D(); + + +//extern bool isAlive; + + @interface UIApplication (Private) @@ -67,11 +97,47 @@ - (void)applicationDidFinishLaunching:(UIApplication *)application { UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; accelerometer.delegate = self; accelerometer.updateInterval = 0.01; - + // do all the game startup work iphoneStartup(); + +#if SPEARSTOREKIT + //check if user downloaded spear but didn't purchase + if (IsSpearInstalled() && !IsSpearPurchased()) + { + alertPurchaseSpear = [[UIAlertView alloc] initWithTitle:@""//Title" + message:@"You have downloaded and installed Spear of Destiny. Would you like to unlock those levels by purchasing it for $1.99?" + delegate:self + cancelButtonTitle:@"No" + otherButtonTitles:@"Yes", nil]; + + [alertPurchaseSpear show]; + } +#endif + } +//this is so that we can respond to alertView events (messageboxes) +//but this should only respond to the alertPurchaseSpear +- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex +{ + //this is if they clicked yes to going to the map instructions website + if (wasCalledFromDownloadInstructionsMenu && buttonIndex == 1) { + SysIPhoneOpenURL( "http://www.idsoftware.com/wolfenstein-3d-classic-platinum/mapinstructions/" ); + return; + } + + //if they clicked yes to going to the idsoftware website + if (buttonIndex == 1) + SysIPhoneOpenURL( "http://www.idsoftware.com/wolfenstein-3d-classic-platinum/" ); + + /* + if (alertPurchaseSpear && (alertPurchaseSpear == actionSheet)) + { + if (buttonIndex != actionSheet.cancelButtonIndex) + BeginStoreKit(); + }*/ +} - (void)applicationWillResignActive:(UIApplication *)application { } @@ -84,10 +150,70 @@ - (void)applicationWillTerminate:(UIApplication *)application { iphoneShutdown(); } +#if 1 +extern char urlbuffer[1024]; - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { // wolf3d:foo should launch wolf3d now... next, add useful URL parameter encoding + + +#ifdef LITE + iphoneMessageBox("Lite version", "This is a Lite version. You must purchase Wolfenstein3D to get this feature."); + return NO; +#endif + + if (!url) + return NO; + + NSString *str = [url absoluteString]; //in the future we may wish to parse this string + //for commands that wolf3d might follow + //for now we'll just start the storekit + char buffer[1024]; + + if(![str getCString:buffer maxLength:1024 encoding:NSUTF8StringEncoding]) + { + iphoneMessageBox("Not Valid", "There were encoding errors. Make sure the link is less than 1023 characters in length."); + return NO; + } + + //iphoneMessageBox("URL", buffer); + /* + if (strcmp(buffer, "wolf3d:foo") == 0) + GetSpear(); + */ + char *pstr = buffer;//&buffer[strlen(buffer) - 5]; + pstr += strlen(buffer) - 4; + + if (strcmp(pstr, ".map") != 0) + { + iphoneMessageBox("Not Valid", "URL is not a valid map. Maps must end in \".map\""); + return NO; + } + + + if (strncmp(buffer, "wolf3dp:", 8) == 0) + { + + char cURL[1024]; + char *http = "http:"; + strcpy(cURL, http); + strcpy(cURL + 5, buffer + 8); + //strcpy(cURL, "http://gregory.hodges.googlepages.com/SODmm.tgz"); //TODO: delete me + Com_Printf("wolf3dp: installing map %s\n", cURL); + strcpy(urlbuffer, cURL); + //download and install this map + //iphoneMessageBox("wolf3d:", "it's a map TODO install"); + //InstallUserMap(); + DownloadURLConnection(cURL); + } + else + { + iphoneMessageBox("Not Valid", "URL is not a valid map. Identifier must start with \"wolf3dp:\""); + return NO; + } + return YES; } +#endif - (void)dealloc { @@ -101,7 +227,7 @@ - (void)restartAccelerometerIfNeeded { // I have no idea why this seems to happen sometimes... if ( Sys_Milliseconds() - lastAccelUpdateMsec > 1000 ) { static int count; - if ( ++count < 100 ) { + if ( ++count < 5 ) { printf( "Restarting accelerometer updates.\n" ); } UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; @@ -121,6 +247,104 @@ - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAccelera lastAccelUpdateMsec = Sys_Milliseconds(); } +//------------------------------------------------------------ +// connection +// called by the app when data is received during download +// gsh +//------------------------------------------------------------- +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +{ + // lock the game out temporarily + pthread_mutex_t eventMutex; + pthread_mutex_lock( &eventMutex ); +/* + //display the network activity indicator + UIApplication* app = [UIApplication sharedApplication]; + app.networkActivityIndicatorVisible = YES; // to stop it, set this to NO + app.statusBarHidden = NO; +*/ + // append the new data to file + AppendUserDataToFile(data); + + // the game is free to copy the appendedData size now + pthread_mutex_unlock( &eventMutex ); +} + +//------------------------------------------------------------------------ +// connectionDidFinishLoading +// this is called when the app finishes downloading +// the new Spear of Destiny Levels +// gsh +//------------------------------------------------------------------------ +- (void) connectionDidFinishLoading:(NSURLConnection *)connection +{ + Com_Printf("connectionDidFinishLoading called\n"); +/* + //no need to display network traffic anymore + UIApplication* app = [UIApplication sharedApplication]; + app.networkActivityIndicatorVisible = NO; // to stop it, set this to NO + app.statusBarHidden = YES; +*/ + //release the connection + [connection release]; + + //uncompress/move files/delete unwanted + FinalizeUserDownload(); +} + +//------------------------------------------------------------------------ +// connection didFailWithError +// if the connection fails during the download then this is called +// gsh +//------------------------------------------------------------------------ +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + //let user know that the connection failed + iphoneMessageBox("Connection Failed", "Please check your connection and try again later."); + + //return the user to the main menu + menuState = IPM_MAIN; +/* + //no need to display network traffic anymore + UIApplication* app = [UIApplication sharedApplication]; + app.networkActivityIndicatorVisible = NO; // to stop it, set this to NO + app.statusBarHidden = YES; */ +} +/* +- (void)setDownloadResponse:(NSURLResponse *)aDownloadResponse +{ + [aDownloadResponse retain]; + [downloadResponse release]; + downloadResponse = aDownloadResponse; +} + +- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response +{ + // reset the progress, this might be called multiple times + bytesReceived=0; + + // retain the response to use later + [self setDownloadResponse:response]; +} + +- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length +{ + long long expectedLength=[[self downloadResponse] expectedContentLength]; + + bytesReceived=bytesReceived+length; + + if (expectedLength != NSURLResponseUnknownLength) { + // if the expected content length is + // available, display percent complete + float percentComplete=(bytesReceived/(float)expectedLength)*100.0; + NSLog(@"Percent complete - %f",percentComplete); + } else { + // if the expected content length is + // unknown just log the progress + NSLog(@"Bytes received - %d",bytesReceived); + } +} +*/ @end diff --git a/wolf3d/code/iphone/wolf3d_icon.png b/wolf3d/code/iphone/wolf3d_icon.png index 956a45a..363eeca 100644 Binary files a/wolf3d/code/iphone/wolf3d_icon.png and b/wolf3d/code/iphone/wolf3d_icon.png differ diff --git a/wolf3d/code/wolf/wolf_actor_ai.c b/wolf3d/code/wolf/wolf_actor_ai.c index f07b8d8..ef46fe2 100644 --- a/wolf3d/code/wolf/wolf_actor_ai.c +++ b/wolf3d/code/wolf/wolf_actor_ai.c @@ -71,8 +71,8 @@ PUBLIC void A_DeathScream( entity_t *self ) { switch( self->type ) { - case en_mutant: - if( g_version->value == SPEAROFDESTINY ) + case en_mutant: //added 0's to all of these in order to check if sounds are correct... gsh + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ) { Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/033.wav" ), 1, ATTN_NORM, 0 ); } @@ -83,7 +83,7 @@ PUBLIC void A_DeathScream( entity_t *self ) break; case en_guard: - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ) { Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( dsodsounds[ US_RndT() % 6 ] ), 1, ATTN_NORM, 0 ); } @@ -94,7 +94,7 @@ PUBLIC void A_DeathScream( entity_t *self ) break; case en_officer: - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ) { Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/046.wav" ), 1, ATTN_NORM, 0 ); } @@ -105,7 +105,7 @@ PUBLIC void A_DeathScream( entity_t *self ) break; case en_ss: - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ) { Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/035.wav" ), 1, ATTN_NORM, 0 ); } @@ -116,7 +116,7 @@ PUBLIC void A_DeathScream( entity_t *self ) break; case en_dog: - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ) { Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/031.wav" ), 1, ATTN_NORM, 0 ); } @@ -208,7 +208,7 @@ PUBLIC void A_FirstSighting( entity_t *self ) break; case en_officer: - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ) { Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/043.wav" ), 1, ATTN_NORM, 0 ); } @@ -918,7 +918,7 @@ PUBLIC void T_Projectile( entity_t *self ) { if( self->type == en_rocket || self->type == en_hrocket ) { // rocket ran into obstacle, draw explosion! - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ) { Sound_StartSound( NULL, 1, CHAN_WEAPON, Sound_RegisterSound( "lsfx/001.wav" ), 1, ATTN_NORM, 0 ); } diff --git a/wolf3d/code/wolf/wolf_ai_com.c b/wolf3d/code/wolf/wolf_ai_com.c index dcdc6a4..59bf310 100644 --- a/wolf3d/code/wolf/wolf_ai_com.c +++ b/wolf3d/code/wolf/wolf_ai_com.c @@ -924,7 +924,8 @@ PUBLIC void T_Bite( entity_t *self ) { long dx, dy; - Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "lsfx/076.wav" ), 1, ATTN_NORM, 0 ); +// Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "lsfx/076.wav" ), 1, ATTN_NORM, 0 ); //gsh this was the original code + Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/002.wav" ), 1, ATTN_NORM, 0 ); //gsh changed to this... the original code wasn't the correct sound file dx = ABS( Player.position.origin[ 0 ] - self->x ) - TILEGLOBAL; if( dx <= MINACTORDIST ) @@ -1156,7 +1157,7 @@ PUBLIC void T_Shoot( entity_t *self ) switch( self->type ) { case en_ss: - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9 )//added the episode check... gsh) { Sound_StartSound( NULL, 1, CHAN_WEAPON, Sound_RegisterSound( "sfx/020.wav" ), 1, ATTN_NORM, 0 ); } @@ -1175,7 +1176,7 @@ PUBLIC void T_Shoot( entity_t *self ) break; default: - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh) { Sound_StartSound( NULL, 1, CHAN_WEAPON, Sound_RegisterSound( "sfx/038.wav" ), 1, ATTN_NORM, 0 ); } @@ -1302,7 +1303,7 @@ PUBLIC void T_Launch( entity_t *self ) default: proj->type = en_rocket; - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh) { Sound_StartSound( NULL, 1, CHAN_WEAPON, Sound_RegisterSound( "lsfx/008.wav" ), 1, ATTN_NORM, 0 ); } diff --git a/wolf3d/code/wolf/wolf_client_main.c b/wolf3d/code/wolf/wolf_client_main.c index 3b608d7..b6af805 100644 --- a/wolf3d/code/wolf/wolf_client_main.c +++ b/wolf3d/code/wolf/wolf_client_main.c @@ -19,6 +19,20 @@ */ #include "../wolfiphone.h" +/* +void ReplaceText(char* original, char* insert, int nInsertAt) +{ + int sizeInsert = sizeof(insert); + int sizeOriginal = sizeof(original); //should be 1024 + + for (int i = 0; i < sizeInsert; i++) + { + original[nInsertAt + i] = insert[i]; + } + + + +}*/ /* ----------------------------------------------------------------------------- @@ -34,14 +48,15 @@ */ PUBLIC void Client_PrepRefresh( const char *r_mapname ) { - char mapname[ 32 ]; +// char mapname[ 32 ]; + char mapname[ 64 ]; //gsh, decided to allow longer map names if( ! r_mapname || ! *r_mapname ) { return; } - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 10)//added the episode check... gsh) { spritelocation = SODSPRITESDIRNAME; } @@ -78,7 +93,47 @@ PUBLIC void Client_PrepRefresh( const char *r_mapname ) // clear any lines of console text Con_ClearNotify(); - + + //gsh + //this is a hack... to save space on the download... we've removed the music + //so instead we're going to replace the SOD music with wolf3d music here + //however, we don't have to worry about that now that we package the SOD music + //with the binary + /* + if (currentMap.episode >= 6) //if it's the SOD levels + { + char *source; + switch (currentMap.episode * 10 + currentMap.map) + { + case 60: source = "ZEROHOUR.ogg"; break; + case 61: source = "CORNER.ogg"; break; + case 62: source = "DUNGEON.ogg"; break; + case 63: source = "ENDLEVEL.ogg"; break; + case 64: source = "FUNKYOU.ogg"; break; + case 65: source = "HEADACHE.ogg"; break; + case 66: source = "HITLWLTZ.ogg"; break; + case 67: source = "INTROCW3.ogg"; break; + case 68: source = "NAZI_NOR.ogg"; break; + case 69: source = "NAZI_OMI.ogg"; break; + case 70: source = "NAZI_RAP.ogg"; break; + case 71: source = "PACMAN.ogg"; break; + case 72: source = "POW.ogg"; break; + case 73: source = "PREGNANT.ogg"; break; + case 74: source = "ROSTER.ogg"; break; + case 75: source = "SALUTE.ogg"; break; + case 76: source = "SEARCHN.ogg"; break; + case 77: source = "SUSPENSE.ogg"; break; + case 78: source = "TWELFTH.ogg"; break; + case 79: source = "URAHERO.ogg"; break; + case 80: source = "ULTIMATE.ogg"; break; + default: + source = "CORNER.ogg"; + } + strcpy(levelData.musicName + 6, source); //the '6' is to get us past the "music/" part of musicName + levelData.musicName[6 + strlen(source)] = '\0'; + }*/ + + Com_Printf("Starting Music Track: %s\n", levelData.musicName); Sound_StartBGTrack( levelData.musicName, levelData.musicName ); Player.playstate = ex_playing; diff --git a/wolf3d/code/wolf/wolf_level.c b/wolf3d/code/wolf/wolf_level.c index 617a33b..4b29339 100644 --- a/wolf3d/code/wolf/wolf_level.c +++ b/wolf3d/code/wolf/wolf_level.c @@ -905,7 +905,7 @@ PUBLIC LevelData_t *Level_LoadMap( const char *levelname ) - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh) { statinfo = static_sod; num_statics = sizeof( static_sod ) / sizeof( static_sod[ 0 ] ); @@ -933,6 +933,7 @@ PUBLIC LevelData_t *Level_LoadMap( const char *levelname ) filesize = FS_GetFileSize( fhandle ); if( filesize < MAPHEADER_SIZE ) { + Com_Printf("Map file size is smaller than mapheader size\n"); return NULL; } @@ -943,6 +944,7 @@ PUBLIC LevelData_t *Level_LoadMap( const char *levelname ) FS_ReadFile( &signature, 1, 4, fhandle ); if( signature != MAP_SIGNATURE ) { + Com_Printf("File signature does not match MAP_SIGNATURE\n"); return NULL; } @@ -973,6 +975,7 @@ PUBLIC LevelData_t *Level_LoadMap( const char *levelname ) if( filesize < (MAPHEADER_SIZE + mapNameLength + musicNameLength + length[ 0 ] + length[ 1 ] + length[ 2 ]) ) { + Com_Printf("filesize is less than MAPHEADER_SIZE + mapNameLength + musicNameLength + etc\n"); return NULL; } @@ -990,6 +993,7 @@ PUBLIC LevelData_t *Level_LoadMap( const char *levelname ) if( filesize < (MAPHEADER_SIZE + mapNameLength + musicNameLength) ) { + Com_Printf("filesize is less than MAPHEADER_SIZE + mapNameLength + musicNameLength\n"); return NULL; } @@ -1165,6 +1169,114 @@ PUBLIC LevelData_t *Level_LoadMap( const char *levelname ) return newMap; } +/* + ----------------------------------------------------------------------------- + Function: Level_VerifyMap + + Parameters: level file name + + Returns: 0 if invalid map, 1 otherwise + + Notes: + + ----------------------------------------------------------------------------- + */ +PUBLIC int Level_VerifyMap( const char *levelname ) +{ + W16 rle; + W32 offset[ 3 ]; + W16 length[ 3 ]; + W16 w, h; + W32 signature; + W32 ceiling, floor; + filehandle_t *fhandle; + W16 mapNameLength; + char *mapName = NULL; + W16 musicNameLength; + char *musicName = NULL; + SW32 filesize; + int value = 1; + + + fhandle = FS_OpenFile( levelname, FA_FILE_IPHONE_DOC_DIR ); + if( ! fhandle ) + { + value = 0; + goto cleanup; + } + + filesize = FS_GetFileSize( fhandle ); + if( filesize < MAPHEADER_SIZE ) + { + value = 0; + goto cleanup; + } + + FS_ReadFile( &signature, 1, 4, fhandle ); + if( signature != MAP_SIGNATURE ) + { + value = 0; + goto cleanup; + } + + FS_ReadFile( &rle, 2, 1, fhandle ); + + FS_ReadFile( &w, 2, 1, fhandle ); + FS_ReadFile( &h, 2, 1, fhandle ); + + FS_ReadFile( &ceiling, 4, 1, fhandle ); + FS_ReadFile( &floor, 4, 1, fhandle ); + + + FS_ReadFile( &length, 2, 3, fhandle ); + FS_ReadFile( &offset, 4, 3, fhandle ); + + + FS_ReadFile( &mapNameLength, 1, 2, fhandle ); + FS_ReadFile( &musicNameLength, 1, 2, fhandle ); + + FS_ReadFile( &levelstate.fpartime, sizeof( float ), 1, fhandle ); + + FS_ReadFile( levelstate.spartime, sizeof( W8 ), 5, fhandle ); + levelstate.spartime[ 5 ] = '\0'; + + + if( filesize < (MAPHEADER_SIZE + mapNameLength + musicNameLength + + length[ 0 ] + length[ 1 ] + length[ 2 ]) ) + { + value = 0; + goto cleanup; + } + + mapName = Z_Malloc( mapNameLength + 1 ); + musicName = Z_Malloc( musicNameLength + 1 ); + + + FS_ReadFile( mapName, 1, mapNameLength, fhandle ); + mapName[ mapNameLength ] = '\0'; + + + FS_ReadFile( musicName, 1, musicNameLength, fhandle ); + musicName[ musicNameLength ] = '\0'; + + + if( filesize < (MAPHEADER_SIZE + mapNameLength + musicNameLength) ) + { + value = 0; + goto cleanup; + } + +cleanup: + FS_CloseFile(fhandle); + if (mapName) { + Z_Free(mapName); + } + if (musicName) { + Z_Free(musicName); + } + return value; +} + diff --git a/wolf3d/code/wolf/wolf_local.h b/wolf3d/code/wolf/wolf_local.h index 0c84640..f0586e4 100644 --- a/wolf3d/code/wolf/wolf_local.h +++ b/wolf3d/code/wolf/wolf_local.h @@ -140,8 +140,7 @@ extern void ProcessGuards( void ); #define WL6SPRITESDIRNAME "sprites" -#define SODSPRITESDIRNAME "sodsprites" - +#define SODSPRITESDIRNAME "sodsprites"//"sprites" //gsh was originally "sodsprites" extern char *spritelocation; diff --git a/wolf3d/code/wolf/wolf_main.c b/wolf3d/code/wolf/wolf_main.c index 141b829..cda6e6c 100644 --- a/wolf3d/code/wolf/wolf_main.c +++ b/wolf3d/code/wolf/wolf_main.c @@ -70,7 +70,9 @@ PUBLIC void Game_Init( void ) episode = Cvar_Get( "episode", "0", CVAR_ARCHIVE ); skill = Cvar_Get( "skill", "1", CVAR_ARCHIVE ); - g_version = Cvar_Get( "g_version", "0", CVAR_ARCHIVE ); +// g_version = Cvar_Get( "g_version", "0", CVAR_ARCHIVE ); + g_version = Cvar_Get( "g_version", "1", CVAR_ARCHIVE ); //we should make a #ifdef for "special version" + //this version is to come with spear #ifndef LITE Cmd_AddCommand( "map", Map_f ); diff --git a/wolf3d/code/wolf/wolf_player.c b/wolf3d/code/wolf/wolf_player.c index db10119..b47617b 100644 --- a/wolf3d/code/wolf/wolf_player.c +++ b/wolf3d/code/wolf/wolf_player.c @@ -83,6 +83,7 @@ PRIVATE _boolean PL_ChangeWeapon( player_t *self, int weapon ) return false; } + self->weapon = self->pendingweapon = weapon; @@ -461,7 +462,7 @@ PRIVATE void PL_PlayerAttack( player_t *self, _boolean re_attack ) ----------------------------------------------------------------------------- */ PUBLIC void PL_Process( player_t *self, LevelData_t *lvl ) -{ +{ int n; self->madenoise = false; @@ -489,11 +490,34 @@ PUBLIC void PL_Process( player_t *self, LevelData_t *lvl ) if( Player.cmd.buttons & BUTTON_ATTACK ) { self->flags |= PL_FLAG_ATTCK; - + + //gsh + if (self->previousweapon != WEAPON_KNIFE && self->previousweapon) + { + //self->weapon = self->previousweapon; + PL_ChangeWeapon(self, self->previousweapon); + } + + self->attackframe = 0; + self->attackcount = attackinfo[ self->weapon ][ 0 ].tics; + self->weaponframe = attackinfo[ self->weapon ][ 0 ].frame; + } + else if ( Player.cmd.buttons & BUTTON_ALTERNATE_ATTACK ) //gsh + { + self->flags |= PL_FLAG_ATTCK; + +// PL_ChangeWeapon(self, WEAPON_KNIFE); + if (self->weapon != WEAPON_KNIFE) + { + self->previousweapon = self->weapon; + self->weapon = WEAPON_KNIFE; + } + self->attackframe = 0; self->attackcount = attackinfo[ self->weapon ][ 0 ].tics; self->weaponframe = attackinfo[ self->weapon ][ 0 ].frame; - } else if ( Player.cmd.buttons & BUTTON_CHANGE_WEAPON ) { + } + else if ( Player.cmd.buttons & BUTTON_CHANGE_WEAPON ) { self->pendingweapon=self->weapon; for( n = 0 ; n < 4; ++n ) { @@ -559,9 +583,51 @@ PUBLIC void PL_Spawn( placeonplane_t location, LevelData_t *lvl ) Areas_ConnectAreas( Player.areanumber ); + //gsh + iphoneSetLevelNotifyText(); + /* char str[128]; - sprintf( str, "Entering level E%iM%i", currentMap.episode + 1, currentMap.map + 1 ); + //sprintf( str, "Entering level E%iM%i", currentMap.episode + 1, currentMap.map + 1 ); + //gsh + if (currentMap.episode < 6) + sprintf( str, "Entering level E%iM%i", currentMap.episode+1, currentMap.map+1 ); + else if (currentMap.episode < 10) { + int currentLevel = currentMap.episode * 10 + currentMap.map; + switch (currentLevel) { + case 60: case 61: case 62: case 63: case 64: + sprintf( str, "Entering Tunnels %i", currentLevel-60+1); + break; + case 78: + sprintf( str, "Entering Tunnels %i", 6); + break; + case 65: case 66: case 67: case 68: case 69: + sprintf( str, "Entering Dungeons %i", currentLevel-65+1); + break; + case 79: + sprintf( str, "Entering Dungeons %i", 6); + break; + case 70: case 71: case 72: case 73: case 74: case 75: + sprintf( str, "Entering Castle"); + break; + case 76: + sprintf( str, "Entering Ramparts"); + break; + case 77: + sprintf( str, "Entering Death Knight"); + break; + case 80: + sprintf( str, "Entering Dungeon Dimension"); + break; + default: + sprintf( str, " "); + break; + } + } + else + sprintf( str, "Entering level custom %i", /*currentMap.episode+1,* currentMap.map+1 ); + iphoneSetNotifyText( str ); + */ } /* @@ -918,6 +984,7 @@ PUBLIC void PL_NewGame( player_t *self ) self->ammo[ AMMO_BULLETS ] = 16; // JDC: changed for iphone 8; self->lives = 3; + self->previousweapon = WEAPON_KNIFE; //gsh self->weapon = self->pendingweapon = WEAPON_PISTOL; self->items = ITEM_WEAPON_1 | ITEM_WEAPON_2; self->next_extra = EXTRAPOINTS; @@ -973,6 +1040,7 @@ PUBLIC _boolean PL_Reborn( player_t *self ) self->weaponframe = 0; self->flags = 0; + self->previousweapon = WEAPON_KNIFE; //gsh self->weapon = self->pendingweapon = WEAPON_PISTOL; self->items = ITEM_WEAPON_1 | ITEM_WEAPON_2; diff --git a/wolf3d/code/wolf/wolf_player.h b/wolf3d/code/wolf/wolf_player.h index fb4eff5..2cf1012 100644 --- a/wolf3d/code/wolf/wolf_player.h +++ b/wolf3d/code/wolf/wolf_player.h @@ -135,6 +135,7 @@ typedef struct player_s int old_score, score, next_extra; unsigned items; // (keys, weapon) int weapon, pendingweapon; + int previousweapon; //gsh // additional info int attackframe, attackcount, weaponframe; // attack info unsigned flags; diff --git a/wolf3d/code/wolf/wolf_powerups.c b/wolf3d/code/wolf/wolf_powerups.c index 508e63f..0e6f08e 100644 --- a/wolf3d/code/wolf/wolf_powerups.c +++ b/wolf3d/code/wolf/wolf_powerups.c @@ -254,7 +254,8 @@ PRIVATE int Pow_Give( pow_t type ) { return 0; } - Sound_StartSound( NULL, 0, CHAN_ITEM, Sound_RegisterSound( "lsfx/064.wav" ), 1, ATTN_NORM, 0 ); +// Sound_StartSound( NULL, 0, CHAN_ITEM, Sound_RegisterSound( "lsfx/064.wav" ), 1, ATTN_NORM, 0 ); //gsh, I don't like this sound + Sound_StartSound( NULL, 0, CHAN_ITEM, Sound_RegisterSound( "lsfx/031.wav" ), 1, ATTN_NORM, 0 ); //gsh, I like this sound break; case pow_machinegun: @@ -290,14 +291,22 @@ PRIVATE int Pow_Give( pow_t type ) case pow_spear: { - char szTextMsg[ 256 ]; + //gsh char szTextMsg[ 256 ]; + + Com_Printf("Spear of Destiny picked up!!\n"); - Sound_StartSound( NULL, 0, CHAN_ITEM, Sound_RegisterSound( "sodsfx/109.wav" ), 1, ATTN_NORM, 0 ); + Sound_StartSound( NULL, 0, CHAN_ITEM, Sound_RegisterSound( "sfx/109.wav" ), 1, ATTN_NORM, 0 ); //gsh iphoneSetNotifyText( "Spear of Destiny" ); - - my_snprintf( szTextMsg, sizeof( szTextMsg ), +/* //gsh + my_snprintf( szTextMsg, sizeof( szTextMsg ), //this is supposed to load the last level... but it isn't "loading ; map s%.2d.map\n", 20 ); Cbuf_AddText( szTextMsg ); + */ + + //this might be a bit of a hack. But it works. + //Load the last level... gsh + iphoneStartMap(8, 0, currentMap.skill); + } break; diff --git a/wolf3d/code/wolf/wolf_pushwalls.c b/wolf3d/code/wolf/wolf_pushwalls.c index b040d7d..41fb6c4 100644 --- a/wolf3d/code/wolf/wolf_pushwalls.c +++ b/wolf3d/code/wolf/wolf_pushwalls.c @@ -96,7 +96,7 @@ PUBLIC _boolean PushWall_Push( int x, int y, dir4type dir ) iphoneSetNotifyText( "You found a secret!" ); } - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9)//added the episode check... gsh ).. TODO: fix sfx and other media { Sound_StartSound( NULL, 1, CHAN_AUTO, Sound_RegisterSound( "sfx/030.wav" ), 1, ATTN_STATIC, 0 ); } diff --git a/wolf3d/code/wolf/wolf_renderer.c b/wolf3d/code/wolf/wolf_renderer.c index cf11bad..5a26c96 100644 --- a/wolf3d/code/wolf/wolf_renderer.c +++ b/wolf3d/code/wolf/wolf_renderer.c @@ -59,7 +59,14 @@ PUBLIC void R_BeginRegistration( const char *map ) ++texture_registration_sequence; - my_snprintf( fullname, sizeof( fullname ), "maps/%s.map", map ); + //my_snprintf( fullname, sizeof( fullname ), "maps/%s.map", map ); + if ( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 10) //add if/else... gsh + my_snprintf( fullname, sizeof( fullname ), "%s.map", map ); + else if (currentMap.episode >= 10) + my_snprintf( fullname, sizeof( fullname ), "%s.map", map ); + else + my_snprintf( fullname, sizeof( fullname ), "maps/%s.map", map ); + // Door_ResetDoors( &r_world->Doors ); Powerup_Reset(); @@ -74,13 +81,13 @@ PUBLIC void R_BeginRegistration( const char *map ) if( r_world == NULL ) { - Com_Printf( "Could not load map (%s)\n", map ); + Com_Printf( "Could not load map (%s) in R_BeginRegistration\n", map ); return; } levelstate.floornum = floornumber; - if( g_version->value == SPEAROFDESTINY ) + if( g_version->value == SPEAROFDESTINY && currentMap.episode >= 6 && currentMap.episode < 9) //added the episode check... gsh) { if( strlen( map ) >= 2 ) { diff --git a/wolf3d/code/wolfiphone.h b/wolf3d/code/wolfiphone.h index e44404f..84a2ab4 100644 --- a/wolf3d/code/wolfiphone.h +++ b/wolf3d/code/wolfiphone.h @@ -85,3 +85,5 @@ #include "iphone/iphone_wolf.h" +#include "iphone_alerts.h" +