Mac: Rebuilt Cheat Finder

This commit is contained in:
Michael Buckley 2023-03-25 07:36:29 -07:00
parent 35ea8b4ec9
commit 2e568452c0
19 changed files with 1854 additions and 1358 deletions

View File

@ -33,6 +33,7 @@ extern NSWindowFrameAutosaveName const kMainWindowIdentifier;
@property (nonatomic, strong) NSWindow *gameWindow; @property (nonatomic, strong) NSWindow *gameWindow;
@property (nonatomic, strong) S9xPreferencesWindowController *preferencesWindowController; @property (nonatomic, strong) S9xPreferencesWindowController *preferencesWindowController;
@property (nonatomic, strong) NSWindowController *cheatsWindowController; @property (nonatomic, strong) NSWindowController *cheatsWindowController;
@property (nonatomic, strong) NSWindowController *cheatFinderWindowController;
@property (nonatomic, readonly, assign) S9xDeviceSetting deviceSetting; @property (nonatomic, readonly, assign) S9xDeviceSetting deviceSetting;
- (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player; - (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player;

View File

@ -21,9 +21,14 @@
#import <Carbon/Carbon.h> #import <Carbon/Carbon.h>
#import "AppDelegate.h" #import "AppDelegate.h"
#import "S9xPreferencesConstants.h" #import "S9xPreferencesConstants.h"
#import "S9xCheatFinderViewController.h"
NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow"; NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow";
NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow"; NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow";
NSWindowFrameAutosaveName const kCheatFinderWindowIdentifier = @"s9xCheatFinderWindow";
@interface AppDelegate () <S9xCheatFinderDelegate>
@end
@implementation AppDelegate @implementation AppDelegate
@ -638,4 +643,39 @@ NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow";
[NSUserDefaults.standardUserDefaults setBool:self.s9xEngine.cheatsEnabled forKey:kEnableCheatsPref]; [NSUserDefaults.standardUserDefaults setBool:self.s9xEngine.cheatsEnabled forKey:kEnableCheatsPref];
} }
- (IBAction)openCheatFinderWindow:(id)sender
{
if ( self.cheatFinderWindowController == nil )
{
S9xCheatFinderViewController *vc = [[S9xCheatFinderViewController alloc] initWithNibName:@"S9xCheatFinderViewController" bundle:nil];
vc.engine = self.s9xEngine;
vc.delegate = self;
NSWindow *window = [NSWindow windowWithContentViewController:vc];
self.cheatFinderWindowController = [[NSWindowController alloc] initWithWindow:window];
window = self.cheatFinderWindowController.window;
window.title = NSLocalizedString(@"Cheat Finder", nil);
window.restorationClass = self.class;
window.frameAutosaveName = kCheatFinderWindowIdentifier;
window.releasedWhenClosed = NO;
if ( ![window setFrameUsingName:kCheatFinderWindowIdentifier] )
{
[window center];
}
}
[self.cheatFinderWindowController showWindow:nil];
[self.cheatFinderWindowController.window makeKeyAndOrderFront:nil];
[self.cheatFinderWindowController.window makeKeyWindow];
}
- (void)addedCheat
{
[((S9xCheatsViewController *)self.cheatsWindowController.contentViewController) deselectAll];
[((S9xCheatsViewController *)self.cheatsWindowController.contentViewController) reloadData];
}
@end @end

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
</dependencies> </dependencies>
<objects> <objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"> <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@ -404,12 +404,18 @@
<action selector="toggleCheats:" target="-1" id="IZg-ZR-9iA"/> <action selector="toggleCheats:" target="-1" id="IZg-ZR-9iA"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Show Cheats" id="9oz-Uu-GkA"> <menuItem title="Show Cheats" id="9oz-Uu-GkA">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
<action selector="openCheatsWindow:" target="-1" id="VdR-bM-JgN"/> <action selector="openCheatsWindow:" target="-1" id="VdR-bM-JgN"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Cheat Finder…" id="FVY-1R-MN4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="openCheatFinderWindow:" target="-1" id="6gG-03-7xm"/>
</connections>
</menuItem>
</items> </items>
</menu> </menu>
</menuItem> </menuItem>

View File

@ -28,6 +28,13 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithCheatItem:(nullable S9xCheatItem *)cheatItem saveCallback:(void (^)(void))saveCallback; - (instancetype)initWithCheatItem:(nullable S9xCheatItem *)cheatItem saveCallback:(void (^)(void))saveCallback;
- (void)updateSaveButton;
@property (nonatomic, weak) IBOutlet NSTextField *codeField;
@property (nonatomic, weak) IBOutlet NSTextField *descriptionField;
@property (nonatomic, weak) IBOutlet NSTextField *addressField;
@property (nonatomic, weak) IBOutlet NSTextField *valueField;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -25,10 +25,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface S9xCheatEditViewController () <NSTextFieldDelegate> @interface S9xCheatEditViewController () <NSTextFieldDelegate>
@property (nonatomic, weak) IBOutlet NSTextField *codeField;
@property (nonatomic, weak) IBOutlet NSTextField *descriptionField;
@property (nonatomic, weak) IBOutlet NSTextField *addressField;
@property (nonatomic, weak) IBOutlet NSTextField *valueField;
@property (nonatomic, weak) IBOutlet NSTextField *invalidCodeLabel; @property (nonatomic, weak) IBOutlet NSTextField *invalidCodeLabel;
@property (nonatomic, weak) IBOutlet NSButton *saveButton; @property (nonatomic, weak) IBOutlet NSButton *saveButton;

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>

View File

@ -0,0 +1,38 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2023 Michael Donald Buckley
***********************************************************************************/
#import <Cocoa/Cocoa.h>
#import <snes9x_framework/snes9x_framework.h>
NS_ASSUME_NONNULL_BEGIN
@protocol S9xCheatFinderDelegate <NSObject>
- (void)addedCheat;
@end
@interface S9xCheatFinderViewController : NSViewController
@property (nonatomic, strong) S9xEngine *engine;
@property (nonatomic, weak) id<S9xCheatFinderDelegate> delegate;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,927 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2023 Michael Donald Buckley
***********************************************************************************/
#import <snes9x_framework/snes9x_framework.h>
#import "S9xCheatFinderViewController.h"
#import "S9xCheatEditViewController.h"
#import "S9xHexNumberFormatter.h"
#define MAIN_MEMORY_SIZE 0x20000
#define MAIN_MEMORY_BASE 0x7E0000
#define MAX_WATCHES 16
typedef NS_ENUM(uint32_t, S9xCheatFinderByteSize) {
S9xCheatFinderByteSize1 = 1,
S9xCheatFinderByteSize2 = 2,
S9xCheatFinderByteSize3 = 3,
S9xCheatFinderByteSize4 = 4
};
typedef NS_ENUM(uint32_t, S9xCheatFinderValueType) {
S9xCheatFinderValueTypeUnsigned = 101,
S9xCheatFinderValueTypeSigned = 102,
S9xCheatFinderValueTypeHexadecimal = 103
};
typedef NS_ENUM(uint32_t, S9xCheatFinderComparisonType) {
S9xCheatFinderComparisonTypeEqual = 0,
S9xCheatFinderComparisonTypeNotEqual = 1,
S9xCheatFinderComparisonTypeGreaterThan = 2,
S9xCheatFinderComparisonTypeGreaterThanOrEqual = 3,
S9xCheatFinderComparisonTypeLessThan = 4,
S9xCheatFinderComparisonTypeLessThanOrEqual = 5
};
typedef NS_ENUM(uint32_t, S9xCheatFinderCompareTo) {
S9xCheatFinderCompareToCustom = 200,
S9xCheatFinderCompareToPrevious = 201,
S9xCheatFinderCompareToStored = 202
};
typedef NS_ENUM(uint32_t, S9xCheatFinderWatchSegments) {
S9xCheatFinderWatchSegmentsAdd = 0,
S9xCheatFinderWatchSegmentsRemove = 1,
S9xCheatFinderWatchSegmentsSave = 2,
S9xCheatFinderWatchSegmentsLoad = 3
};
@interface S9xCheatFinderTableView : NSTableView
@property (nonatomic, strong, nullable) void (^deleteBlock)(NSIndexSet *);
@end
@interface S9xCheatFinderViewController () <NSTableViewDataSource, NSTableViewDelegate, NSTextFieldDelegate, S9xEmulationDelegate>
@property (nonatomic, weak) IBOutlet S9xCheatFinderTableView *addressTableView;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *addressTableWidthConstraint;
@property (nonatomic, weak) IBOutlet NSPopUpButton *byteSizePopUp;
@property (nonatomic, weak) IBOutlet NSPopUpButton *comparisonTypePopUp;
@property (nonatomic, weak) IBOutlet NSTextField *customValueField;
@property (nonatomic, weak) IBOutlet NSButton *resetButon;
@property (nonatomic, weak) IBOutlet NSButton *searchButton;
@property (nonatomic, weak) IBOutlet NSButton *addCheatButton;
@property (nonatomic, weak) IBOutlet S9xCheatFinderTableView *watchTableView;
@property (nonatomic, weak) IBOutlet NSSegmentedControl *watchButtonsSegmentedControl;
@property (nonatomic, readonly, assign) S9xCheatFinderByteSize byteSize;
@property (nonatomic, readonly, assign) S9xCheatFinderValueType valueType;
@property (nonatomic, readonly, assign) S9xCheatFinderComparisonType compareType;
@property (nonatomic, readonly, assign) S9xCheatFinderCompareTo compareTo;
@property (nonatomic, readonly, strong) NSNumber *customValue;
@end
@interface S9xCheatFinderEntry : NSObject
@property (nonatomic, assign) uint32_t address;
@property (nonatomic, assign) uint32_t value;
@property (nonatomic, assign) uint32_t prevValue;
@property (nonatomic, assign) uint32_t storedValue;
@end
@implementation S9xCheatFinderViewController
{
BOOL _hasStored;
BOOL _hasPrevious;
uint8_t _storedRAM[MAIN_MEMORY_SIZE];
uint8_t _previousRAM[MAIN_MEMORY_SIZE];
uint8_t _currentRAM[MAIN_MEMORY_SIZE];
uint8_t _statusFlag[MAIN_MEMORY_SIZE];
NSMutableArray<S9xCheatFinderEntry *> *_addressRows;
NSMutableArray<S9xWatchPoint *> *_watchRows;
NSNumberFormatter *_unsignedFormatter;
NSNumberFormatter *_signedFormatter;
NSNumberFormatter *_hexFormatter;
BOOL _shouldReopen;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_unsignedFormatter = [NSNumberFormatter new];
_unsignedFormatter.minimum = @(0);
_unsignedFormatter.maximum = @(UINT_MAX);
_signedFormatter = [NSNumberFormatter new];
_signedFormatter.minimum = @(INT_MIN);
_signedFormatter.maximum = @(INT_MAX);
_hexFormatter = [S9xHexNumberFormatter new];
[NSNotificationCenter.defaultCenter addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:NSOperationQueue.mainQueue usingBlock:^(NSNotification *notification)
{
[self updateScrollBar];
}];
__weak S9xCheatFinderViewController *weakSelf = self;
self.addressTableView.deleteBlock = ^(NSIndexSet *deletedIndexes)
{
__strong S9xCheatFinderViewController *strongSelf = weakSelf;
[deletedIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop)
{
S9xCheatFinderEntry *entry = strongSelf->_addressRows[i];
strongSelf->_statusFlag[entry.address] = 0;
strongSelf.resetButon.enabled = YES;
}];
[strongSelf reloadData];
};
self.watchTableView.deleteBlock = ^(NSIndexSet *deletedIndexes)
{
__strong S9xCheatFinderViewController *strongSelf = weakSelf;
[strongSelf->_watchRows removeObjectsAtIndexes:deletedIndexes];
[strongSelf.engine setWatchPoints:self->_watchRows];
[strongSelf reloadWatchPoints];
};
[self resetAll];
}
- (void)viewWillAppear
{
[super viewWillAppear];
[self updateScrollBar];
[self.engine copyRAM:(uint8_t *)_currentRAM length:sizeof(_currentRAM)];
[self reloadData];
[self reloadWatchPoints];
}
- (void)viewWillDisappear
{
[super viewWillDisappear];
[self copyPrevious];
}
- (void)resetAll
{
[self.byteSizePopUp selectItemWithTag:S9xCheatFinderByteSize2];
((NSButton *)[self.view viewWithTag:S9xCheatFinderValueTypeUnsigned]).state = NSControlStateValueOn;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToCustom]).state = NSControlStateValueOn;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToPrevious]).enabled = NO;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToStored]).enabled = NO;
self.resetButon.enabled = NO;
self.searchButton.enabled = NO;
self.addCheatButton.enabled = NO;
[self.comparisonTypePopUp selectItemWithTag:S9xCheatFinderComparisonTypeEqual];
self.customValueField.stringValue = @"";
self.customValueField.formatter = _unsignedFormatter;
_hasStored = NO;
_hasPrevious = NO;
_shouldReopen = NO;
self.engine.emulationDelegate = self;
[self.engine copyRAM:(uint8_t *)_currentRAM length:sizeof(_currentRAM)];
[self.engine setWatchPoints:@[]];
[self reset:self];
}
- (void)copyPrevious
{
memcpy(_previousRAM, _currentRAM, MAIN_MEMORY_SIZE);
_hasPrevious = YES;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToPrevious]).enabled = YES;
}
- (void)reloadData
{
NSMutableSet<NSNumber *> *selectedAddresses = [NSMutableSet new];
[self.addressTableView.selectedRowIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop)
{
[selectedAddresses addObject:@(_addressRows[i].address)];
}];
_addressRows = [NSMutableArray new];
for ( NSUInteger i = 0; i < MAIN_MEMORY_SIZE; ++i )
{
if ( _statusFlag[i] )
{
S9xCheatFinderEntry *entry = [S9xCheatFinderEntry new];
entry.address = (uint32_t)i;
entry.value = [self copyValueFrom:_currentRAM index:i];
entry.prevValue = [self copyValueFrom:_previousRAM index:i];
entry.storedValue = [self copyValueFrom:_storedRAM index:i];
[_addressRows addObject:entry];
}
}
[self.addressTableView reloadData];
NSIndexSet *newRows = [_addressRows indexesOfObjectsPassingTest:^(S9xCheatFinderEntry *entry, NSUInteger i, BOOL *stop)
{
return [selectedAddresses containsObject:@(entry.address)];
}];
[self.addressTableView selectRowIndexes:newRows byExtendingSelection:NO];
}
- (void)reloadWatchPoints
{
_watchRows = [[self.engine getWatchPoints] mutableCopy];
[self.watchTableView reloadData];
}
- (uint32_t)copyValueFrom:(uint8_t *)buffer index:(NSUInteger)index
{
uint32_t value = 0;
NSInteger size = self.byteSize;
if (size + index >= MAIN_MEMORY_SIZE)
{
size = MAIN_MEMORY_SIZE - index;
}
memcpy(&value, &(buffer[index]), size);
return value;
}
- (NSString *)stringFor:(uint8_t *)buffer index:(NSUInteger)index
{
uint32_t value = [self copyValueFrom:buffer index:index];
NSString *string = nil;
switch (self.valueType)
{
case S9xCheatFinderValueTypeUnsigned:
string = [NSString stringWithFormat:@"%u", value];
break;
case S9xCheatFinderValueTypeSigned:
switch (self.byteSize)
{
case S9xCheatFinderByteSize1:
string = [NSString stringWithFormat:@"%d", (int8_t)value];
break;
case S9xCheatFinderByteSize2:
string = [NSString stringWithFormat:@"%d", (int16_t)value];
break;
case S9xCheatFinderByteSize3:
if (value >= (1 << 23))
{
value = (int32_t)value - (1 << 24);
}
string = [NSString stringWithFormat:@"%d", value];
break;
case S9xCheatFinderByteSize4:
string = [NSString stringWithFormat:@"%d", value];
break;
}
break;
case S9xCheatFinderValueTypeHexadecimal:
{
switch(self.byteSize)
{
case S9xCheatFinderByteSize1:
string = [NSString stringWithFormat:@"%02X", value];
break;
case S9xCheatFinderByteSize2:
string = [NSString stringWithFormat:@"%04X", value];
break;
case S9xCheatFinderByteSize3:
string = [NSString stringWithFormat:@"%06X", value];
break;
case S9xCheatFinderByteSize4:
string = [NSString stringWithFormat:@"%08X", value];
break;
}
break;
}
}
return string;
}
- (void)updateSearchButton
{
switch (self.compareTo)
{
case S9xCheatFinderCompareToCustom:
self.searchButton.enabled = self.customValueField.stringValue.length > 0;
break;
case S9xCheatFinderCompareToPrevious:
self.searchButton.enabled = _hasPrevious;
break;
case S9xCheatFinderCompareToStored:
self.searchButton.enabled = _hasStored;
break;
}
}
- (void)updateWatchButtons
{
NSInteger numAddressesSelected = self.addressTableView.numberOfSelectedRows;
NSUInteger numWatches = _watchRows.count;
NSInteger numWatchesSelected = self.watchTableView.numberOfSelectedRows;
[self.watchButtonsSegmentedControl setEnabled:numAddressesSelected > 0 && numAddressesSelected + numWatches <= MAX_WATCHES forSegment:S9xCheatFinderWatchSegmentsAdd];
[self.watchButtonsSegmentedControl setEnabled:numWatchesSelected > 0 forSegment:(NSInteger)S9xCheatFinderWatchSegmentsRemove];
[self.watchButtonsSegmentedControl setEnabled:numWatches != 0 forSegment:S9xCheatFinderWatchSegmentsSave];
}
- (void)updateScrollBar
{
const CGFloat defaultWidth = 393.0;
const CGFloat scrollbarWidth = 15.0;
if (NSScroller.preferredScrollerStyle == NSScrollerStyleLegacy)
{
self.addressTableWidthConstraint.constant = defaultWidth + scrollbarWidth;
}
else
{
self.addressTableWidthConstraint.constant = defaultWidth;
}
[self.view layout];
[self.addressTableView sizeLastColumnToFit];
[self.watchTableView sizeLastColumnToFit];
}
#pragma mark - Actions
- (IBAction)storeValues:(id)sender
{
memcpy(_storedRAM, _currentRAM, MAIN_MEMORY_SIZE);
_hasStored = YES;
((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToStored]).enabled = YES;
[self reloadData];
[self updateSearchButton];
}
- (IBAction)reset:(id)sender
{
memset(_statusFlag, 1, sizeof(_statusFlag));
self.resetButon.enabled = NO;
[self reloadData];
[self updateSearchButton];
[self.addressTableView deselectAll:self];
[self.watchTableView deselectAll:self];
[self updateWatchButtons];
}
- (IBAction)search:(id)sender
{
NSMutableIndexSet *rowsToRemove = [NSMutableIndexSet new];
NSNumber *customValue = self.customValue;
S9xCheatFinderValueType valueType = self.valueType;
S9xCheatFinderComparisonType comparisonType = self.compareType;
S9xCheatFinderCompareTo compareTo = self.compareTo;
for (S9xCheatFinderEntry *entry in _addressRows)
{
switch(valueType)
{
case S9xCheatFinderValueTypeUnsigned:
case S9xCheatFinderValueTypeHexadecimal:
{
uint32_t value = [self copyValueFrom:_currentRAM index:entry.address];
uint32_t comparedValue;
switch(compareTo)
{
case S9xCheatFinderCompareToCustom:
comparedValue = customValue.unsignedIntValue;
break;
case S9xCheatFinderCompareToStored:
comparedValue = [self copyValueFrom:_storedRAM index:entry.address];
break;
case S9xCheatFinderCompareToPrevious:
comparedValue = [self copyValueFrom:_previousRAM index:entry.address];
break;
}
switch(comparisonType)
{
case S9xCheatFinderComparisonTypeEqual:
_statusFlag[entry.address] = (value == comparedValue);
break;
case S9xCheatFinderComparisonTypeNotEqual:
_statusFlag[entry.address] = (value != comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThan:
_statusFlag[entry.address] = (value > comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThanOrEqual:
_statusFlag[entry.address] = (value >= comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThan:
_statusFlag[entry.address] = (value < comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThanOrEqual:
_statusFlag[entry.address] = (value <= comparedValue);
break;
}
break;
}
case S9xCheatFinderValueTypeSigned:
{
int32_t value = [self copyValueFrom:_currentRAM index:entry.address];
int32_t comparedValue;
switch(compareTo)
{
case S9xCheatFinderCompareToCustom:
comparedValue = customValue.intValue;
break;
case S9xCheatFinderCompareToStored:
comparedValue = [self copyValueFrom:_storedRAM index:entry.address];
break;
case S9xCheatFinderCompareToPrevious:
comparedValue = [self copyValueFrom:_previousRAM index:entry.address];
break;
}
switch(comparisonType)
{
case S9xCheatFinderComparisonTypeEqual:
_statusFlag[entry.address] = (value == comparedValue);
break;
case S9xCheatFinderComparisonTypeNotEqual:
_statusFlag[entry.address] = (value != comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThan:
_statusFlag[entry.address] = (value > comparedValue);
break;
case S9xCheatFinderComparisonTypeGreaterThanOrEqual:
_statusFlag[entry.address] = (value >= comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThan:
_statusFlag[entry.address] = (value < comparedValue);
break;
case S9xCheatFinderComparisonTypeLessThanOrEqual:
_statusFlag[entry.address] = (value <= comparedValue);
break;
}
break;
}
}
}
[_addressRows removeObjectsAtIndexes:rowsToRemove];
[self reloadData];
[self updateWatchButtons];
self.resetButon.enabled = YES;
}
- (IBAction)reload:(id)sender
{
[self reloadData];
}
- (IBAction)setFormat:(id)sender
{
[self reloadData];
S9xCheatFinderValueType valueType = (S9xCheatFinderValueType)[sender tag];
NSNumber *value = self.customValue;
switch (valueType)
{
case S9xCheatFinderValueTypeUnsigned:
self.customValueField.formatter = _unsignedFormatter;
break;
case S9xCheatFinderValueTypeSigned:
self.customValueField.formatter = _signedFormatter;
break;
case S9xCheatFinderValueTypeHexadecimal:
self.customValueField.formatter = _hexFormatter;
break;
}
self.customValueField.stringValue = [self.customValueField.formatter stringForObjectValue:value];
}
- (IBAction)setCompareTarget:(id)sender
{
[self reloadData];
[self updateSearchButton];
[self updateWatchButtons];
}
- (IBAction)addCheat:(id)sender
{
S9xCheatFinderEntry *entry = _addressRows[self.addressTableView.selectedRow];
S9xCheatEditViewController *vc = [[S9xCheatEditViewController alloc] initWithCheatItem:nil saveCallback:^
{
[self.delegate addedCheat];
}];
[self presentViewControllerAsSheet:vc];
vc.addressField.objectValue = @(entry.address + MAIN_MEMORY_BASE);
vc.valueField.objectValue = @(_currentRAM[entry.address]);
[vc.view.window makeFirstResponder:vc.descriptionField];
[vc updateSaveButton];
}
- (IBAction)watchesAction:(NSSegmentedControl *)sender
{
switch((S9xCheatFinderWatchSegments)sender.selectedSegment)
{
case S9xCheatFinderWatchSegmentsAdd:
{
NSIndexSet *selectedIndexes = self.addressTableView.selectedRowIndexes;
[selectedIndexes enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop)
{
S9xWatchPoint *watchPoint = [S9xWatchPoint new];
S9xCheatFinderEntry *entry = _addressRows[i];
watchPoint.address = entry.address + MAIN_MEMORY_BASE;
watchPoint.size = self.byteSize;
watchPoint.format = self.valueType - 100;
[_watchRows addObject:watchPoint];
}];
[self.engine setWatchPoints:_watchRows];
[self reloadWatchPoints];
break;
}
case S9xCheatFinderWatchSegmentsRemove:
{
[_watchRows removeObjectsAtIndexes:self.watchTableView.selectedRowIndexes];
[self reloadWatchPoints];
break;
}
case S9xCheatFinderWatchSegmentsSave:
{
NSSavePanel *savePanel = [NSSavePanel new];
savePanel.nameFieldStringValue = @"watches.txt";
[savePanel beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse response)
{
if (response == NSModalResponseOK)
{
FILE *file = fopen(savePanel.URL.path.UTF8String, "wb");
if (file != NULL)
{
for ( S9xWatchPoint *watchPoint in self->_watchRows)
{
fprintf(file, "address = 0x%x, name = \"?\", size = %d, format = %d\n", watchPoint.address, watchPoint.size, watchPoint.format);
}
fclose(file);
}
}
}];
break;
}
case S9xCheatFinderWatchSegmentsLoad:
{
NSOpenPanel *openPanel = [NSOpenPanel new];
openPanel.allowsMultipleSelection = NO;
openPanel.canChooseDirectories = NO;
[openPanel beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse response)
{
FILE *file = fopen(openPanel.URL.path.UTF8String, "rb");
if (file != NULL)
{
self->_watchRows = [NSMutableArray new];
for (NSUInteger i = 0; i < MAX_WATCHES; ++i)
{
uint32_t address;
uint32_t size;
uint32_t format;
char ignore[32];
fscanf(file, "address = 0x%x, name = \"%31[^\"]\", size = %d, format = %d\n", &address, ignore, &size, &format);
if (ferror(file))
{
break;
}
S9xWatchPoint *watchPoint = [S9xWatchPoint new];
watchPoint.address = address;
watchPoint.size = size;
watchPoint.format = format;
[self->_watchRows addObject:watchPoint];
if(feof(file))
{
break;
}
}
fclose(file);
[self.engine setWatchPoints:self->_watchRows];
[self reloadWatchPoints];
}
}];
}
}
}
#pragma mark - Emulation Delegate
- (void)gameLoaded
{
[self resetAll];
[self emulationResumed];
}
- (void)emulationPaused
{
if (!NSThread.isMainThread)
{
dispatch_sync(dispatch_get_main_queue(), ^
{
[self emulationPaused];
});
}
else if (_shouldReopen)
{
[self.view.window makeKeyAndOrderFront:self];
_shouldReopen = NO;
}
}
- (void)emulationResumed
{
if (!NSThread.isMainThread)
{
dispatch_sync(dispatch_get_main_queue(), ^
{
[self emulationResumed];
});
}
else
{
if ([self.view.window isVisible])
{
[self.view.window close];
_shouldReopen = YES;
}
[self reloadData];
}
}
#pragma mark - Table View Delegate
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
if (tableView == self.addressTableView)
{
return _addressRows.count;
}
else
{
return _watchRows.count;
}
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString *value = [self tableView:tableView objectValueForTableColumn:tableColumn row:row];
NSTableCellView *cell = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
cell.textField.stringValue = value;
return cell;
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
if (tableView == self.addressTableView)
{
S9xCheatFinderEntry *entry = _addressRows[row];
if ([tableColumn.identifier isEqualToString:@"address"])
{
return [NSString stringWithFormat:@"%06X", entry.address + MAIN_MEMORY_BASE];
}
else if ([tableColumn.identifier isEqualToString:@"currentValue"])
{
return [self stringFor:_currentRAM index:entry.address];
}
else if ([tableColumn.identifier isEqualToString:@"previousValue"])
{
if (!_hasPrevious)
{
return @"";
}
return [self stringFor:_previousRAM index:entry.address];
}
else if ( [tableColumn.identifier isEqualToString:@"storedValue"])
{
if (!_hasStored)
{
return @"";
}
return [self stringFor:_storedRAM index:entry.address];
}
return @"";
}
else
{
S9xWatchPoint *watchPoint = _watchRows[row];
NSString *formatString;
switch((S9xCheatFinderValueType)(watchPoint.format + 100))
{
case S9xCheatFinderValueTypeSigned:
formatString = @"s";
break;
case S9xCheatFinderValueTypeUnsigned:
formatString = @"u";
break;
case S9xCheatFinderValueTypeHexadecimal:
formatString = @"x";
break;
}
return [NSString stringWithFormat:@"%06X,%d%@", watchPoint.address, watchPoint.size, formatString];
}
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
self.addCheatButton.enabled = self.addressTableView.numberOfSelectedRows == 1;
[self updateWatchButtons];
}
#pragma mark - Text Field Delegate
- (void)controlTextDidChange:(NSNotification *)obj
{
[self updateSearchButton];
}
#pragma mark - Accessors
@dynamic byteSize;
- (S9xCheatFinderByteSize)byteSize
{
return (S9xCheatFinderByteSize)[self.byteSizePopUp selectedTag];
}
- (S9xCheatFinderValueType)valueType
{
S9xCheatFinderValueType valueType;
if (((NSButton *)[self.view viewWithTag:S9xCheatFinderValueTypeUnsigned]).state == NSOnState)
{
valueType = S9xCheatFinderValueTypeUnsigned;
}
else if (((NSButton *)[self.view viewWithTag:S9xCheatFinderValueTypeSigned]).state == NSOnState)
{
valueType = S9xCheatFinderValueTypeSigned;
}
else
{
valueType = S9xCheatFinderValueTypeHexadecimal;
}
return valueType;
}
@dynamic compareType;
- (S9xCheatFinderComparisonType)compareType
{
return (S9xCheatFinderComparisonType)self.comparisonTypePopUp.selectedTag;
}
@dynamic compareTo;
- (S9xCheatFinderCompareTo)compareTo
{
S9xCheatFinderCompareTo compareTo;
if (((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToCustom]).state == NSOnState)
{
compareTo = S9xCheatFinderCompareToCustom;
}
else if (((NSButton *)[self.view viewWithTag:S9xCheatFinderCompareToStored]).state == NSOnState)
{
compareTo = S9xCheatFinderCompareToStored;
}
else
{
compareTo = S9xCheatFinderCompareToPrevious;
}
return compareTo;
}
@dynamic customValue;
- (NSNumber *)customValue
{
return [((NSNumberFormatter *)self.customValueField.formatter) numberFromString:self.customValueField.stringValue];
}
@end
@implementation S9xCheatFinderTableView
- (void)keyDown:(NSEvent *)event
{
if ( [event.characters isEqualToString:@"\b"] || [event.characters isEqualToString:@"\x7f"] )
{
if (self.deleteBlock != nil && self.numberOfSelectedRows > 0)
{
self.deleteBlock(self.selectedRowIndexes);
}
}
else
{
[super keyDown:event];
}
}
@end
@implementation S9xCheatFinderEntry
@end

View File

@ -0,0 +1,530 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="S9xCheatFinderViewController">
<connections>
<outlet property="addCheatButton" destination="ut3-qV-HGo" id="tjX-Gg-J4f"/>
<outlet property="addressTableView" destination="sYl-gL-DD1" id="8cU-16-9xx"/>
<outlet property="addressTableWidthConstraint" destination="Icm-wc-CD6" id="R2l-by-fFC"/>
<outlet property="byteSizePopUp" destination="cRe-AN-vwd" id="Jsr-J6-K3O"/>
<outlet property="comparisonTypePopUp" destination="8E0-uI-3yG" id="9Pb-eL-qnZ"/>
<outlet property="customValueField" destination="eXx-ny-Tok" id="jOO-1g-ZrX"/>
<outlet property="resetButon" destination="Iue-dD-GsP" id="iZY-so-mm9"/>
<outlet property="searchButton" destination="kaT-sZ-PRb" id="OmJ-QB-kyt"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
<outlet property="watchButtonsSegmentedControl" destination="rg7-go-Amx" id="adb-5o-3fI"/>
<outlet property="watchTableView" destination="0yj-jc-bsT" id="mxE-U8-j3A"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="641" height="504"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ut3-qV-HGo">
<rect key="frame" x="521" y="208" width="107" height="32"/>
<buttonCell key="cell" type="push" title="Add Cheat…" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="s8c-70-5VV">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="addCheat:" target="-2" id="1E5-9d-VrX"/>
</connections>
</button>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Iue-dD-GsP">
<rect key="frame" x="414" y="240" width="108" height="32"/>
<buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="1IS-Dv-QTo">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="reset:" target="-2" id="tKx-xy-lZs"/>
</connections>
</button>
<scrollView autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Z8O-p3-OZ8">
<rect key="frame" x="20" y="20" width="393" height="464"/>
<clipView key="contentView" id="85a-zn-2E6">
<rect key="frame" x="1" y="1" width="391" height="462"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="automatic" headerView="iN8-VY-ogh" viewBased="YES" id="sYl-gL-DD1" customClass="S9xCheatFinderTableView">
<rect key="frame" x="0.0" y="0.0" width="393" height="434"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="17" height="0.0"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="address" width="68" minWidth="68" maxWidth="68" id="PCE-6l-BBu">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Address">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="Zdc-Os-Bi7">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="address" id="0NR-A5-OjJ">
<rect key="frame" x="8" y="0.0" width="66" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Dgd-on-ZeT">
<rect key="frame" x="0.0" y="4" width="69" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="00000000" id="cwC-aq-IFr">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="Dgd-on-ZeT" id="WQq-mc-hYk"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="currentValue" width="86" minWidth="86" maxWidth="86" id="Vwl-qJ-uNZ">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Current">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="HkI-7L-JeO">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="currentValue" id="ZOd-kp-vCM">
<rect key="frame" x="91" y="0.0" width="86" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="i95-bi-omC">
<rect key="frame" x="0.0" y="4" width="103" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="-2147483648" id="psi-UC-PXB">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="i95-bi-omC" id="ggC-ha-GoA"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="previousValue" width="86" minWidth="86" maxWidth="86" id="dJ6-AP-GhI">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Previous">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="kX1-a6-V9h">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="previousValue" id="31E-xj-mDP">
<rect key="frame" x="194" y="0.0" width="86" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wh7-NY-USM">
<rect key="frame" x="0.0" y="4" width="103" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="-2147483648" id="qr7-q7-sej">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="Wh7-NY-USM" id="DNK-1e-gIq"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="storedValue" width="90" minWidth="90" maxWidth="1000" id="oWj-Ws-aMa">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Stored">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" identifier="storedValue" title="Text Cell" id="scu-B5-zJ7">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="8y9-1G-mD4">
<rect key="frame" x="297" y="0.0" width="87" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iql-ZD-Qi4">
<rect key="frame" x="0.0" y="4" width="104" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="-2147483648" id="aIg-2X-Ccv">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="iql-ZD-Qi4" id="6ZO-oj-X2D"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="Lq4-TH-tMo"/>
<outlet property="delegate" destination="-2" id="BcQ-I0-UPf"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="width" constant="393" id="Icm-wc-CD6"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="had-bq-XTh">
<rect key="frame" x="-100" y="-100" width="392" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="FyW-kM-PC8">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" wantsLayer="YES" id="iN8-VY-ogh">
<rect key="frame" x="0.0" y="0.0" width="393" height="28"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CJT-h8-WOU">
<rect key="frame" x="419" y="468" width="117" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Value Size:" id="OxX-tw-Vqn">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cRe-AN-vwd">
<rect key="frame" x="539" y="461" width="86" height="25"/>
<popUpButtonCell key="cell" type="push" title="1 Bytes" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="6u8-S0-1HE" id="v4e-cD-Jvg">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="ahy-ao-c12">
<items>
<menuItem title="1 Bytes" tag="1" id="6u8-S0-1HE">
<connections>
<action selector="reload:" target="-2" id="R90-mV-hi2"/>
</connections>
</menuItem>
<menuItem title="2 Bytes" state="on" tag="2" id="cIU-wH-R28">
<connections>
<action selector="reload:" target="-2" id="8nL-gR-C8K"/>
</connections>
</menuItem>
<menuItem title="3 Bytes" tag="3" id="7kS-Oq-ENU">
<connections>
<action selector="reload:" target="-2" id="SbZ-ZM-Wrr"/>
</connections>
</menuItem>
<menuItem title="4 Bytes" tag="4" id="U24-yb-eYi">
<connections>
<action selector="reload:" target="-2" id="4Ur-cc-Gmk"/>
</connections>
</menuItem>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Iwa-5p-7mk">
<rect key="frame" x="419" y="361" width="117" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Comparison:" id="FPt-dO-3ZL">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8E0-uI-3yG">
<rect key="frame" x="539" y="354" width="86" height="25"/>
<popUpButtonCell key="cell" type="push" title="=" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="V0d-DE-Tg8" id="SsD-Ss-ho8">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="3m6-To-Bh8">
<items>
<menuItem title="=" state="on" id="V0d-DE-Tg8"/>
<menuItem title="≠" tag="1" id="GSW-GL-5BE"/>
<menuItem title="&gt;" tag="2" id="xnG-3t-R9N"/>
<menuItem title="≥" tag="3" id="JlT-gc-K9N"/>
<menuItem title="&lt;" tag="4" id="9fT-w3-epd"/>
<menuItem title="≤" tag="5" id="vgd-E3-XFG"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<button verticalHuggingPriority="750" tag="103" translatesAutoresizingMaskIntoConstraints="NO" id="BZc-RO-wiZ">
<rect key="frame" x="419" y="440" width="104" height="18"/>
<buttonCell key="cell" type="radio" title="Hexadecimal" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="d3H-As-fK8">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setFormat:" target="-2" id="h9N-4v-flt"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="102" translatesAutoresizingMaskIntoConstraints="NO" id="nl2-Ws-C1y">
<rect key="frame" x="419" y="418" width="68" height="18"/>
<buttonCell key="cell" type="radio" title="Signed" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="9Wb-iT-whd">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setFormat:" target="-2" id="f2j-CT-bGL"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="101" translatesAutoresizingMaskIntoConstraints="NO" id="YSm-pR-xTv">
<rect key="frame" x="419" y="396" width="84" height="18"/>
<buttonCell key="cell" type="radio" title="Unsigned" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="2Y3-aV-xAX">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setFormat:" target="-2" id="eXM-iz-3GL"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="202" translatesAutoresizingMaskIntoConstraints="NO" id="sOk-o8-x8Y">
<rect key="frame" x="419" y="333" width="115" height="18"/>
<buttonCell key="cell" type="radio" title="Stored Value" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="Jla-qC-IvR">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setCompareTarget:" target="-2" id="pb2-se-c1q"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="201" translatesAutoresizingMaskIntoConstraints="NO" id="YqM-5N-NYa">
<rect key="frame" x="419" y="311" width="115" height="18"/>
<buttonCell key="cell" type="radio" title="Previous Value" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="06y-36-OK5">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setCompareTarget:" target="-2" id="aKc-J9-6Hc"/>
</connections>
</button>
<button verticalHuggingPriority="750" tag="200" translatesAutoresizingMaskIntoConstraints="NO" id="BeO-08-nTS">
<rect key="frame" x="419" y="289" width="115" height="18"/>
<buttonCell key="cell" type="radio" title="This Value:" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="S1G-ML-fIC">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setCompareTarget:" target="-2" id="bt9-ee-D1M"/>
</connections>
</button>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eXx-ny-Tok">
<rect key="frame" x="542" y="287" width="79" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="upd-cO-CDd">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<outlet property="delegate" destination="-2" id="oDO-hH-5sb"/>
</connections>
</textField>
<scrollView autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ibr-Q0-59f">
<rect key="frame" x="421" y="49" width="200" height="149"/>
<clipView key="contentView" id="9bC-Md-S42">
<rect key="frame" x="1" y="1" width="198" height="147"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" rowSizeStyle="automatic" headerView="Be9-bB-Nds" viewBased="YES" id="0yj-jc-bsT" customClass="S9xCheatFinderTableView">
<rect key="frame" x="0.0" y="0.0" width="198" height="119"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="17" height="0.0"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="AutomaticTableColumnIdentifier.0" width="185" minWidth="185" maxWidth="185" id="9gb-7H-ZVq">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Watch">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="9kP-XN-WjV">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="JsP-6w-4Pj">
<rect key="frame" x="8" y="0.0" width="180" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EKy-fB-qcf">
<rect key="frame" x="0.0" y="4" width="180" height="16"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="00000000" id="7hn-hd-g4c">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="EKy-fB-qcf" id="m4e-vb-ub0"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="rtv-F4-sc4"/>
<outlet property="delegate" destination="-2" id="HZd-Vk-Pih"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="height" constant="149" id="Dpk-8G-9tj"/>
<constraint firstAttribute="width" constant="200" id="cs4-sZ-4UP"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="V1J-zT-Szg">
<rect key="frame" x="1" y="132" width="10" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="TMt-m8-lYU">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" wantsLayer="YES" id="Be9-bB-Nds">
<rect key="frame" x="0.0" y="0.0" width="198" height="28"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="845-DP-dPF">
<rect key="frame" x="422" y="204" width="199" height="5"/>
</box>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kaT-sZ-PRb">
<rect key="frame" x="520" y="240" width="108" height="32"/>
<buttonCell key="cell" type="push" title="Search" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uSQ-ca-Uji">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="search:" target="-2" id="ntd-fZ-bbI"/>
</connections>
</button>
<segmentedControl verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rg7-go-Amx">
<rect key="frame" x="422" y="19" width="169" height="23"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" segmentDistribution="fill" style="smallSquare" trackingMode="momentary" id="X8J-oM-StD">
<font key="font" metaFont="system"/>
<segments>
<segment image="NSAddTemplate" width="25"/>
<segment image="NSRemoveTemplate" width="25" tag="1"/>
<segment label="Save…" tag="2"/>
<segment label="Load…" tag="3"/>
</segments>
</segmentedCell>
<connections>
<action selector="watchesAction:" target="-2" id="2kk-Za-Xbn"/>
</connections>
</segmentedControl>
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="afr-7l-W3m">
<rect key="frame" x="414" y="208" width="109" height="32"/>
<buttonCell key="cell" type="push" title="Store Values" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="adn-hg-cHW">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="storeValues:" target="-2" id="Xfx-Ga-KnR"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="YqM-5N-NYa" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="0ae-yj-g2N"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="centerY" secondItem="afr-7l-W3m" secondAttribute="centerY" id="2QJ-De-4Vs"/>
<constraint firstItem="nl2-Ws-C1y" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="2o3-zm-Ypv"/>
<constraint firstItem="CJT-h8-WOU" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="2uS-a2-ZJJ"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="trailing" secondItem="YqM-5N-NYa" secondAttribute="trailing" id="3FF-yi-Ezx"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="3qS-LJ-zqs"/>
<constraint firstItem="afr-7l-W3m" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="4kb-KH-oVR"/>
<constraint firstItem="sOk-o8-x8Y" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="5MG-qE-AUq"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="top" secondItem="YqM-5N-NYa" secondAttribute="bottom" constant="6" symbolic="YES" id="6bi-Z9-qY7"/>
<constraint firstItem="YSm-pR-xTv" firstAttribute="top" secondItem="nl2-Ws-C1y" secondAttribute="bottom" constant="6" symbolic="YES" id="6mU-Wq-dNg"/>
<constraint firstItem="rg7-go-Amx" firstAttribute="leading" secondItem="0yj-jc-bsT" secondAttribute="leading" id="7rk-68-jdc"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="leading" secondItem="8E0-uI-3yG" secondAttribute="leading" id="80d-Pd-Ceb"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="leading" secondItem="afr-7l-W3m" secondAttribute="leading" id="8El-Nu-kgV"/>
<constraint firstItem="kaT-sZ-PRb" firstAttribute="leading" secondItem="Iue-dD-GsP" secondAttribute="trailing" constant="12" symbolic="YES" id="93E-Hy-aaY"/>
<constraint firstItem="8E0-uI-3yG" firstAttribute="firstBaseline" secondItem="Iwa-5p-7mk" secondAttribute="firstBaseline" id="Ae0-Nz-NAM"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="leading" secondItem="afr-7l-W3m" secondAttribute="trailing" constant="12" symbolic="YES" id="B3D-4f-RSH"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="trailing" secondItem="ut3-qV-HGo" secondAttribute="trailing" id="DWI-Em-mDq"/>
<constraint firstItem="Ibr-Q0-59f" firstAttribute="top" secondItem="845-DP-dPF" secondAttribute="bottom" constant="8" symbolic="YES" id="E9F-N9-JbX"/>
<constraint firstItem="rg7-go-Amx" firstAttribute="top" secondItem="Ibr-Q0-59f" secondAttribute="bottom" constant="8" id="GbR-Aq-I11"/>
<constraint firstItem="cRe-AN-vwd" firstAttribute="firstBaseline" secondItem="CJT-h8-WOU" secondAttribute="firstBaseline" id="MCi-sI-MVD"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="trailing" secondItem="kaT-sZ-PRb" secondAttribute="trailing" id="P6E-96-Sa1"/>
<constraint firstItem="Iwa-5p-7mk" firstAttribute="trailing" secondItem="CJT-h8-WOU" secondAttribute="trailing" id="PdZ-EZ-MFE"/>
<constraint firstItem="kaT-sZ-PRb" firstAttribute="width" secondItem="Iue-dD-GsP" secondAttribute="width" id="QBN-pl-uJx"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="width" secondItem="afr-7l-W3m" secondAttribute="width" multiplier="0.976744" id="QcU-EQ-dE1"/>
<constraint firstItem="Z8O-p3-OZ8" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="UEL-k4-8y5"/>
<constraint firstItem="845-DP-dPF" firstAttribute="top" secondItem="ut3-qV-HGo" secondAttribute="bottom" constant="8" id="VMj-sg-Kt1"/>
<constraint firstAttribute="trailing" secondItem="Ibr-Q0-59f" secondAttribute="trailing" constant="20" symbolic="YES" id="Veg-Nn-zNU"/>
<constraint firstItem="YSm-pR-xTv" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="Vyh-5f-U6w"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="trailing" secondItem="8E0-uI-3yG" secondAttribute="trailing" id="Xlb-u7-BFu"/>
<constraint firstAttribute="trailing" secondItem="845-DP-dPF" secondAttribute="trailing" constant="20" symbolic="YES" id="YM9-q1-Llp"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="trailing" secondItem="sOk-o8-x8Y" secondAttribute="trailing" id="aRG-oR-chG"/>
<constraint firstAttribute="trailing" secondItem="kaT-sZ-PRb" secondAttribute="trailing" constant="20" symbolic="YES" id="akN-hx-yAU"/>
<constraint firstItem="afr-7l-W3m" firstAttribute="leading" secondItem="Iue-dD-GsP" secondAttribute="leading" id="b62-cC-BHf"/>
<constraint firstItem="Iwa-5p-7mk" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="dlv-65-Gpw"/>
<constraint firstItem="BZc-RO-wiZ" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="dmd-yO-P0e"/>
<constraint firstItem="845-DP-dPF" firstAttribute="leading" secondItem="sYl-gL-DD1" secondAttribute="trailing" constant="8" id="fRS-c6-TJH"/>
<constraint firstItem="8E0-uI-3yG" firstAttribute="trailing" secondItem="cRe-AN-vwd" secondAttribute="trailing" id="gJg-Bt-TjU"/>
<constraint firstItem="YqM-5N-NYa" firstAttribute="top" secondItem="sOk-o8-x8Y" secondAttribute="bottom" constant="6" symbolic="YES" id="gvQ-Ce-aV7"/>
<constraint firstAttribute="bottom" secondItem="Z8O-p3-OZ8" secondAttribute="bottom" constant="20" symbolic="YES" id="h7F-0d-wf5"/>
<constraint firstItem="8E0-uI-3yG" firstAttribute="leading" secondItem="Iwa-5p-7mk" secondAttribute="trailing" constant="8" symbolic="YES" id="hEh-E9-3mf"/>
<constraint firstItem="ut3-qV-HGo" firstAttribute="top" secondItem="kaT-sZ-PRb" secondAttribute="bottom" constant="12" symbolic="YES" id="ieU-Cm-0UU"/>
<constraint firstItem="Iue-dD-GsP" firstAttribute="centerY" secondItem="kaT-sZ-PRb" secondAttribute="centerY" id="ioh-tJ-nTg"/>
<constraint firstItem="BZc-RO-wiZ" firstAttribute="top" secondItem="cRe-AN-vwd" secondAttribute="bottom" constant="8" symbolic="YES" id="njJ-FB-0Lx"/>
<constraint firstItem="kaT-sZ-PRb" firstAttribute="top" secondItem="eXx-ny-Tok" secondAttribute="bottom" constant="20" id="oaf-md-6hB"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="firstBaseline" secondItem="BeO-08-nTS" secondAttribute="firstBaseline" id="owM-3i-WiN"/>
<constraint firstItem="Iue-dD-GsP" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="rAV-sg-f9X"/>
<constraint firstItem="nl2-Ws-C1y" firstAttribute="top" secondItem="BZc-RO-wiZ" secondAttribute="bottom" constant="6" symbolic="YES" id="rWH-Er-qvc"/>
<constraint firstAttribute="bottom" secondItem="rg7-go-Amx" secondAttribute="bottom" constant="20" symbolic="YES" id="sRO-gB-luF"/>
<constraint firstAttribute="trailing" secondItem="ut3-qV-HGo" secondAttribute="trailing" constant="20" symbolic="YES" id="tAS-9v-hS2"/>
<constraint firstItem="CJT-h8-WOU" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="ue1-b9-0Pf"/>
<constraint firstItem="sOk-o8-x8Y" firstAttribute="top" secondItem="8E0-uI-3yG" secondAttribute="bottom" constant="8" symbolic="YES" id="vyx-CZ-GGc"/>
<constraint firstItem="Iwa-5p-7mk" firstAttribute="top" secondItem="YSm-pR-xTv" secondAttribute="bottom" constant="20" id="wUM-tZ-zSl"/>
<constraint firstItem="cRe-AN-vwd" firstAttribute="leading" secondItem="CJT-h8-WOU" secondAttribute="trailing" constant="8" symbolic="YES" id="wfC-Pj-ztm"/>
<constraint firstItem="Z8O-p3-OZ8" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="xcs-0y-Ngl"/>
<constraint firstItem="BeO-08-nTS" firstAttribute="leading" secondItem="Z8O-p3-OZ8" secondAttribute="trailing" constant="8" symbolic="YES" id="z6G-Zq-7Sd"/>
<constraint firstAttribute="trailing" secondItem="cRe-AN-vwd" secondAttribute="trailing" constant="20" symbolic="YES" id="zdu-96-81C"/>
<constraint firstItem="eXx-ny-Tok" firstAttribute="leading" secondItem="BeO-08-nTS" secondAttribute="trailing" constant="8" symbolic="YES" id="zfC-Qb-ttb"/>
</constraints>
<point key="canvasLocation" x="165" y="148"/>
</customView>
<menuItem title="3 Bytes" id="E3F-R1-gur"/>
<userDefaultsController representsSharedInstance="YES" id="DTR-NK-B52"/>
</objects>
<resources>
<image name="NSAddTemplate" width="18" height="16"/>
<image name="NSRemoveTemplate" width="18" height="4"/>
</resources>
</document>

View File

@ -15,13 +15,14 @@
(c) Copyright 2004 Alexander and Sander (c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger (c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt (c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2022 Michael Donald Buckley (c) Copyright 2019 - 2023 Michael Donald Buckley
***********************************************************************************/ ***********************************************************************************/
#import <snes9x_framework/snes9x_framework.h> #import <snes9x_framework/snes9x_framework.h>
#import "S9xCheatsViewController.h" #import "S9xCheatsViewController.h"
#import "S9xCheatEditViewController.h" #import "S9xCheatEditViewController.h"
#import "S9xHexNumberFormatter.h"
@interface S9xCheatsViewController () <NSTableViewDataSource, NSTableViewDelegate> @interface S9xCheatsViewController () <NSTableViewDataSource, NSTableViewDelegate>
@ -48,6 +49,12 @@
[self reloadData]; [self reloadData];
} }
- (void)viewWillAppear
{
[super viewWillAppear];
[self.tableView sizeLastColumnToFit];
}
- (void)deselectAll - (void)deselectAll
{ {
[self.tableView deselectAll:nil]; [self.tableView deselectAll:nil];
@ -165,82 +172,6 @@
@end @end
@interface S9xHexNumberFormatter : NSFormatter
@end
@implementation S9xHexNumberFormatter
+ (NSUInteger)maxLength
{
return NSUIntegerMax;
}
- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error
{
if (string.length > 0)
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
*obj = @(value);
return YES;
}
return NO;
}
- (NSNumber *)numberFromString:(NSString *)string
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
return @(value);
}
- (NSString *)stringForObjectValue:(id)obj
{
if ([obj isKindOfClass:NSNumber.class])
{
return [NSString stringWithFormat:@"%X", ((NSNumber *)obj).unsignedIntValue];
}
else if ([obj isKindOfClass:NSString.class])
{
return obj;
}
return @"";
}
- (BOOL)isPartialStringValid:(NSString * _Nonnull * _Nonnull)partialStringPtr proposedSelectedRange:(nullable NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString * _Nullable * _Nullable)error
{
static NSCharacterSet *hexCharacterSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
hexCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"] invertedSet];
});
if ( [*partialStringPtr rangeOfCharacterFromSet:hexCharacterSet].location != NSNotFound )
{
*partialStringPtr = nil;
return NO;
}
*partialStringPtr = (*partialStringPtr).uppercaseString;
if ( (*partialStringPtr).length > self.class.maxLength )
{
*partialStringPtr = [*partialStringPtr substringToIndex:self.class.maxLength];
return NO;
}
return YES;
}
@end
@interface S9xAddressFormatter : S9xHexNumberFormatter @interface S9xAddressFormatter : S9xHexNumberFormatter
@end @end

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>
@ -243,7 +243,7 @@
</customView> </customView>
</objects> </objects>
<resources> <resources>
<image name="NSAddTemplate" width="15" height="13"/> <image name="NSAddTemplate" width="18" height="16"/>
<image name="NSRemoveTemplate" width="15" height="4"/> <image name="NSRemoveTemplate" width="18" height="4"/>
</resources> </resources>
</document> </document>

View File

@ -15,19 +15,15 @@
(c) Copyright 2004 Alexander and Sander (c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger (c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt (c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 Michael Donald Buckley (c) Copyright 2019 - 2023 Michael Donald Buckley
***********************************************************************************/ ***********************************************************************************/
#import <Foundation/Foundation.h>
#ifndef _mac_cheatfinder_h_ NS_ASSUME_NONNULL_BEGIN
#define _mac_cheatfinder_h_
extern Boolean cfIsWatching; @interface S9xHexNumberFormatter : NSNumberFormatter
void CheatFinder (void); @end
void InitCheatFinder (void);
void ResetCheatFinder (void);
void DeinitCheatFinder (void);
void CheatFinderDrawWatchAddr (void);
#endif NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,94 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
(c) Copyright 2019 - 2023 Michael Donald Buckley
***********************************************************************************/
#import "S9xHexNumberFormatter.h"
@implementation S9xHexNumberFormatter
+ (NSUInteger)maxLength
{
return NSUIntegerMax;
}
- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error
{
if (string.length > 0)
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
*obj = @(value);
return YES;
}
return NO;
}
- (NSNumber *)numberFromString:(NSString *)string
{
unsigned int value = 0;
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanHexInt:&value];
return @(value);
}
- (NSString *)stringForObjectValue:(id)obj
{
if ([obj isKindOfClass:NSNumber.class])
{
return [NSString stringWithFormat:@"%X", ((NSNumber *)obj).unsignedIntValue];
}
else if ([obj isKindOfClass:NSString.class])
{
return obj;
}
return @"";
}
- (BOOL)isPartialStringValid:(NSString * _Nonnull * _Nonnull)partialStringPtr proposedSelectedRange:(nullable NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString * _Nullable * _Nullable)error
{
static NSCharacterSet *hexCharacterSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
hexCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"] invertedSet];
});
if ( [*partialStringPtr rangeOfCharacterFromSet:hexCharacterSet].location != NSNotFound )
{
*partialStringPtr = nil;
return NO;
}
*partialStringPtr = (*partialStringPtr).uppercaseString;
if ( (*partialStringPtr).length > self.class.maxLength )
{
*partialStringPtr = [*partialStringPtr substringToIndex:self.class.maxLength];
return NO;
}
return YES;
}
@end

File diff suppressed because it is too large Load Diff

View File

@ -137,8 +137,16 @@ extern bool8 pressedKeys[MAC_MAX_PLAYERS][kNumButtons];
extern bool8 pressedGamepadButtons[MAC_MAX_PLAYERS][kNumButtons]; extern bool8 pressedGamepadButtons[MAC_MAX_PLAYERS][kNumButtons];
extern pthread_mutex_t keyLock; extern pthread_mutex_t keyLock;
@protocol S9xEmulationDelegate <NSObject>
- (void)gameLoaded;
- (void)emulationPaused;
- (void)emulationResumed;
@end
@interface S9xView: MTKView @interface S9xView: MTKView
- (void)updatePauseOverlay; - (void)updatePauseOverlay;
@property (nonatomic, weak) id<S9xEmulationDelegate> emulationDelegate;
@end @end
extern S9xView *s9xView; extern S9xView *s9xView;
@ -166,6 +174,21 @@ void CopyPressedKeys(uint8 keys[MAC_MAX_PLAYERS][kNumButtons], uint8 gamepadButt
@property (nonatomic, assign) S9xButtonCode buttonCode; @property (nonatomic, assign) S9xButtonCode buttonCode;
@end @end
typedef NS_ENUM(uint32_t, S9xWatchPointFormat)
{
S9xWatchPointFormatUnsigned = 1,
S9xWatchPointFormatSigned = 2,
S9xWatchPointFormatHex = 3
};
@interface S9xWatchPoint: NSObject
@property (nonatomic, assign) uint32_t address;
@property (nonatomic, assign) uint32_t size;
@property (nonatomic, assign) S9xWatchPointFormat format;
@end
@protocol S9xInputDelegate <NSObject> @protocol S9xInputDelegate <NSObject>
- (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad; - (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad;
- (void)deviceSettingChanged:(S9xDeviceSetting)deviceSetting; - (void)deviceSettingChanged:(S9xDeviceSetting)deviceSetting;
@ -173,9 +196,10 @@ void CopyPressedKeys(uint8 keys[MAC_MAX_PLAYERS][kNumButtons], uint8 gamepadButt
extern id<S9xInputDelegate> inputDelegate; extern id<S9xInputDelegate> inputDelegate;
@interface S9xEngine : NSObject @interface S9xEngine : NSObject <S9xEmulationDelegate>
@property (nonatomic, weak) id<S9xInputDelegate> inputDelegate; @property (nonatomic, weak) id<S9xInputDelegate> inputDelegate;
@property (nonatomic, weak) id<S9xEmulationDelegate> emulationDelegate;
@property (nonatomic, assign) BOOL cheatsEnabled; @property (nonatomic, assign) BOOL cheatsEnabled;
@ -221,6 +245,11 @@ extern id<S9xInputDelegate> inputDelegate;
- (void)setSeparateEchoBufferFromRAM:(BOOL)flag; - (void)setSeparateEchoBufferFromRAM:(BOOL)flag;
- (void)setDisableSpriteLimit:(BOOL)flag; - (void)setDisableSpriteLimit:(BOOL)flag;
- (void)copyRAM:(uint8_t *)buffer length:(size_t)length;
- (NSArray<S9xWatchPoint *> *)getWatchPoints;
- (void)setWatchPoints:(NSArray<S9xWatchPoint *> *)watchPoints;
@end @end
#endif #endif

View File

@ -47,7 +47,6 @@
#import "mac-prefix.h" #import "mac-prefix.h"
#import "mac-audio.h" #import "mac-audio.h"
#import "mac-cheat.h" #import "mac-cheat.h"
#import "mac-cheatfinder.h"
#import "mac-cocoatools.h" #import "mac-cocoatools.h"
#import "mac-controls.h" #import "mac-controls.h"
#import "mac-dialog.h" #import "mac-dialog.h"
@ -339,11 +338,15 @@ static inline void EmulationLoop (void)
bool8 olddisplayframerate = false; bool8 olddisplayframerate = false;
int storedMacFrameSkip = macFrameSkip; int storedMacFrameSkip = macFrameSkip;
if (pauseEmulation)
{
[s9xView.emulationDelegate emulationResumed];
}
pauseEmulation = false; pauseEmulation = false;
frameAdvance = false; frameAdvance = false;
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
if (macQTRecord) if (macQTRecord)
{ {
olddisplayframerate = Settings.DisplayFrameRate; olddisplayframerate = Settings.DisplayFrameRate;
@ -2227,6 +2230,16 @@ static void ProcessInput (void)
case ToggleEmulationPause: case ToggleEmulationPause:
pauseEmulation = !pauseEmulation; pauseEmulation = !pauseEmulation;
if (pauseEmulation)
{
[s9xView.emulationDelegate emulationPaused];
}
else
{
[s9xView.emulationDelegate emulationResumed];
}
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
break; break;
@ -2252,6 +2265,16 @@ static void ProcessInput (void)
{ {
escKeyDown = true; escKeyDown = true;
pauseEmulation = !pauseEmulation; pauseEmulation = !pauseEmulation;
if (pauseEmulation)
{
[s9xView.emulationDelegate emulationPaused];
}
else
{
[s9xView.emulationDelegate emulationResumed];
}
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
dispatch_async(dispatch_get_main_queue(), ^ dispatch_async(dispatch_get_main_queue(), ^
@ -2504,6 +2527,7 @@ static void Initialize (void)
Settings.MultiPlayer5Master = true; Settings.MultiPlayer5Master = true;
Settings.FrameTimePAL = 20000; Settings.FrameTimePAL = 20000;
Settings.FrameTimeNTSC = 16667; Settings.FrameTimeNTSC = 16667;
Settings.DisplayWatchedAddresses = true;
Settings.SixteenBitSound = true; Settings.SixteenBitSound = true;
Settings.Stereo = true; Settings.Stereo = true;
Settings.SoundPlaybackRate = 32000; Settings.SoundPlaybackRate = 32000;
@ -2540,7 +2564,6 @@ static void Initialize (void)
InitKeyboard(); InitKeyboard();
InitAutofire(); InitAutofire();
InitCheatFinder();
InitGraphics(); InitGraphics();
InitMacSound(); InitMacSound();
@ -2577,7 +2600,6 @@ static void Deinitialize (void)
DeinitMultiCart(); DeinitMultiCart();
ReleaseHID(); ReleaseHID();
DeinitCheatFinder();
DeinitGraphics(); DeinitGraphics();
DeinitKeyboard(); DeinitKeyboard();
DeinitMacSound(); DeinitMacSound();
@ -2914,6 +2936,8 @@ void QuitWithFatalError ( NSString *message)
else else
{ {
pauseEmulation = true; pauseEmulation = true;
[self.emulationDelegate emulationPaused];
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
} }
} }
@ -3116,6 +3140,7 @@ void QuitWithFatalError ( NSString *message)
[s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_WIDTH * 2.0]]; [s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_WIDTH * 2.0]];
[s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_HEIGHT * 2.0]]; [s9xView addConstraint:[NSLayoutConstraint constraintWithItem:s9xView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_HEIGHT * 2.0]];
s9xView.device = MTLCreateSystemDefaultDevice(); s9xView.device = MTLCreateSystemDefaultDevice();
s9xView.emulationDelegate = self;
S9xInitDisplay(NULL, NULL); S9xInitDisplay(NULL, NULL);
} }
@ -3175,6 +3200,7 @@ void QuitWithFatalError ( NSString *message)
- (void)pause - (void)pause
{ {
pauseEmulation = true; pauseEmulation = true;
[self.emulationDelegate emulationPaused];
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
} }
@ -3187,6 +3213,7 @@ void QuitWithFatalError ( NSString *message)
- (void)resume - (void)resume
{ {
pauseEmulation = false; pauseEmulation = false;
[self.emulationDelegate emulationResumed];
[s9xView updatePauseOverlay]; [s9xView updatePauseOverlay];
} }
@ -3313,6 +3340,8 @@ void QuitWithFatalError ( NSString *message)
if ( SNES9X_OpenCart(fileURL) ) if ( SNES9X_OpenCart(fileURL) )
{ {
[self.emulationDelegate gameLoaded];
SNES9X_Go(); SNES9X_Go();
s9xView.window.title = fileURL.lastPathComponent.stringByDeletingPathExtension; s9xView.window.title = fileURL.lastPathComponent.stringByDeletingPathExtension;
[s9xView.window makeKeyAndOrderFront:nil]; [s9xView.window makeKeyAndOrderFront:nil];
@ -3420,6 +3449,86 @@ void QuitWithFatalError ( NSString *message)
Cheat.enabled = cheatsEnabled; Cheat.enabled = cheatsEnabled;
} }
- (void)copyRAM:(uint8_t *)buffer length:(size_t)length
{
if ( length > 0x20000)
{
length = 0x20000;
}
memcpy(buffer, Memory.RAM, length);
}
- (NSArray<S9xWatchPoint *> *)getWatchPoints
{
NSMutableArray<S9xWatchPoint *> *watchPoints = [NSMutableArray new];
for (NSUInteger i = 0; i < sizeof(watches)/sizeof(*watches); ++i)
{
if (watches[i].on)
{
S9xWatchPoint *watchPoint = [S9xWatchPoint new];
watchPoint.address = watches[i].address;
watchPoint.size = watches[i].size;
watchPoint.format = (S9xWatchPointFormat)watches[i].format;
[watchPoints insertObject:watchPoint atIndex:0];
}
}
return watchPoints;
}
- (void)setWatchPoints:(NSArray<S9xWatchPoint *> *)watchPoints
{
memset(watches, 0, sizeof(watches));
NSUInteger i = 0;
for (S9xWatchPoint *watchPoint in watchPoints.reverseObjectEnumerator)
{
uint32_t address = watchPoint.address;
watches[i].on = true;
watches[i].address = address;
watches[i].size = watchPoint.size;
watches[i].format = watchPoint.format;
if(address < 0x7E0000 + 0x20000)
{
snprintf(watches[i].desc, sizeof(watches[i].desc), "%6X", address);
}
else if(address < 0x7E0000 + 0x30000)
{
snprintf(watches[i].desc, sizeof(watches[i].desc), "s%05X", address - 0x7E0000 - 0x20000);
}
else
{
snprintf(watches[i].desc, sizeof(watches[i].desc), "i%05X", address - 0x7E0000 - 0x30000);
}
++i;
if (i == 16)
{
break;
}
}
}
- (void)gameLoaded
{
[self.emulationDelegate gameLoaded];
}
- (void)emulationPaused
{
[self.emulationDelegate emulationPaused];
}
- (void)emulationResumed
{
[self.emulationDelegate emulationResumed];
}
@end @end
@implementation S9xJoypad @implementation S9xJoypad
@ -3439,3 +3548,6 @@ void QuitWithFatalError ( NSString *message)
@implementation S9xJoypadInput @implementation S9xJoypadInput
@end @end
@implementation S9xWatchPoint
@end

View File

@ -21,6 +21,7 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "snes9x.h" #include "snes9x.h"
#include "cheats.h"
#include "memmap.h" #include "memmap.h"
#include "apu.h" #include "apu.h"
#include "display.h" #include "display.h"
@ -29,7 +30,6 @@
#include <sys/time.h> #include <sys/time.h>
#include "mac-prefix.h" #include "mac-prefix.h"
#include "mac-cheatfinder.h"
#include "mac-os.h" #include "mac-os.h"
#include "mac-screenshot.h" #include "mac-screenshot.h"
#include "mac-render.h" #include "mac-render.h"
@ -234,8 +234,29 @@ bool8 S9xContinueUpdate (int width, int height)
void S9xPutImage (int width, int height) void S9xPutImage (int width, int height)
{ {
if (cfIsWatching) for(unsigned int i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++)
CheatFinderDrawWatchAddr(); {
if(watches[i].on)
{
int address = watches[i].address - 0x7E0000;
const uint8* source;
if(address < 0x20000)
{
source = Memory.RAM + address;
}
else if(address < 0x30000)
{
source = Memory.SRAM + address - 0x20000;
}
else
{
source = Memory.FillRAM + address - 0x30000;
}
memcpy(&(Cheat.CWatchRAM[address]), source, watches[i].size);
}
}
if (Settings.DisplayFrameRate) if (Settings.DisplayFrameRate)
{ {

View File

@ -32,7 +32,6 @@
#include "mac-prefix.h" #include "mac-prefix.h"
#include "mac-audio.h" #include "mac-audio.h"
#include "mac-cart.h" #include "mac-cart.h"
#include "mac-cheatfinder.h"
#include "mac-dialog.h" #include "mac-dialog.h"
#include "mac-file.h" #include "mac-file.h"
#include "mac-multicart.h" #include "mac-multicart.h"
@ -62,8 +61,6 @@ bool8 SNES9X_OpenCart (NSURL *inRef)
S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
} }
ResetCheatFinder();
if (!inRef) if (!inRef)
{ {
cartRef = NavOpenROMImage(); cartRef = NavOpenROMImage();
@ -133,8 +130,6 @@ bool8 SNES9X_OpenMultiCart (void)
S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
} }
ResetCheatFinder();
if (!MultiCartDialog()) if (!MultiCartDialog())
{ {
cartOpen = false; cartOpen = false;

View File

@ -49,7 +49,6 @@
307C862122D29E29001B879E /* mac-audio.mm in Sources */ = {isa = PBXBuildFile; fileRef = EADE6347052E5C4300A80003 /* mac-audio.mm */; }; 307C862122D29E29001B879E /* mac-audio.mm in Sources */ = {isa = PBXBuildFile; fileRef = EADE6347052E5C4300A80003 /* mac-audio.mm */; };
307C862222D29E29001B879E /* mac-cart.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67004AC7FCE00A80003 /* mac-cart.mm */; }; 307C862222D29E29001B879E /* mac-cart.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67004AC7FCE00A80003 /* mac-cart.mm */; };
307C862322D29E29001B879E /* mac-cheat.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67204AC7FCE00A80003 /* mac-cheat.mm */; }; 307C862322D29E29001B879E /* mac-cheat.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67204AC7FCE00A80003 /* mac-cheat.mm */; };
307C862422D29E29001B879E /* mac-cheatfinder.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */; };
307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */ = {isa = PBXBuildFile; fileRef = EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */; }; 307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */ = {isa = PBXBuildFile; fileRef = EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */; };
307C862922D29E29001B879E /* mac-gworld.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67904AC7FCE00A80003 /* mac-gworld.mm */; }; 307C862922D29E29001B879E /* mac-gworld.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67904AC7FCE00A80003 /* mac-gworld.mm */; };
307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67D04AC7FCE00A80003 /* mac-keyboard.mm */; }; 307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = EAECB67D04AC7FCE00A80003 /* mac-keyboard.mm */; };
@ -238,6 +237,9 @@
30D709C1236F7E3200AAB7C3 /* S9xPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709BF236F7E3200AAB7C3 /* S9xPreferencesWindowController.m */; }; 30D709C1236F7E3200AAB7C3 /* S9xPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709BF236F7E3200AAB7C3 /* S9xPreferencesWindowController.m */; };
30D709C2236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */; }; 30D709C2236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */; };
30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */; }; 30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */; };
30F727EE29C7B365000235A8 /* S9xCheatFinderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */; };
30F727EF29C7B365000235A8 /* S9xCheatFinderViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */; };
30F72A8E29CCF8E2000235A8 /* S9xHexNumberFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -347,6 +349,11 @@
30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xPreferencesWindowController.xib; sourceTree = "<group>"; }; 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xPreferencesWindowController.xib; sourceTree = "<group>"; };
30D709C3236F90DF00AAB7C3 /* S9xButtonConfigTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xButtonConfigTextField.h; sourceTree = "<group>"; }; 30D709C3236F90DF00AAB7C3 /* S9xButtonConfigTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xButtonConfigTextField.h; sourceTree = "<group>"; };
30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xButtonConfigTextField.m; sourceTree = "<group>"; }; 30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xButtonConfigTextField.m; sourceTree = "<group>"; };
30F727EB29C7B365000235A8 /* S9xCheatFinderViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xCheatFinderViewController.h; sourceTree = "<group>"; };
30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xCheatFinderViewController.m; sourceTree = "<group>"; };
30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xCheatFinderViewController.xib; sourceTree = "<group>"; };
30F72A8C29CCF8E2000235A8 /* S9xHexNumberFormatter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xHexNumberFormatter.h; sourceTree = "<group>"; };
30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xHexNumberFormatter.m; sourceTree = "<group>"; };
85FEF90620DDB15B00C038E9 /* bml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bml.cpp; sourceTree = "<group>"; usesTabs = 1; }; 85FEF90620DDB15B00C038E9 /* bml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bml.cpp; sourceTree = "<group>"; usesTabs = 1; };
85FEF90720DDB15C00C038E9 /* bml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bml.h; sourceTree = "<group>"; usesTabs = 1; }; 85FEF90720DDB15C00C038E9 /* bml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bml.h; sourceTree = "<group>"; usesTabs = 1; };
85FEF90A20DDB18D00C038E9 /* sha256.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sha256.cpp; sourceTree = "<group>"; usesTabs = 1; }; 85FEF90A20DDB18D00C038E9 /* sha256.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sha256.cpp; sourceTree = "<group>"; usesTabs = 1; };
@ -548,8 +555,6 @@
EAECB67104AC7FCE00A80003 /* mac-cart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cart.h"; sourceTree = "<group>"; }; EAECB67104AC7FCE00A80003 /* mac-cart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cart.h"; sourceTree = "<group>"; };
EAECB67204AC7FCE00A80003 /* mac-cheat.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheat.mm"; sourceTree = "<group>"; }; EAECB67204AC7FCE00A80003 /* mac-cheat.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheat.mm"; sourceTree = "<group>"; };
EAECB67304AC7FCE00A80003 /* mac-cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheat.h"; sourceTree = "<group>"; }; EAECB67304AC7FCE00A80003 /* mac-cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheat.h"; sourceTree = "<group>"; };
EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheatfinder.mm"; sourceTree = "<group>"; };
EAECB67504AC7FCE00A80003 /* mac-cheatfinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheatfinder.h"; sourceTree = "<group>"; };
EAECB67904AC7FCE00A80003 /* mac-gworld.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-gworld.mm"; sourceTree = "<group>"; }; EAECB67904AC7FCE00A80003 /* mac-gworld.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-gworld.mm"; sourceTree = "<group>"; };
EAECB67A04AC7FCE00A80003 /* mac-gworld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-gworld.h"; sourceTree = "<group>"; }; EAECB67A04AC7FCE00A80003 /* mac-gworld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-gworld.h"; sourceTree = "<group>"; };
EAECB67B04AC7FCE00A80003 /* mac-joypad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-joypad.mm"; sourceTree = "<group>"; }; EAECB67B04AC7FCE00A80003 /* mac-joypad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-joypad.mm"; sourceTree = "<group>"; };
@ -715,6 +720,11 @@
30CF849927AF0C61002B37A9 /* S9xCheatEditViewController.h */, 30CF849927AF0C61002B37A9 /* S9xCheatEditViewController.h */,
30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */, 30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */,
30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */, 30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */,
30F727EB29C7B365000235A8 /* S9xCheatFinderViewController.h */,
30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */,
30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */,
30F72A8C29CCF8E2000235A8 /* S9xHexNumberFormatter.h */,
30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */,
); );
path = Cheats; path = Cheats;
sourceTree = "<group>"; sourceTree = "<group>";
@ -998,7 +1008,6 @@
EADE6349052E5C5300A80003 /* mac-audio.h */, EADE6349052E5C5300A80003 /* mac-audio.h */,
EAECB67104AC7FCE00A80003 /* mac-cart.h */, EAECB67104AC7FCE00A80003 /* mac-cart.h */,
EAECB67304AC7FCE00A80003 /* mac-cheat.h */, EAECB67304AC7FCE00A80003 /* mac-cheat.h */,
EAECB67504AC7FCE00A80003 /* mac-cheatfinder.h */,
EA85C24D0B4EC13300F5F9C9 /* mac-cocoatools.h */, EA85C24D0B4EC13300F5F9C9 /* mac-cocoatools.h */,
EA809F9D08F8F2190072CDFB /* mac-controls.h */, EA809F9D08F8F2190072CDFB /* mac-controls.h */,
EA2DBC0A0510ABE700A80003 /* mac-file.h */, EA2DBC0A0510ABE700A80003 /* mac-file.h */,
@ -1021,7 +1030,6 @@
EADE6347052E5C4300A80003 /* mac-audio.mm */, EADE6347052E5C4300A80003 /* mac-audio.mm */,
EAECB67004AC7FCE00A80003 /* mac-cart.mm */, EAECB67004AC7FCE00A80003 /* mac-cart.mm */,
EAECB67204AC7FCE00A80003 /* mac-cheat.mm */, EAECB67204AC7FCE00A80003 /* mac-cheat.mm */,
EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */,
EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */, EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */,
EA809FA108F8F2420072CDFB /* mac-controls.mm */, EA809FA108F8F2420072CDFB /* mac-controls.mm */,
EA2DBC0C0510ABE700A80003 /* mac-file.mm */, EA2DBC0C0510ABE700A80003 /* mac-file.mm */,
@ -1256,6 +1264,7 @@
306937CB2635EE5800007ABB /* S9xDisplayPreferencesViewController.xib in Resources */, 306937CB2635EE5800007ABB /* S9xDisplayPreferencesViewController.xib in Resources */,
306937E92636365100007ABB /* S9xFilesPreferencesViewController.xib in Resources */, 306937E92636365100007ABB /* S9xFilesPreferencesViewController.xib in Resources */,
30D709B0236F583600AAB7C3 /* Localizable.strings in Resources */, 30D709B0236F583600AAB7C3 /* Localizable.strings in Resources */,
30F727EF29C7B365000235A8 /* S9xCheatFinderViewController.xib in Resources */,
304B364A262E328400F8DC8E /* S9xControlsPreferencesViewController.xib in Resources */, 304B364A262E328400F8DC8E /* S9xControlsPreferencesViewController.xib in Resources */,
30D709B1236F585100AAB7C3 /* Snes9x Help in Resources */, 30D709B1236F585100AAB7C3 /* Snes9x Help in Resources */,
30D709B3236F731B00AAB7C3 /* SRAM.icns in Resources */, 30D709B3236F731B00AAB7C3 /* SRAM.icns in Resources */,
@ -1295,6 +1304,8 @@
309C54802627F3060055DD95 /* S9xControlsPreferencesViewController.m in Sources */, 309C54802627F3060055DD95 /* S9xControlsPreferencesViewController.m in Sources */,
30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */, 30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */,
306937E82636365100007ABB /* S9xFilesPreferencesViewController.m in Sources */, 306937E82636365100007ABB /* S9xFilesPreferencesViewController.m in Sources */,
30F72A8E29CCF8E2000235A8 /* S9xHexNumberFormatter.m in Sources */,
30F727EE29C7B365000235A8 /* S9xCheatFinderViewController.m in Sources */,
30CF849C27AF0C61002B37A9 /* S9xCheatEditViewController.m in Sources */, 30CF849C27AF0C61002B37A9 /* S9xCheatEditViewController.m in Sources */,
306937D02636253900007ABB /* S9xPreferencesTabViewController.m in Sources */, 306937D02636253900007ABB /* S9xPreferencesTabViewController.m in Sources */,
30714721230E379600917F82 /* main.m in Sources */, 30714721230E379600917F82 /* main.m in Sources */,
@ -1315,7 +1326,6 @@
307C862122D29E29001B879E /* mac-audio.mm in Sources */, 307C862122D29E29001B879E /* mac-audio.mm in Sources */,
307C862222D29E29001B879E /* mac-cart.mm in Sources */, 307C862222D29E29001B879E /* mac-cart.mm in Sources */,
307C862322D29E29001B879E /* mac-cheat.mm in Sources */, 307C862322D29E29001B879E /* mac-cheat.mm in Sources */,
307C862422D29E29001B879E /* mac-cheatfinder.mm in Sources */,
307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */, 307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */,
307C862922D29E29001B879E /* mac-gworld.mm in Sources */, 307C862922D29E29001B879E /* mac-gworld.mm in Sources */,
307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */, 307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */,