]> Dogcows Code - chaz/thecheat/blobdiff - MyDocument.m
The Cheat 1.0b3
[chaz/thecheat] / MyDocument.m
diff --git a/MyDocument.m b/MyDocument.m
new file mode 100644 (file)
index 0000000..a4733cc
--- /dev/null
@@ -0,0 +1,1737 @@
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Project:   The Cheat
+//
+// File:      MyDocument.m
+// Created:   Sun Sep 07 2003
+//
+// Copyright: 2003 Chaz McGarvey.  All rights reserved.
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#import "MyDocument.h"
+
+#import "CheatClient.h"
+
+
+// Internal Functions
+void TCPlaySound( NSString *name );
+
+
+@implementation MyDocument
+
+- (id)init
+{
+    if ( self = [super init] )
+       {
+               NSNotificationCenter            *nc = [NSNotificationCenter defaultCenter];
+               
+               // initialize stuff
+               sockfd = -1;
+               serverList = [[NSMutableArray alloc] init];
+               addressList = [[NSMutableArray alloc] init];
+               
+               // set up the network browser
+               browser = [[NSNetServiceBrowser alloc] init];
+               [browser setDelegate:self];
+               [browser searchForServicesOfType:@"_cheat._tcp." inDomain:@"local."];
+
+               // notifications to receive
+               [nc addObserver:self selector:@selector(listenerStarted:) name:@"TCListenerStarted" object:nil];
+               [nc addObserver:self selector:@selector(listenerStopped:) name:@"TCListenerStopped" object:nil];
+               [nc addObserver:self selector:@selector(windowsOnTopChanged:) name:@"TCWindowsOnTopChanged" object:nil];
+
+               [self connectToLocal];
+       }
+       
+    return self;
+}
+
+- (NSString *)windowNibName
+{
+    return @"MyDocument";
+}
+
+- (NSString *)displayName
+{
+       return [NSString stringWithFormat:@"The Cheat %i", TCGlobalDocumentCount++];
+}
+
+- (void)windowControllerDidLoadNib:(NSWindowController *)controller
+{
+    [super windowControllerDidLoadNib:controller];
+
+       [self initialInterfaceSetup];
+}
+
+
+- (void)close
+{
+       // closing the window will automatically disconnect the client from the server,
+       // but if the application is quitting, the client may not get a chance to exit.
+       // this _should_ be OK.
+       [self disconnect];
+       
+       // clean up status timer stuff.
+       // we do this here because we don't want the timer to fire after the window is gone
+       // since we need to use the window in that method.
+       [savedStatusColor release], savedStatusColor = nil;
+       [savedStatusText release], savedStatusText = nil;
+       [statusTextTimer invalidate];
+       [statusTextTimer release], statusTextTimer = nil;
+       
+       [super close];
+}
+
+
+- (void)initialInterfaceSetup
+{
+       NSString                        *localName = @"Local"; //[NSString stringWithFormat:@"%@ (local)", TCGlobalBroadcastName];
+       
+       // misc window settings
+       [cheatWindow useOptimizedDrawing:YES];
+       [cheatWindow setFrameAutosaveName:@"TCCheatWindow"];
+
+       // set options
+       if ( TCGlobalWindowsOnTop )
+       {
+               [cheatWindow setLevel:NSPopUpMenuWindowLevel];
+       }
+
+       // set up the server menu default items
+       [serverMenu removeAllItems];
+       [serverMenu addItemWithTitle:@"Not Connected" action:@selector(serverMenuDisconnect:) keyEquivalent:@""];
+       [serverMenu addItemWithTitle:localName action:@selector(serverMenuLocal:) keyEquivalent:@""];
+       [processMenu removeAllItems];
+       
+       // give tags to the menu items.
+       [[typeMenu itemWithTitle:@"Integer"] setTag:TYPE_INTEGER];
+       [[typeMenu itemWithTitle:@"String"] setTag:TYPE_STRING];
+       [[typeMenu itemWithTitle:@"Decimal"] setTag:TYPE_DECIMAL];
+       [[typeMenu itemWithTitle:@"Unknown Value"] setTag:TYPE_UNKNOWN];
+       [[stringSizeMenu itemWithTitle:@"8-bit"] setTag:SIZE_8_BIT];
+       [[integerSizeMenu itemWithTitle:@"char"] setTag:SIZE_8_BIT];
+       [[integerSizeMenu itemWithTitle:@"short"] setTag:SIZE_16_BIT];
+       [[integerSizeMenu itemWithTitle:@"long"] setTag:SIZE_32_BIT];
+       [[decimalSizeMenu itemWithTitle:@"float"] setTag:SIZE_32_BIT];
+       [[decimalSizeMenu itemWithTitle:@"double"] setTag:SIZE_64_BIT];
+       
+       // set default state
+       [statusText setStringValue:@""];
+       [self setStatusDisconnected];
+       
+       // change sheet initial interface.
+       [changeSecondsCombo setEnabled:NO];
+}
+
+- (void)updateSearchButton
+{
+       TCtype                  type = [typePopup indexOfSelectedItem];
+       
+       if ( type != TYPE_UNKNOWN )
+       {
+               if ( [[searchTextField stringValue] isEqualToString:@""] )
+               {
+                       [searchButton setEnabled:NO];
+               }
+               else
+               {
+                       [searchButton setEnabled:YES];
+               }
+       }
+       else
+       {
+               [searchButton setEnabled:YES];
+       }
+}
+
+- (void)updatePauseButton
+{
+       if ( !targetPaused )
+       {
+               [pauseButton setTitle:@"Pause Target"];
+       }
+       else
+       {
+               [pauseButton setTitle:@"Resume Target"];
+       }
+}
+
+- (void)updateSearchBoxes
+{
+       TCtype                  type = [typePopup indexOfSelectedItem];
+       
+       if ( type != TYPE_UNKNOWN )
+       {
+               [searchTextField setEnabled:YES];
+               [searchRadioMatrix setEnabled:NO];
+       }
+       else
+       {
+               [searchTextField setEnabled:NO];
+               [searchRadioMatrix setEnabled:YES];
+       }
+}
+
+- (void)updateChangeButton
+{
+       if ( addressSelected )
+       {
+               [changeButton setEnabled:YES];
+       }
+       else
+       {
+               [changeButton setEnabled:NO];
+       }
+}
+
+
+- (void)setStatusDisconnected
+{
+       lastStatus = status;
+       status = STATUS_DISCONNECTED;
+       
+       [serverPopup setEnabled:YES];
+       [pauseButton setTitle:@"Pause Target"];
+       [pauseButton setEnabled:NO];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [searchTextField setEnabled:NO];
+       [searchRadioMatrix setEnabled:NO];
+       [searchButton setEnabled:NO];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"Not Connected" duration:0];
+       [statusBar stopAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setTitle:@"ChangeÉ"];
+       [changeButton setEnabled:NO];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Not Connected"];
+}
+
+- (void)setStatusConnected
+{
+       lastStatus = status;
+       status = STATUS_CONNECTED;
+       
+       [serverPopup setEnabled:YES];
+       [self updatePauseButton];
+       [pauseButton setEnabled:YES];
+       [processPopup setEnabled:YES];
+       [typePopup setEnabled:YES];
+       [sizePopup setEnabled:YES];
+       [self updateSearchBoxes];
+       [self updateSearchButton];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"Connected" duration:0];
+       [statusBar stopAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setTitle:@"ChangeÉ"];
+       [changeButton setEnabled:NO];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusCheating
+{
+       lastStatus = status;
+       status = STATUS_CHEATING;
+       
+       [serverPopup setEnabled:YES];
+       [self updatePauseButton];
+       [pauseButton setEnabled:YES];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [self updateSearchBoxes];
+       [self updateSearchButton];
+       [clearSearchButton setEnabled:YES];
+       if ( searchResultsAmount < TCMaxSearchResults )
+       {
+               if ( searchResultsAmount == 1 )
+               {
+                       [self setStatusText:[NSString stringWithFormat:@"Results: %i", searchResultsAmount] duration:0 color:[NSColor colorWithCalibratedRed:0.0f green:0.5f blue:0.0f alpha:1.0f]];
+               }
+               else if ( searchResultsAmount == 0 )
+               {
+                       [self setStatusText:[NSString stringWithFormat:@"Results: %i", searchResultsAmount] duration:0 color:[NSColor colorWithCalibratedRed:0.5f green:0.0f blue:0.0f alpha:1.0f]];
+               }
+               else
+               {
+                       [self setStatusText:[NSString stringWithFormat:@"Results: %i", searchResultsAmount] duration:0];
+               }
+       }
+       else
+       {
+               [self setStatusText:[NSString stringWithFormat:@"Results: >%i", TCMaxSearchResults] duration:0];
+       }
+       [statusBar stopAnimation:self];
+       [addressTable setEnabled:YES];
+       [changeButton setTitle:@"ChangeÉ"];
+       [self updateChangeButton];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusSearching
+{
+       lastStatus = status;
+       status = STATUS_SEARCHING;
+       
+       [serverPopup setEnabled:NO];
+       [self updatePauseButton];
+       [pauseButton setEnabled:NO];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [searchTextField setEnabled:NO];
+       [searchRadioMatrix setEnabled:NO];
+       [searchButton setEnabled:NO];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"SearchingÉ" duration:0];
+       [statusBar startAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setTitle:@"ChangeÉ"];
+       [changeButton setEnabled:NO];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusChanging
+{
+       lastStatus = status;
+       status = STATUS_CHANGING;
+       
+       [serverPopup setEnabled:NO];
+       [self updatePauseButton];
+       [pauseButton setEnabled:NO];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [searchTextField setEnabled:NO];
+       [searchRadioMatrix setEnabled:NO];
+       [searchButton setEnabled:NO];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"ChangingÉ" duration:0];
+       [statusBar startAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setEnabled:NO];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusChangingLater
+{
+       lastStatus = status;
+       status = STATUS_CHANGING_LATER;
+       
+       [serverPopup setEnabled:NO];
+       [self updatePauseButton];
+       [pauseButton setEnabled:NO];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [searchTextField setEnabled:NO];
+       [searchRadioMatrix setEnabled:NO];
+       [searchButton setEnabled:NO];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"Changing LaterÉ" duration:0];
+       [statusBar startAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setTitle:@"Cancel Change"];
+       [changeButton setEnabled:YES];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusChangingContinuously
+{
+       lastStatus = status;
+       status = STATUS_CHANGING_CONTINUOUSLY;
+       
+       [serverPopup setEnabled:NO];
+       [self updatePauseButton];
+       [pauseButton setEnabled:YES];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [searchTextField setEnabled:NO];
+       [searchRadioMatrix setEnabled:NO];
+       [searchButton setEnabled:NO];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"Repeated Change" duration:0];
+       [statusBar startAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setTitle:@"Stop Change"];
+       [changeButton setEnabled:YES];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusUndoing
+{
+       lastStatus = status;
+       status = STATUS_UNDOING;
+       
+       [serverPopup setEnabled:NO];
+       [self updatePauseButton];
+       [pauseButton setEnabled:NO];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [searchTextField setEnabled:NO];
+       [searchRadioMatrix setEnabled:NO];
+       [searchButton setEnabled:NO];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"UndoingÉ" duration:0];
+       [statusBar startAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setTitle:@"ChangeÉ"];
+       [changeButton setEnabled:NO];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusRedoing
+{
+       lastStatus = status;
+       status = STATUS_REDOING;
+       
+       [serverPopup setEnabled:NO];
+       [self updatePauseButton];
+       [pauseButton setEnabled:NO];
+       [processPopup setEnabled:NO];
+       [typePopup setEnabled:NO];
+       [sizePopup setEnabled:NO];
+       [searchTextField setEnabled:NO];
+       [searchRadioMatrix setEnabled:NO];
+       [searchButton setEnabled:NO];
+       [clearSearchButton setEnabled:NO];
+       [self setStatusText:@"RedoingÉ" duration:0];
+       [statusBar startAnimation:self];
+       [addressTable setEnabled:NO];
+       [changeButton setTitle:@"ChangeÉ"];
+       [changeButton setEnabled:NO];
+       
+       [[serverMenu itemAtIndex:0] setTitle:@"Disconnect"];
+}
+
+- (void)setStatusToLast
+{
+       switch ( lastStatus )
+       {
+               case STATUS_DISCONNECTED:
+                       [self setStatusDisconnected];
+                       break;
+                       
+               case STATUS_CONNECTED:
+                       [self setStatusConnected];
+                       break;
+                       
+               case STATUS_CHEATING:
+                       [self setStatusCheating];
+                       break;
+                       
+               case STATUS_SEARCHING:
+                       [self setStatusSearching];
+                       break;
+                       
+               case STATUS_CHANGING:
+                       [self setStatusChanging];
+                       break;
+                       
+               case STATUS_CHANGING_LATER:
+                       [self setStatusChangingLater];
+                       break;
+                       
+               case STATUS_CHANGING_CONTINUOUSLY:
+                       [self setStatusChangingContinuously];
+                       break;
+                       
+               case STATUS_UNDOING:
+                       [self setStatusUndoing];
+                       break;
+                       
+               case STATUS_REDOING:
+                       [self setStatusRedoing];
+                       break;
+       }
+}
+
+- (void)setStatusText:(NSString *)msg duration:(NSTimeInterval)seconds
+{
+       [self setStatusText:msg duration:seconds color:[NSColor blackColor]];
+}
+
+- (void)setStatusText:(NSString *)msg duration:(NSTimeInterval)seconds color:(NSColor *)color
+{
+       if ( seconds == 0 )
+       {
+               [statusText setTextColor:color];
+               [statusText setStringValue:msg];
+       }
+       else
+       {
+               if ( statusTextTimer )
+               {
+                       [statusTextTimer invalidate];
+                       [statusTextTimer release];
+               }
+               else
+               {
+                       [savedStatusText release];
+                       [savedStatusColor release];
+                       savedStatusText = [[statusText stringValue] retain];
+                       savedStatusColor = [[statusText textColor] retain];
+               }
+               
+               [statusText setTextColor:color];
+               [statusText setStringValue:msg];
+               statusTextTimer = [[NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(statusTextTimer:) userInfo:nil repeats:NO] retain];
+               
+       }
+}
+
+- (void)statusTextTimer:(NSTimer *)timer
+{
+       [statusText setTextColor:savedStatusColor];
+       [statusText setStringValue:savedStatusText];
+       
+       [savedStatusColor release], savedStatusColor = nil;
+       [savedStatusText release], savedStatusText = nil;
+       [statusTextTimer invalidate];
+       [statusTextTimer release], statusTextTimer = nil;
+}
+
+
+- (void)connectToLocal
+{
+       NSString                        *localName = @"Local"; //[NSString stringWithFormat:@"%@ (local)", TCGlobalBroadcastName];
+       
+       // depending on how the listener is listening, we need to use different means to connect to local
+       if ( TCGlobalListening )
+       {
+               if ( TCGlobalAllowRemote )
+               {
+                       struct sockaddr_in      addr;
+
+                       addr.sin_family = AF_INET;
+                       addr.sin_port = htonl( TCGlobalListenPort );
+                       addr.sin_addr.s_addr = INADDR_ANY;
+
+                       [self connectToServer:[NSData dataWithBytes:&addr length:sizeof(addr)] name:localName];
+               }
+               else
+               {
+                       struct sockaddr_un      addr;
+
+                       addr.sun_family = AF_UNIX;
+                       strncpy( addr.sun_path, TCDefaultListenPath, 103 );
+
+                       [self connectToServer:[NSData dataWithBytes:&addr length:sizeof(addr)] name:localName];
+               }
+       }
+}
+
+- (void)connectToServer:(NSData *)addr name:(NSString *)name
+{
+       everConnected = YES;
+       
+       if ( connection )
+       {
+               [self disconnect];
+               
+               waitingToConnect = YES;
+               connectionAddress = [addr retain];
+               connectionName = [name retain];
+       }
+       else
+       {
+               connection = [[CheatClient clientWithDelegate:self server:addr name:name] retain];
+               connectionAddress = [addr retain];
+               connectionName = [name retain];
+       }
+
+       [self setStatusConnected];
+}
+
+- (void)disconnect
+{
+       if ( connection )
+       {
+               [connection release], connection = nil;
+               close( sockfd );
+
+               [self clearSearch];
+
+               [connectionAddress release], connectionAddress = nil;
+               [connectionName release], connectionName = nil;
+
+               [processMenu removeAllItems];
+
+               [serverPopup selectItemAtIndex:0];
+               [self setStatusDisconnected];
+       }
+}
+
+
+- (void)sendProcessListRequest
+{
+       PacketHeader    header;
+       int                             length = sizeof(header);
+
+       header.checksum = RandomChecksum();
+       header.function = 1;
+       header.size = 0;
+
+       if ( SendBuffer( sockfd, (char *)(&header), &length ) == -1 || length != sizeof(header) )
+       {
+               NSLog( @"sendProcessListRequest failed on socket %i", sockfd );
+       }
+}
+
+- (void)sendClearSearch
+{
+       PacketHeader    header;
+       int                             length = sizeof(header);
+       
+       header.checksum = RandomChecksum();
+       header.function = 3;
+       header.size = 0;
+       
+       if ( SendBuffer( sockfd, (char *)(&header), &length ) == -1 || length != sizeof(header) )
+       {
+               NSLog( @"sendClearSearch failed on socket %i", sockfd );
+       }
+}
+
+- (void)sendSearch:(char const *)data size:(int)size
+{
+       PacketHeader    header;
+       int                             length = sizeof(header) + size;
+       int                             lengthAfter = length;
+
+       char                    *buffer, *ptr;
+
+       header.checksum = RandomChecksum();
+       header.function = 5;
+       header.size = size;
+
+       if ( (buffer = (char *)malloc( length )) == NULL )
+       {
+               NSLog( @"sendSearch:size: failed" );
+       }
+
+       ptr = buffer;
+
+       COPY_TO_BUFFER( ptr, &header, sizeof(header) );
+       COPY_TO_BUFFER( ptr, data, size );
+
+       if ( SendBuffer( sockfd, buffer, &lengthAfter ) == -1 || lengthAfter != length )
+       {
+               NSLog( @"sendSearch:size: failed" );
+       }
+
+       free( buffer );
+}
+
+- (void)sendChange:(char const *)data size:(int)size
+{
+       PacketHeader    header;
+       int                             length = sizeof(header) + size;
+       int                             lengthAfter = length;
+       
+       char                    *buffer, *ptr;
+       
+       header.checksum = RandomChecksum();
+       header.function = 8;
+       header.size = size;
+       
+       if ( (buffer = (char *)malloc( length )) == NULL )
+       {
+               NSLog( @"sendChange:size: failed" );
+       }
+       
+       ptr = buffer;
+       
+       COPY_TO_BUFFER( ptr, &header, sizeof(header) );
+       COPY_TO_BUFFER( ptr, data, size );
+       
+       if ( SendBuffer( sockfd, buffer, &lengthAfter ) == -1 || lengthAfter != length )
+       {
+               NSLog( @"sendChange:size: failed" );
+       }
+       
+       free( buffer );
+}
+
+- (void)sendPauseTarget;
+{
+       PacketHeader    header;
+       int                             length = sizeof(header);
+
+       header.checksum = RandomChecksum();
+       header.function = 10;
+       header.size = 0;
+
+       if ( SendBuffer( sockfd, (char *)(&header), &length ) == -1 || length != sizeof(header) )
+       {
+               NSLog( @"sendPauseTarget failed" );
+       }
+}
+
+- (void)sendVariableValueRequest
+{
+
+}
+
+- (void)sendUndoRequest
+{
+       PacketHeader    header;
+       int                             length = sizeof(header);
+
+       header.checksum = RandomChecksum();
+       header.function = 14;
+       header.size = 0;
+
+       if ( SendBuffer( sockfd, (char *)(&header), &length ) == -1 || length != sizeof(header) )
+       {
+               NSLog( @"sendUndoRequest failed" );
+       }
+}
+
+- (void)sendRedoRequest
+{
+       PacketHeader    header;
+       int                             length = sizeof(header);
+
+       header.checksum = RandomChecksum();
+       header.function = 16;
+       header.size = 0;
+
+       if ( SendBuffer( sockfd, (char *)(&header), &length ) == -1 || length != sizeof(header) )
+       {
+               NSLog( @"sendRedoRequest failed" );
+       }
+}
+
+- (void)sendSetTargetPID:(int)pid
+{
+       PacketHeader    header;
+       int                             length = sizeof(header) + sizeof(u_int32_t);
+       int                             lengthAfter = length;
+
+       u_int32_t               tarPID = (u_int32_t)pid;
+
+       char                    *buffer, *ptr;
+
+       header.checksum = RandomChecksum();
+       header.function = 18;
+       header.size = sizeof(u_int32_t);
+
+       if ( (buffer = (char *)malloc( length )) == NULL )
+       {
+               NSLog( @"sendSetTargetPID: failed" );
+       }
+
+       ptr = buffer;
+
+       COPY_TO_BUFFER( ptr, &header, sizeof(header) );
+       COPY_TO_BUFFER( ptr, &tarPID, sizeof(tarPID) );
+
+       if ( SendBuffer( sockfd, buffer, &lengthAfter ) == -1 || lengthAfter != length )
+       {
+               NSLog( @"sendSetTargetPID: failed" );
+       }
+
+       free( buffer );
+}
+
+
+- (void)receivedProcessList:(NSData *)data
+{
+       NSMenuItem              *item;
+       u_int32_t               processCount = 0;
+
+       char                    *ptr = (char *)[data bytes];
+       int                             i, max;
+
+       COPY_FROM_BUFFER( &processCount, ptr, sizeof(processCount) );
+
+       max = (int)processCount;
+
+       for ( i = 0; i < max; i++ )
+       {
+               u_int32_t       pid;
+               NSString        *name;
+
+               COPY_FROM_BUFFER( &pid, ptr, sizeof(pid) );
+               name = [NSString stringWithCString:ptr], ptr += [name length] + 1;
+
+               item = [[NSMenuItem alloc] initWithTitle:name action:@selector(processMenuItem:) keyEquivalent:@""];
+               [item setTag:(int)pid];
+
+               [processMenu addItem:[item autorelease]];
+       }
+}
+
+- (void)receivedSearchFinished
+{
+       if ( searchResultsAmount == 1 )
+       {
+               TCPlaySound( @"Submarine" );
+       }
+       else if ( searchResultsAmount == 0 )
+       {
+               TCPlaySound( @"Basso" );
+       }
+       
+       [self setStatusToLast];
+       [self setStatusText:@"Search Finished" duration:1.5];
+       [cheatWindow makeFirstResponder:searchTextField];
+}
+
+- (void)receivedVariableList:(NSData *)data
+{
+       char                    *ptr = (char *)[data bytes];
+
+       [self destroyResults];
+
+       COPY_FROM_BUFFER( &searchResultsAmount, ptr, sizeof(searchResultsAmount) );
+
+       if ( searchResultsAmount > 0 )
+       {
+               int                             memSize = TCAddressSize*searchResultsAmount;
+               
+               if ( (searchResults = (TCaddress *)malloc( memSize )) == NULL )
+               {
+                       NSLog( @"receivedVariableList failed: malloc failed" );
+                       searchResultsAmount = 0;
+                       return;
+               }
+
+               COPY_FROM_BUFFER( searchResults, ptr, memSize );
+       }
+
+       [addressTable reloadData];
+}
+
+- (void)receivedChangeFinished
+{
+       TCPlaySound( @"Tink" );
+       
+       [self setStatusToLast];
+       [self setStatusText:@"Change Finished" duration:1.5];
+}
+
+- (void)receivedError:(NSData *)data
+{
+       u_int32_t               fatal;
+       NSString                *msg;
+
+       char                    *ptr = (char *)[data bytes];
+
+       COPY_FROM_BUFFER( &fatal, ptr, sizeof(fatal) );
+
+       msg = [NSString stringWithCString:ptr];
+       
+       // alert the user.
+       [self handleErrorMessage:msg fatal:fatal];
+}
+
+- (void)receivedUndoFinished
+{
+       [self setStatusToLast];
+}
+
+- (void)receivedRedoFinished
+{
+       [self setStatusToLast];
+}
+
+- (void)receivedUndoRedoStatus:(NSData *)data
+{
+       char                    *ptr = (char *)[data bytes];
+       
+       COPY_FROM_BUFFER( &undoCount, ptr, sizeof(undoCount) );
+       COPY_FROM_BUFFER( &redoCount, ptr, sizeof(redoCount) );
+       
+       NSLog( @"UNDO: %i, REDO: %i", undoCount, redoCount );
+}
+
+- (void)receivedAppLaunched:(NSData *)data
+{
+       NSMenuItem              *item;
+
+       char                    *ptr = (char *)[data bytes];
+
+       u_int32_t               pid;
+       NSString                *name;
+
+       COPY_FROM_BUFFER( &pid, ptr, sizeof(pid) );
+       name = [NSString stringWithCString:ptr], ptr += [name length] + 1;
+
+       item = [[NSMenuItem alloc] initWithTitle:name action:@selector(processMenuItem:) keyEquivalent:@""];
+       [item setTag:(int)pid];
+
+       [processMenu addItem:[item autorelease]];
+}
+
+- (void)receivedAppQuit:(NSData *)data
+{
+       u_int32_t               pid;
+       
+       char                    *ptr = (char *)[data bytes];
+
+       COPY_FROM_BUFFER( &pid, ptr, sizeof(pid) );
+
+       [processMenu removeItemWithTag:pid];
+}
+
+- (void)receivedTargetQuit
+{
+       [self clearSearch];
+       [self sendClearSearch];
+       
+       // tell the server that the first app is now the target.
+       targetPID = [[processMenu itemAtIndex:0] tag];
+       [self sendSetTargetPID:targetPID];
+       
+       // alert the user.
+       [self handleErrorMessage:@"The application that was being cheated has quit." fatal:NO];
+       
+       [self setStatusConnected];
+}
+
+- (void)receivedPauseFinished:(NSData *)data
+{
+       char                    *ptr = (char *)[data bytes];
+
+       COPY_FROM_BUFFER( &targetPaused, ptr, sizeof(targetPaused) );
+
+       if ( targetPaused )
+       {
+               [self setStatusText:@"Target Paused" duration:1.5];
+       }
+       else
+       {
+               [self setStatusText:@"Target Resumed" duration:1.5];
+       }
+       
+       [self updatePauseButton];
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   Searching & Changing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)search
+{
+       TCtype                  type = [[typePopup selectedItem] tag];
+       TCsize                  size = [[sizePopup selectedItem] tag];
+       
+       char                    *data, *ptr;
+       int                             dataSize = sizeof(type) + sizeof(size);
+       
+       data = (char *)malloc( dataSize );
+       ptr = data;
+       
+       // copy the size and type of the variable.
+       COPY_TO_BUFFER( ptr, &type, sizeof(type) );
+       COPY_TO_BUFFER( ptr, &size, sizeof(size) );
+       
+       // switch to cheating mode if this is the first search.
+       if ( status == STATUS_CONNECTED )
+       {
+               [self setStatusCheating];
+       }
+       
+       // copy the value to search for.
+       switch ( type )
+       {
+               case TYPE_STRING:
+               {
+                       switch ( size )
+                       {
+                               case SIZE_8_BIT:
+                               {
+                                       NSString                        *string = [searchTextField stringValue];
+                                       int                                     stringLength = [string length] + 1;
+                                       
+                                       data = (char *)realloc( data, dataSize + stringLength );
+                                       ptr = data + dataSize;
+                                       dataSize += stringLength;
+                                       
+                                       COPY_TO_BUFFER( ptr, [string cString], stringLength );
+                               }
+                                       break;
+                       }
+               }
+                       break;
+                       
+               case TYPE_INTEGER:
+               {
+                       switch ( size )
+                       {
+                               case SIZE_8_BIT:
+                               {
+                                       int8_t                  value = [searchTextField intValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                                       
+                               case SIZE_16_BIT:
+                               {
+                                       int16_t                 value = [searchTextField intValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                                       
+                               case SIZE_32_BIT:
+                               {
+                                       int32_t                 value = [searchTextField intValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                       }
+               }
+                       break;
+                       
+               case TYPE_DECIMAL:
+               {
+                       switch ( size )
+                       {
+                               case SIZE_32_BIT:
+                               {
+                                       float                   value = [searchTextField floatValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                                       
+                               case SIZE_64_BIT:
+                               {
+                                       double                  value = [searchTextField doubleValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                       }
+               }
+                       break;
+                       
+               case TYPE_UNKNOWN:
+               {
+                       u_int32_t               value = 0;//[searchTextField intValue];
+                       
+                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                       ptr = data + dataSize;
+                       dataSize += sizeof(value);
+                       
+                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+               }
+                       break;
+       }
+       
+       [self sendSearch:data size:dataSize];
+       free( data );
+       
+       [self setStatusSearching];
+}
+
+- (void)change
+{
+       TCtype                  type = [[typePopup selectedItem] tag];
+       TCsize                  size = [[sizePopup selectedItem] tag];
+       
+       NSArray                 *selectedAddresses = [[addressTable selectedRowEnumerator] allObjects];
+       int                             i, addressCount = [selectedAddresses count];
+       
+       char                    *data, *ptr;
+       int                             dataSize = sizeof(type) + sizeof(size) + sizeof(addressCount) + TCAddressSize*addressCount;
+       
+       data = (char *)malloc( dataSize );
+       ptr = data;
+       
+       // copy the size and type of the variable.
+       COPY_TO_BUFFER( ptr, &type, sizeof(type) );
+       COPY_TO_BUFFER( ptr, &size, sizeof(size) );
+
+       // copy the amount and the list of addresses to change.
+       COPY_TO_BUFFER( ptr, &addressCount, sizeof(addressCount) );
+       for ( i = 0; i < addressCount; i++ )
+       {
+               COPY_TO_BUFFER( ptr, &((TCaddress *)searchResults)[ [[selectedAddresses objectAtIndex:i] intValue] ], sizeof(TCaddress) );
+       }
+       
+       // copy the new value.
+       switch ( type )
+       {
+               case TYPE_STRING:
+               {
+                       switch ( size )
+                       {
+                               case SIZE_8_BIT:
+                               {
+                                       NSString                        *string = [changeTextField stringValue];
+                                       int                                     stringLength = [string length] + 1;
+                                       
+                                       data = (char *)realloc( data, dataSize + stringLength );
+                                       ptr = data + dataSize;
+                                       dataSize += stringLength;
+                                       
+                                       COPY_TO_BUFFER( ptr, [string cString], stringLength );
+                               }
+                                       break;
+                       }
+               }
+                       break;
+                       
+               case TYPE_INTEGER:
+               {
+                       switch ( size )
+                       {
+                               case SIZE_8_BIT:
+                               {
+                                       int8_t                  value = [changeTextField intValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                                       
+                               case SIZE_16_BIT:
+                               {
+                                       int16_t                 value = [changeTextField intValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                                       
+                               case SIZE_32_BIT:
+                               {
+                                       int32_t                 value = [changeTextField intValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                       }
+               }
+                       break;
+                       
+               case TYPE_DECIMAL:
+               {
+                       switch ( size )
+                       {
+                               case SIZE_32_BIT:
+                               {
+                                       float                   value = [changeTextField floatValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                                       
+                               case SIZE_64_BIT:
+                               {
+                                       double                  value = [changeTextField doubleValue];
+                                       
+                                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                                       ptr = data + dataSize;
+                                       dataSize += sizeof(value);
+                                       
+                                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+                               }
+                                       break;
+                       }
+               }
+                       break;
+                       
+               case TYPE_UNKNOWN:
+               {
+                       u_int32_t               value = 0;//[searchTextField intValue];
+                       
+                       data = (char *)realloc( data, dataSize + sizeof(value) );
+                       ptr = data + dataSize;
+                       dataSize += sizeof(value);
+                       
+                       COPY_TO_BUFFER( ptr, &value, sizeof(value) );
+               }
+                       break;
+       }
+       
+       [self sendChange:data size:dataSize];
+       free( data );
+       
+       [self setStatusChanging];
+}
+
+
+- (void)changeSheet:(NSWindow *)sheet returned:(int)returned context:(void *)context
+{
+       if ( returned == 1 )
+       {
+               if ( [recurringChangeButton state] == NSOnState )
+               {
+                       float                   seconds = [changeSecondsCombo floatValue];
+                       
+                       [self setStatusChangingContinuously];
+                       
+                       [self change];
+                       
+                       changeTimer = [[NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(changeTimer:) userInfo:nil repeats:YES] retain];
+               }
+               else
+               {
+                       [self change];
+               }
+       }
+}
+
+
+- (void)changeTimer:(NSTimer *)timer
+{
+       [self change];
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   Cheat Window Interface
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (IBAction)typePopup:(id)sender
+{
+       switch ( [typePopup indexOfSelectedItem] )
+       {
+               case TYPE_STRING:
+                       [sizePopup setMenu:stringSizeMenu];
+                       break;
+
+               case TYPE_INTEGER:
+               case TYPE_UNKNOWN:
+                       [sizePopup setMenu:integerSizeMenu];
+                       break;
+
+               case TYPE_DECIMAL:
+                       [sizePopup setMenu:decimalSizeMenu];
+                       break;
+       }
+       
+       [self updateSearchBoxes];
+       [self updateSearchButton];
+}
+
+
+- (IBAction)searchButton:(id)sender
+{
+       [self search];
+}
+
+- (IBAction)clearSearchButton:(id)sender
+{
+       [self clearSearch];
+       
+       [self setStatusConnected];
+       [self setStatusText:@"Search Cleared" duration:1.5];
+
+       [self sendClearSearch];
+}
+
+
+- (IBAction)changeButton:(id)sender
+{
+       [changeTimer invalidate];
+       [changeTimer release], changeTimer = nil;
+       
+       if ( status == STATUS_CHANGING_CONTINUOUSLY )
+       {
+               [self setStatusCheating];
+       }
+       else if ( status = STATUS_CHEATING )
+       {
+               [NSApp beginSheet:changeSheet modalForWindow:cheatWindow modalDelegate:self didEndSelector:@selector(changeSheet:returned:context:) contextInfo:NULL];
+               //[NSApp runModalForWindow:changeSheet];
+               //[NSApp endSheet:changeSheet];
+               //[changeSheet orderOut:self];
+       }
+}
+
+
+- (IBAction)serverMenuItem:(id)sender
+{
+       NSData                          *data = [[[serverList objectAtIndex:[sender tag]] addresses] objectAtIndex:0];
+/*     struct sockaddr_in      addr;
+
+       [data getBytes:&addr];*/
+
+       [self connectToServer:data name:[serverPopup titleOfSelectedItem]];
+}
+
+- (IBAction)serverMenuDisconnect:(id)sender
+{
+       [self disconnect];
+}
+
+- (IBAction)serverMenuLocal:(id)sender
+{
+       [self connectToLocal];
+}
+
+- (IBAction)processMenuItem:(id)sender
+{
+       targetPID = [sender tag];
+
+       [self sendSetTargetPID:targetPID];
+
+       [self setStatusText:[NSString stringWithFormat:@"PID: %i", targetPID] duration:0];
+}
+
+
+- (IBAction)pauseButton:(id)sender
+{
+       [self sendPauseTarget];
+}
+
+
+- (void)undoMenu:(id)sender
+{
+       if ( undoCount == 1 )
+       {
+               [self clearSearchButton:self];
+       }
+       else
+       {
+               [self sendUndoRequest];
+
+               [self setStatusUndoing];
+       }
+}
+
+- (void)redoMenu:(id)sender
+{
+       [self sendRedoRequest];
+
+       [self setStatusRedoing];
+}
+
+- (BOOL)respondsToSelector:(SEL)aSelector
+{
+       if ( aSelector == @selector(undoMenu:) )
+       {
+               if ( status == STATUS_CHEATING && undoCount > 0 )
+               {
+                       return YES;
+               }
+               else
+               {
+                       return NO;
+               }
+       }
+       
+       if ( aSelector == @selector(redoMenu:) )
+       {
+               if ( status == STATUS_CHEATING && redoCount > 0 )
+               {
+                       return YES;
+               }
+               else
+               {
+                       return NO;
+               }
+       }
+       
+       return [super respondsToSelector:aSelector];
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   Change Sheet Interface
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (IBAction)cancelButton:(id)sender
+{
+       [changeSheet orderOut:sender];
+       [NSApp endSheet:changeSheet returnCode:0];
+       //[NSApp stopModal];
+}
+
+- (IBAction)okButton:(id)sender
+{
+       [changeSheet orderOut:sender];
+       [NSApp endSheet:changeSheet returnCode:1];
+       //[NSApp stopModal];
+}
+
+
+- (IBAction)recurringChangeButton:(id)sender
+{
+       if ( [recurringChangeButton state] == NSOnState )
+       {
+               [changeSecondsCombo setEnabled:YES];
+       }
+       else
+       {
+               [changeSecondsCombo setEnabled:NO];
+       }
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   Cleaning Up
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)clearSearch
+{
+       undoCount = 0;
+       redoCount = 0;
+       
+       targetPaused = NO;
+       
+       [changeTimer invalidate];
+       [changeTimer release], changeTimer = nil;
+       
+       [self destroyResults];
+       [addressTable reloadData];
+}
+
+- (void)destroyResults
+{
+       if ( searchResultsAmount > 0 )
+       {
+               free( searchResults );
+               
+               searchResultsAmount = 0;
+       }
+}
+
+
+- (void)dealloc
+{
+       [[NSNotificationCenter defaultCenter] removeObserver:self];
+       
+       [self disconnect];
+
+       [browser release];
+
+       [serverList release];
+       [addressList release];
+       
+       // clean up status timer stuff
+       [savedStatusColor release];
+       [savedStatusText release];
+       [statusTextTimer invalidate];
+       [statusTextTimer release];
+       
+       [changeTimer invalidate];
+       [changeTimer release];
+       
+       [self destroyResults];
+
+       [super dealloc];
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   TCListener Notifications
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)listenerStarted:(NSNotification *)note
+{
+       if ( !everConnected )
+       {
+               [self connectToLocal];
+       }
+}
+
+- (void)listenerStopped:(NSNotification *)note
+{
+       
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   TCWindowsOnTopChanged Notification
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)windowsOnTopChanged:(NSNotification *)note
+{
+       if ( TCGlobalWindowsOnTop )
+       {
+               [cheatWindow setLevel:NSPopUpMenuWindowLevel];
+       }
+       else
+       {
+               [cheatWindow setLevel:NSNormalWindowLevel];
+       }
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   TCWindowsOnTopChanged Notification
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)handleErrorMessage:(NSString *)msg fatal:(BOOL)fatal
+{
+       // close the change sheet if it's open.
+       if ( [cheatWindow attachedSheet] )
+       {
+               [changeSheet orderOut:self];
+               [NSApp endSheet:changeSheet returnCode:0];
+       }
+       
+       // show message.
+       NSBeginAlertSheet( fatal? @"Fatal Error":@"Error", @"OK", nil, nil, cheatWindow, nil, nil, nil, 0, msg );
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   ClientDelegate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)clientConnectedWithSocket:(int)sock name:(NSString *)name
+{
+       // the client is reporting that a connection has been made.
+       sockfd = sock;
+
+       [self sendProcessListRequest];
+       
+       [serverPopup selectItemWithTitle:name];
+       
+       [self setStatusConnected];
+}
+
+- (void)clientDisconnected
+{
+       // if there is a pending connection, connect now.
+       if ( waitingToConnect )
+       {
+               waitingToConnect = NO;
+               connection = [[CheatClient clientWithDelegate:self server:connectionAddress name:connectionName] retain];
+       }
+       // if our connection variable is still valid, we were disconnected unexpectedly.
+       else if ( connection )
+       {
+               [self disconnect];
+               NSBeginAlertSheet( @"Network Failure", @"OK", nil, nil, cheatWindow, nil, nil, nil, 0, @"The server has disconnected you." );
+       }
+}
+
+- (void)clientError:(NSString *)error message:(NSString *)message
+{
+       NSBeginAlertSheet( error, @"OK", nil, nil, cheatWindow, nil, nil, nil, 0, message );
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   NSToolbar Delegate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/*
+*** A toolbar is no longer used, but the code still remains for possible future use. ***
+- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
+{
+       NSToolbarItem           *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
+
+       if ( [itemIdentifier isEqualToString:@"Disconnect"] )
+       {
+               disconnectButton = item;
+               
+        [item setLabel:@"Disconnect"];
+        [item setPaletteLabel:[item label]];
+        [item setImage:[NSImage imageNamed:@"disconnect"]];
+        [item setTarget:self];
+               [item setToolTip:@"Click here to pause or unpause the program being cheated."];
+    }
+       else if ( [itemIdentifier isEqualToString:@"ServerPopup"] )
+       {
+               NSRect          fRect = [typePopup frame];
+               NSSize          fSize = NSMakeSize( FLT_MAX, fRect.size.height );
+               NSMenuItem      *menu = [[NSMenuItem alloc] initWithTitle:@"Server" action:@selector(serverPopup:) keyEquivalent:@""];
+
+               [menu setSubmenu:[serverPopup menu]];
+               
+        [item setLabel:@"Server"];
+        [item setPaletteLabel:[item label]];
+        [item setView:serverPopup];
+               [item setMinSize:fRect.size];
+               [item setMaxSize:fSize];
+               [item setMenuFormRepresentation:[menu autorelease]];
+               [item autorelease];
+    }
+
+    return item;
+}
+
+- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
+{
+       return [NSArray arrayWithObjects:NSToolbarSeparatorItemIdentifier,
+               NSToolbarSpaceItemIdentifier,
+               NSToolbarFlexibleSpaceItemIdentifier,
+               NSToolbarCustomizeToolbarItemIdentifier,
+               @"Disconnect", @"ServerPopup", nil];
+}
+
+- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
+{
+       return [NSArray arrayWithObjects:@"Disconnect", @"ServerPopup", nil];
+}*/
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   NSTableView Data Source/Delegate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)controlTextDidChange:(NSNotification *)aNotification
+{
+       [self updateSearchButton];
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   NSTableView Data Source/Delegate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (int)numberOfRowsInTableView:(NSTableView *)table
+{
+       return (searchResultsAmount <= TCMaxSearchResults) ? searchResultsAmount : TCMaxSearchResults;
+}
+
+- (id)tableView:(NSTableView *)table objectValueForTableColumn:(NSTableColumn *)column row:(int)row
+{
+       return [NSString stringWithFormat:@"%0.8X", ((TCaddress *)searchResults)[row]];
+}
+
+- (void)tableView:(NSTableView *) setObjectValue:(id)object forTableColumn:(NSTableColumn *)column row:(int)row
+{
+       return;
+}
+
+- (void)tableViewSelectionDidChange:(NSNotification *)note
+{
+       if ( [addressTable selectedRow] != -1 )
+       {
+               addressSelected = YES;
+       }
+       else
+       {
+               addressSelected = NO;
+       }
+       
+       [self updateChangeButton];
+}
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%   NSNetServiceBrowser Delegate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)more
+{
+       // a server has broadcast; not much use until it's resolved.
+       [service setDelegate:self];
+       [service resolve];
+}
+
+- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didRemoveService:(NSNetService *)service moreComing:(BOOL)more
+{
+       [serverMenu removeAllItemsWithTitle:[service name]];
+       
+       // if this is the last broadcast server, take away the divider.
+       if ( [serverMenu numberOfItems] == 3 )
+       {
+               [serverMenu removeItemAtIndex:2];
+       }
+}
+
+- (void)netServiceDidResolveAddress:(NSNetService *)service
+{
+       NSString                *name = [service name];
+       int                             tag = [serverList count];
+       NSMenuItem              *item;
+       
+       if ( [serverMenu itemWithTitle:name] == nil )
+       {
+               item = [[NSMenuItem alloc] initWithTitle:[service name] action:@selector(serverMenuItem:) keyEquivalent:@""];
+               
+               [item setTag:tag];
+               
+               // if this is the first server, add a divider.
+               if ( [serverMenu numberOfItems] <= 2 )
+               {
+                       [serverMenu addItem:[NSMenuItem separatorItem]];
+               }
+               
+               [serverList addObject:service];
+               [serverMenu addItem:[item autorelease]];
+               
+               // select the item if we are already connected to the server.
+               // this could happen if the server rebroadcast as a different name.
+               if ( connection && [[[service addresses] objectAtIndex:0] isEqualToData:connectionAddress] )
+               {
+                       [serverPopup selectItemWithTitle:[service name]];
+               }
+       }
+}
+
+
+@end
+
+
+// Internal Functions
+void TCPlaySound( NSString *name )
+{
+       if ( TCGlobalPlaySounds )
+       {
+               [[NSSound soundNamed:name] play];
+       }
+}
This page took 0.044698 seconds and 4 git commands to generate.