From 2e568452c0f2df5655732945c8fea5bc67f49a36 Mon Sep 17 00:00:00 2001 From: Michael Buckley Date: Sat, 25 Mar 2023 07:36:29 -0700 Subject: [PATCH] Mac: Rebuilt Cheat Finder --- macosx/Snes9x/AppDelegate.h | 1 + macosx/Snes9x/AppDelegate.m | 40 + macosx/Snes9x/Base.lproj/MainMenu.xib | 12 +- .../Cheats/S9xCheatEditViewController.h | 7 + .../Cheats/S9xCheatEditViewController.m | 4 - .../Cheats/S9xCheatEditViewController.xib | 4 +- .../Cheats/S9xCheatFinderViewController.h | 38 + .../Cheats/S9xCheatFinderViewController.m | 927 ++++++++++++ .../Cheats/S9xCheatFinderViewController.xib | 530 +++++++ .../Snes9x/Cheats/S9xCheatsViewController.m | 85 +- .../Snes9x/Cheats/S9xCheatsViewController.xib | 8 +- .../Cheats/S9xHexNumberFormatter.h} | 20 +- macosx/Snes9x/Cheats/S9xHexNumberFormatter.m | 94 ++ macosx/mac-cheatfinder.mm | 1237 ----------------- macosx/mac-os.h | 31 +- macosx/mac-os.mm | 120 +- macosx/mac-render.mm | 27 +- macosx/mac-snes9x.mm | 5 - macosx/snes9x.xcodeproj/project.pbxproj | 22 +- 19 files changed, 1854 insertions(+), 1358 deletions(-) create mode 100644 macosx/Snes9x/Cheats/S9xCheatFinderViewController.h create mode 100644 macosx/Snes9x/Cheats/S9xCheatFinderViewController.m create mode 100644 macosx/Snes9x/Cheats/S9xCheatFinderViewController.xib rename macosx/{mac-cheatfinder.h => Snes9x/Cheats/S9xHexNumberFormatter.h} (62%) mode change 100755 => 100644 create mode 100644 macosx/Snes9x/Cheats/S9xHexNumberFormatter.m delete mode 100755 macosx/mac-cheatfinder.mm diff --git a/macosx/Snes9x/AppDelegate.h b/macosx/Snes9x/AppDelegate.h index eceeb0ad..6943ad58 100644 --- a/macosx/Snes9x/AppDelegate.h +++ b/macosx/Snes9x/AppDelegate.h @@ -33,6 +33,7 @@ extern NSWindowFrameAutosaveName const kMainWindowIdentifier; @property (nonatomic, strong) NSWindow *gameWindow; @property (nonatomic, strong) S9xPreferencesWindowController *preferencesWindowController; @property (nonatomic, strong) NSWindowController *cheatsWindowController; +@property (nonatomic, strong) NSWindowController *cheatFinderWindowController; @property (nonatomic, readonly, assign) S9xDeviceSetting deviceSetting; - (void)setButtonCode:(S9xButtonCode)buttonCode forKeyCode:(int16)keyCode player:(int8)player; diff --git a/macosx/Snes9x/AppDelegate.m b/macosx/Snes9x/AppDelegate.m index 784cc174..f636eb31 100644 --- a/macosx/Snes9x/AppDelegate.m +++ b/macosx/Snes9x/AppDelegate.m @@ -21,9 +21,14 @@ #import #import "AppDelegate.h" #import "S9xPreferencesConstants.h" +#import "S9xCheatFinderViewController.h" NSWindowFrameAutosaveName const kMainWindowIdentifier = @"s9xMainWindow"; NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow"; +NSWindowFrameAutosaveName const kCheatFinderWindowIdentifier = @"s9xCheatFinderWindow"; + +@interface AppDelegate () +@end @implementation AppDelegate @@ -638,4 +643,39 @@ NSWindowFrameAutosaveName const kCheatsWindowIdentifier = @"s9xCheatsWindow"; [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 diff --git a/macosx/Snes9x/Base.lproj/MainMenu.xib b/macosx/Snes9x/Base.lproj/MainMenu.xib index 707adc64..b6c63585 100644 --- a/macosx/Snes9x/Base.lproj/MainMenu.xib +++ b/macosx/Snes9x/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + @@ -404,12 +404,18 @@ - + + + + + + + diff --git a/macosx/Snes9x/Cheats/S9xCheatEditViewController.h b/macosx/Snes9x/Cheats/S9xCheatEditViewController.h index cd8c868f..bcb1c758 100644 --- a/macosx/Snes9x/Cheats/S9xCheatEditViewController.h +++ b/macosx/Snes9x/Cheats/S9xCheatEditViewController.h @@ -28,6 +28,13 @@ NS_ASSUME_NONNULL_BEGIN - (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 NS_ASSUME_NONNULL_END diff --git a/macosx/Snes9x/Cheats/S9xCheatEditViewController.m b/macosx/Snes9x/Cheats/S9xCheatEditViewController.m index 650d1080..f5ec1896 100644 --- a/macosx/Snes9x/Cheats/S9xCheatEditViewController.m +++ b/macosx/Snes9x/Cheats/S9xCheatEditViewController.m @@ -25,10 +25,6 @@ NS_ASSUME_NONNULL_BEGIN @interface S9xCheatEditViewController () -@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 NSButton *saveButton; diff --git a/macosx/Snes9x/Cheats/S9xCheatEditViewController.xib b/macosx/Snes9x/Cheats/S9xCheatEditViewController.xib index 4e82bde9..73690a91 100644 --- a/macosx/Snes9x/Cheats/S9xCheatEditViewController.xib +++ b/macosx/Snes9x/Cheats/S9xCheatEditViewController.xib @@ -1,8 +1,8 @@ - + - + diff --git a/macosx/Snes9x/Cheats/S9xCheatFinderViewController.h b/macosx/Snes9x/Cheats/S9xCheatFinderViewController.h new file mode 100644 index 00000000..f25fcac9 --- /dev/null +++ b/macosx/Snes9x/Cheats/S9xCheatFinderViewController.h @@ -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 + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol S9xCheatFinderDelegate +- (void)addedCheat; +@end + +@interface S9xCheatFinderViewController : NSViewController + +@property (nonatomic, strong) S9xEngine *engine; +@property (nonatomic, weak) id delegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/macosx/Snes9x/Cheats/S9xCheatFinderViewController.m b/macosx/Snes9x/Cheats/S9xCheatFinderViewController.m new file mode 100644 index 00000000..8d8037aa --- /dev/null +++ b/macosx/Snes9x/Cheats/S9xCheatFinderViewController.m @@ -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 + +#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 () + +@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 *_addressRows; + + NSMutableArray *_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 *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 diff --git a/macosx/Snes9x/Cheats/S9xCheatFinderViewController.xib b/macosx/Snes9x/Cheats/S9xCheatFinderViewController.xib new file mode 100644 index 00000000..7e3cb230 --- /dev/null +++ b/macosx/Snes9x/Cheats/S9xCheatFinderViewController.xib @@ -0,0 +1,530 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macosx/Snes9x/Cheats/S9xCheatsViewController.m b/macosx/Snes9x/Cheats/S9xCheatsViewController.m index 86e3fd00..ff889c14 100644 --- a/macosx/Snes9x/Cheats/S9xCheatsViewController.m +++ b/macosx/Snes9x/Cheats/S9xCheatsViewController.m @@ -15,13 +15,14 @@ (c) Copyright 2004 Alexander and Sander (c) Copyright 2004 - 2005 Steven Seeger (c) Copyright 2005 Ryan Vogt - (c) Copyright 2019 - 2022 Michael Donald Buckley + (c) Copyright 2019 - 2023 Michael Donald Buckley ***********************************************************************************/ #import #import "S9xCheatsViewController.h" #import "S9xCheatEditViewController.h" +#import "S9xHexNumberFormatter.h" @interface S9xCheatsViewController () @@ -48,6 +49,12 @@ [self reloadData]; } +- (void)viewWillAppear +{ + [super viewWillAppear]; + [self.tableView sizeLastColumnToFit]; +} + - (void)deselectAll { [self.tableView deselectAll:nil]; @@ -165,82 +172,6 @@ @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 @end diff --git a/macosx/Snes9x/Cheats/S9xCheatsViewController.xib b/macosx/Snes9x/Cheats/S9xCheatsViewController.xib index 2ef097a6..e31e66bf 100644 --- a/macosx/Snes9x/Cheats/S9xCheatsViewController.xib +++ b/macosx/Snes9x/Cheats/S9xCheatsViewController.xib @@ -1,8 +1,8 @@ - + - + @@ -243,7 +243,7 @@ - - + + diff --git a/macosx/mac-cheatfinder.h b/macosx/Snes9x/Cheats/S9xHexNumberFormatter.h old mode 100755 new mode 100644 similarity index 62% rename from macosx/mac-cheatfinder.h rename to macosx/Snes9x/Cheats/S9xHexNumberFormatter.h index 529bebc1..86086959 --- a/macosx/mac-cheatfinder.h +++ b/macosx/Snes9x/Cheats/S9xHexNumberFormatter.h @@ -1,6 +1,6 @@ /*****************************************************************************\ - Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. - This file is licensed under the Snes9x License. + 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. \*****************************************************************************/ @@ -15,19 +15,15 @@ (c) Copyright 2004 Alexander and Sander (c) Copyright 2004 - 2005 Steven Seeger (c) Copyright 2005 Ryan Vogt - (c) Copyright 2019 Michael Donald Buckley + (c) Copyright 2019 - 2023 Michael Donald Buckley ***********************************************************************************/ +#import -#ifndef _mac_cheatfinder_h_ -#define _mac_cheatfinder_h_ +NS_ASSUME_NONNULL_BEGIN -extern Boolean cfIsWatching; +@interface S9xHexNumberFormatter : NSNumberFormatter -void CheatFinder (void); -void InitCheatFinder (void); -void ResetCheatFinder (void); -void DeinitCheatFinder (void); -void CheatFinderDrawWatchAddr (void); +@end -#endif +NS_ASSUME_NONNULL_END diff --git a/macosx/Snes9x/Cheats/S9xHexNumberFormatter.m b/macosx/Snes9x/Cheats/S9xHexNumberFormatter.m new file mode 100644 index 00000000..356d3a5d --- /dev/null +++ b/macosx/Snes9x/Cheats/S9xHexNumberFormatter.m @@ -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 diff --git a/macosx/mac-cheatfinder.mm b/macosx/mac-cheatfinder.mm deleted file mode 100755 index 855caeeb..00000000 --- a/macosx/mac-cheatfinder.mm +++ /dev/null @@ -1,1237 +0,0 @@ -/*****************************************************************************\ - 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 Michael Donald Buckley - ***********************************************************************************/ - - -#include "snes9x.h" -#include "memmap.h" -#include "cheats.h" - -#include "mac-prefix.h" -#include "mac-audio.h" -#include "mac-dialog.h" -#include "mac-os.h" -#include "mac-screenshot.h" -#include "mac-stringtools.h" -#include "mac-cheatfinder.h" - -#define kCFNumBytesPop 'Size' -#define kCFViewModeRad 'Mode' -#define kCFCompModePop 'Math' -#define kCFCompStoredRad 'RSto' -#define kCFCompLastRad 'RLst' -#define kCFCompThisRad 'RThs' -#define kCFCompValueTxt 'CTxt' -#define kCFSearchBtn 'BSea' -#define kCFStoreValueBtn 'BSto' -#define kCFWatchBtn 'BWat' -#define kCFDrawerBtn 'Drwr' -#define kCFWatchAddrTxt 'WTxt' -#define kCFRestoreBtn 'BRes' -#define kCFRemoveBtn 'BRem' -#define kCFAddEntryBtn 'BAdd' -#define kCFUserPane 'Pane' -#define kCFSheetAddrTxt 'AEad' -#define kCFSheetCurrentValueTxt 'AEcv' -#define kCFSheetCheetValueTxt 'AEtx' -#define kCFSheetDescriptionTxt 'AEde' -#define kCFSheetAddBtn 'SHTa' -#define kCFSheetCancelBtn 'SHTc' -#define kCFListView 'List' -#define kCFUpperViews 'UI_T' -#define kCFLowerViews 'UI_B' - -#define kEventScrollableScrollThere 'ESST' -#define kEventCheatFinderList 'ECFL' -#define kControlListLinePart 172 - -#define MAIN_MEMORY_SIZE 0x20000 - -#define kCheatFinderListViewClassID CFSTR("com.snes9x.macos.snes9x.cheatfinder") - -enum -{ - kCFHexadecimal = 1, - kCFSignedDecimal, - kCFUnsignedDecimal -}; - -enum -{ - kCFCompWithStored = 1, - kCFCompWithLast, - kCFCompWithThis -}; - -enum -{ - kCFSearchEqual = 1, - kCFSearchNotEqual, - kCFSearchGreater, - kCFSearchGreaterOrEqual, - kCFSearchLess, - kCFSearchLessOrEqual -}; - -typedef struct -{ - IBNibRef nibRef; - WindowRef main; - WindowRef sheet; - WindowRef drawer; - HIViewRef list; - HIViewRef scroll; - EventHandlerRef sEref; - EventHandlerUPP sUPP; -} WindowData; - -typedef struct -{ - HIViewRef view; - HIPoint originPoint; - HISize lineSize; - Boolean inFocus; -} ListViewData; - -Boolean cfIsWatching = false; - -extern SCheatData Cheat; - -static UInt8 *cfStoredRAM; -static UInt8 *cfLastRAM; -static UInt8 *cfCurrentRAM; -static UInt8 *cfStatusFlag; -static UInt32 *cfAddress; - -static SInt32 cfNumRows; -static SInt32 cfListSelection; - -static SInt32 cfViewMode; -static SInt32 cfCompMode; -static SInt32 cfCompWith; -static UInt32 cfViewNumBytes; -static UInt32 cfWatchAddr; -static Boolean cfIsNewGame; -static Boolean cfIsStored; -static Boolean cfDrawerShow; - -static int cfListAddrColumnWidth; -static char cfWatchTextFormat[32]; -static CTFontRef cfListLineCTFontRef; -#ifdef MAC_TIGER_PANTHER_SUPPORT -static ATSUStyle cfListLineATSUStyle; -#endif - -static HIViewID kCheatFinderListViewID = { 'CHET', 'FNDR' }; - -static void CheatFinderSearch (WindowData *); -static void CheatFinderRestoreList (WindowData *); -static void CheatFinderRemoveFromList (WindowData *); -static void CheatFinderAdjustButtons (WindowData *); -static void CheatFinderBuildResultList (void); -static void CheatFinderHandleAddEntryButton (WindowData *); -static void CheatFinderMakeValueFormat (char *); -static void CheatFinderAddEntry (SInt64, char *); -static void CheatFinderBeginAddEntrySheet (WindowData *); -static void CheatFinderEndAddEntrySheet (WindowData *); -static void CheatFinderListViewScrollToThere (float, ListViewData *); -static void CheatFinderListViewDraw (CGContextRef, HIRect *, ListViewData *); -static float CheatFinderListViewSanityCheck (float, ListViewData *); -static SInt64 CheatFinderReadBytes (UInt8 *, UInt32); -static SInt64 CheatFinderGetValueEditText (ControlRef); -static Boolean CheatFinderCompare (SInt64, SInt64); -static HIViewPartCode CheatFinderListViewFindPart (EventRef, ListViewData *, SInt32 *); - - -void InitCheatFinder (void) -{ - cfStoredRAM = new UInt8 [MAIN_MEMORY_SIZE + 10]; - cfLastRAM = new UInt8 [MAIN_MEMORY_SIZE + 10]; - cfCurrentRAM = new UInt8 [MAIN_MEMORY_SIZE + 10]; - cfStatusFlag = new UInt8 [MAIN_MEMORY_SIZE + 10]; - cfAddress = new UInt32[MAIN_MEMORY_SIZE + 10]; - - if (!cfStoredRAM || !cfLastRAM || !cfCurrentRAM || !cfStatusFlag || !cfAddress) - QuitWithFatalError(@"cheatfinder 01"); - - memset(cfCurrentRAM, 0x00, MAIN_MEMORY_SIZE + 10); - - cfViewMode = kCFUnsignedDecimal; - cfViewNumBytes = 2; - cfCompMode = kCFSearchEqual; - cfCompWith = kCFCompWithThis; - - cfListLineCTFontRef = CTFontCreateWithName(CFSTR("Lucida Sans Typewriter Regular"), 11.0f, NULL); - if (cfListLineCTFontRef == NULL) - { - cfListLineCTFontRef = CTFontCreateWithName(CFSTR("Menlo"), 11.0f, NULL); - if (cfListLineCTFontRef == NULL) - { - cfListLineCTFontRef = CTFontCreateWithName(CFSTR("Monaco"), 11.0f, NULL); - if (cfListLineCTFontRef == NULL) - QuitWithFatalError(@"cheatfinder 02"); - } - } -} - -void ResetCheatFinder (void) -{ - memset(cfStoredRAM, 0x00, MAIN_MEMORY_SIZE); - memset(cfLastRAM, 0x00, MAIN_MEMORY_SIZE); - memset(cfStatusFlag, 0xFF, MAIN_MEMORY_SIZE); - - cfWatchAddr = 0; - cfIsNewGame = true; - cfIsWatching = false; - cfIsStored = false; - cfDrawerShow = false; - - CheatFinderMakeValueFormat(cfWatchTextFormat); -} - -void DeinitCheatFinder (void) -{ - CFRelease(cfListLineCTFontRef); - - delete [] cfStoredRAM; - delete [] cfLastRAM; - delete [] cfCurrentRAM; - delete [] cfStatusFlag; - delete [] cfAddress; -} - -void CheatFinder (void) -{ -// static HIObjectClassRef cfListViewClass = NULL; -// -// OSStatus err; -// HIViewRef ctl; -// HIViewID cid; -// char num[256]; -// WindowData cf; -// EventHandlerRef wEref, pEref; -// EventHandlerUPP wUPP, pUPP; -// EventTypeSpec wEvents[] = { { kEventClassCommand, kEventCommandProcess }, -// { kEventClassCommand, kEventCommandUpdateStatus }, -// { kEventClassWindow, kEventWindowClose } }, -// pEvents[] = { { kEventClassControl, kEventControlDraw } }, -// cEvents[] = { { kEventClassHIObject, kEventHIObjectConstruct }, -// { kEventClassHIObject, kEventHIObjectInitialize }, -// { kEventClassHIObject, kEventHIObjectDestruct }, -// { kEventClassScrollable, kEventScrollableGetInfo }, -// { kEventClassScrollable, kEventScrollableScrollTo }, -// { kEventCheatFinderList, kEventScrollableScrollThere }, -// { kEventClassControl, kEventControlHitTest }, -// { kEventClassControl, kEventControlTrack }, -// { kEventClassControl, kEventControlValueFieldChanged }, -// { kEventClassControl, kEventControlDraw } }; -// -// if (!cartOpen) -// return; -// -// err = CreateNibReference(kMacS9XCFString, &(cf.nibRef)); -// if (err == noErr) -// { -// err = CreateWindowFromNib(cf.nibRef, CFSTR("CheatFinder"), &(cf.main)); -// if (err == noErr) -// { -// err = CreateWindowFromNib(cf.nibRef, CFSTR("CFDrawer"), &(cf.drawer)); -// if (err == noErr) -// { -// memcpy(cfCurrentRAM, Memory.RAM, MAIN_MEMORY_SIZE); -// CheatFinderBuildResultList(); -// -// err = noErr; -// if (!cfListViewClass) -// err = HIObjectRegisterSubclass(kCheatFinderListViewClassID, kHIViewClassID, 0, CheatFinderListViewHandler, GetEventTypeCount(cEvents), cEvents, NULL, &cfListViewClass); -// if (err == noErr) -// { -// HIObjectRef hiObject; -// HIViewRef userpane, scrollview, listview, imageview, root; -// HILayoutInfo layoutinfo; -// HIRect frame; -// HISize minSize; -// CGImageRef image; -// Rect rct; -// float pich; -// -// GetWindowBounds(cf.main, kWindowContentRgn, &rct); -// -// minSize.width = (float) (rct.right - rct.left); -// minSize.height = (float) (rct.bottom - rct.top ); -// err = SetWindowResizeLimits(cf.main, &minSize, NULL); -// -// root = HIViewGetRoot(cf.main); -// cid.id = 0; -// cid.signature = kCFUserPane; -// HIViewFindByID(root, cid, &userpane); -// -// err = HIScrollViewCreate(kHIScrollViewOptionsVertScroll, &scrollview); -// HIViewAddSubview(userpane, scrollview); -// HIViewGetBounds(userpane, &frame); -// cfListAddrColumnWidth = (int) (frame.size.width * 0.4); -// frame.origin.y += 16.0f; -// frame.size.height -= 16.0f; -// frame = CGRectInset(frame, 1.0f, 1.0f); -// HIViewSetFrame(scrollview, &frame); -// HIViewSetVisible(scrollview, true); -// cf.scroll = scrollview; -// -// layoutinfo.version = kHILayoutInfoVersionZero; -// HIViewGetLayoutInfo(scrollview, &layoutinfo); -// -// layoutinfo.binding.top.toView = userpane; -// layoutinfo.binding.top.kind = kHILayoutBindTop; -// layoutinfo.binding.bottom.toView = userpane; -// layoutinfo.binding.bottom.kind = kHILayoutBindBottom; -// layoutinfo.binding.left.toView = userpane; -// layoutinfo.binding.left.kind = kHILayoutBindLeft; -// layoutinfo.binding.right.toView = userpane; -// layoutinfo.binding.right.kind = kHILayoutBindRight; -// HIViewSetLayoutInfo(scrollview, &layoutinfo); -// -// err = HIObjectCreate(kCheatFinderListViewClassID, NULL, &hiObject); -// listview = (HIViewRef) hiObject; -// HIViewAddSubview(scrollview, listview); -// SetControl32BitMinimum(listview, 1); -// SetControl32BitMaximum(listview, cfNumRows); -// SetControl32BitValue(listview, 1); -// HIViewSetVisible(listview, true); -// cf.list = listview; -// -// cid.signature = kCFNumBytesPop; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfViewNumBytes); -// -// cid.signature = kCFViewModeRad; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfViewMode); -// -// cid.signature = kCFCompModePop; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfCompMode); -// -// if (cfIsNewGame || (!cfIsStored && (cfCompWith == kCFCompWithStored))) -// cfCompWith = kCFCompWithThis; -// -// cid.signature = kCFCompStoredRad; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfCompWith == kCFCompWithStored); -// if (cfIsStored) -// ActivateControl(ctl); -// else -// DeactivateControl(ctl); -// -// cid.signature = kCFCompLastRad; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfCompWith == kCFCompWithLast); -// if (!cfIsNewGame) -// ActivateControl(ctl); -// else -// DeactivateControl(ctl); -// -// cid.signature = kCFCompThisRad; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfCompWith == kCFCompWithThis); -// -// cid.signature = kCFCompValueTxt; -// HIViewFindByID(root, cid, &ctl); -// SetEditTextCFString(ctl, CFSTR(""), false); -// err = SetKeyboardFocus(cf.main, ctl, kControlFocusNextPart); -// -// cid.signature = kCFWatchBtn; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfIsWatching); -// -// cid.signature = kCFDrawerBtn; -// HIViewFindByID(root, cid, &ctl); -// SetControl32BitValue(ctl, cfDrawerShow); -// -// cid.signature = kCFWatchAddrTxt; -// HIViewFindByID(root, cid, &ctl); -// if (cfIsWatching) -// { -// sprintf(num, "%06lX", cfWatchAddr + 0x7E0000); -// SetStaticTextCStr(ctl, num, false); -// } -// else -// SetStaticTextCFString(ctl, CFSTR(""), false); -// -// CheatFinderAdjustButtons(&cf); -// -// pUPP = NewEventHandlerUPP(CheatFinderListFrameEventHandler); -// err = InstallControlEventHandler(userpane, pUPP, GetEventTypeCount(pEvents), pEvents, (void *) userpane, &pEref); -// -// wUPP = NewEventHandlerUPP(CheatFinderWindowEventHandler); -// err = InstallWindowEventHandler (cf.main, wUPP, GetEventTypeCount(wEvents), wEvents, (void *) &cf, &wEref); -// -// pich = (float) (IPPU.RenderedScreenHeight >> ((IPPU.RenderedScreenHeight > 256) ? 1 : 0)); -// -// err = SetDrawerParent(cf.drawer, cf.main); -// err = SetDrawerOffsets(cf.drawer, 0.0f, (float) ((rct.bottom - rct.top) - (pich + 37))); -// -// image = CreateGameScreenCGImage(); -// if (image) -// { -// err = HIImageViewCreate(image, &imageview); -// if (err == noErr) -// { -// HIViewFindByID(HIViewGetRoot(cf.drawer), kHIViewWindowContentID, &ctl); -// -// HIViewAddSubview(ctl, imageview); -// HIImageViewSetOpaque(imageview, false); -// HIImageViewSetScaleToFit(imageview, true); -// HIViewSetVisible(imageview, true); -// -// frame.origin.x = 8.0f; -// frame.origin.y = 8.0f; -// frame.size.width = (float) SNES_WIDTH; -// frame.size.height = pich; -// HIViewSetFrame(imageview, &frame); -// } -// } -// -// MoveWindowPosition(cf.main, kWindowCheatFinder, true); -// ShowWindow(cf.main); -// -// if (cfDrawerShow) -// err = OpenDrawer(cf.drawer, kWindowEdgeDefault, false); -// -// err = RunAppModalLoopForWindow(cf.main); -// -// HideWindow(cf.main); -// SaveWindowPosition(cf.main, kWindowCheatFinder); -// -// err = RemoveEventHandler(pEref); -// DisposeEventHandlerUPP(pUPP); -// -// err = RemoveEventHandler(wEref); -// DisposeEventHandlerUPP(wUPP); -// -// if (image) -// CGImageRelease(image); -// } -// -// CFRelease(cf.drawer); -// } -// -// CFRelease(cf.main); -// } -// -// DisposeNibReference(cf.nibRef); -// -// memcpy(cfLastRAM, Memory.RAM, MAIN_MEMORY_SIZE); -// cfIsNewGame = false; -// } -} - -static SInt64 CheatFinderReadBytes (UInt8 *mem, UInt32 addr) -{ - switch (cfViewMode) - { - case kCFSignedDecimal: - { - switch (cfViewNumBytes) - { - case 1: return ((SInt64) (SInt8) mem[addr]); - case 2: return ((SInt64) (SInt16) (mem[addr] | (mem[addr + 1] << 8))); - case 4: return ((SInt64) (SInt32) (mem[addr] | (mem[addr + 1] << 8) | (mem[addr + 2] << 16) | (mem[addr + 3] << 24))); - case 3: return ((SInt64) (((SInt32) ((mem[addr] | (mem[addr + 1] << 8) | (mem[addr + 2] << 16)) << 8)) >> 8)); - } - - break; - } - - case kCFUnsignedDecimal: - case kCFHexadecimal: - { - switch (cfViewNumBytes) - { - case 1: return ((SInt64) (UInt8) mem[addr]); - case 2: return ((SInt64) (UInt16) (mem[addr] | (mem[addr + 1] << 8))); - case 3: return ((SInt64) (UInt32) (mem[addr] | (mem[addr + 1] << 8) | (mem[addr + 2] << 16))); - case 4: return ((SInt64) (UInt32) (mem[addr] | (mem[addr + 1] << 8) | (mem[addr + 2] << 16) | (mem[addr + 3] << 24))); - } - - break; - } - } - - return (0); -} - - -static SInt64 CheatFinderGetValueEditText (HIViewRef control) -{ - SInt64 result = 0; - UInt32 uvalue; - SInt32 svalue; - char num[256]; - - GetEditTextCStr(control, num); - if (num[0] == 0) - { - SetEditTextCFString(control, CFSTR("0"), true); - return (0); - } - - switch (cfViewMode) - { - case kCFSignedDecimal: - { - if (sscanf(num, "%ld", &svalue) == 1) - { - switch (cfViewNumBytes) - { - case 1: - { - if (svalue > 127) - { - svalue = 127; - SetEditTextCFString(control, CFSTR("127"), true); - } - else - if (svalue < -128) - { - svalue = -128; - SetEditTextCFString(control, CFSTR("-128"), true); - } - - break; - } - - case 2: - { - if (svalue > 32767) - { - svalue = 32767; - SetEditTextCFString(control, CFSTR("32767"), true); - } - else - if (svalue < -32768) - { - svalue = -32768; - SetEditTextCFString(control, CFSTR("-32768"), true); - } - - break; - } - - case 3: - { - if (svalue > 8388607) - { - svalue = 8388607; - SetEditTextCFString(control, CFSTR("8388607"), true); - } - else - if (svalue < -8388608) - { - svalue = -8388608; - SetEditTextCFString(control, CFSTR("-8388608"), true); - } - - break; - } - } - } - else - { - svalue = 0; - SetEditTextCFString(control, CFSTR("0"), true); - } - - result = (SInt64) svalue; - - break; - } - - case kCFUnsignedDecimal: - { - if (sscanf(num, "%lu", &uvalue) == 1) - { - switch (cfViewNumBytes) - { - case 1: - { - if (uvalue > 255) - { - uvalue = 255; - SetEditTextCFString(control, CFSTR("255"), true); - } - - break; - } - - case 2: - { - if (uvalue > 65535) - { - uvalue = 65535; - SetEditTextCFString(control, CFSTR("65535"), true); - } - - break; - } - - case 3: - { - if (uvalue > 16777215) - { - uvalue = 16777215; - SetEditTextCFString(control, CFSTR("16777215"), true); - } - - break; - } - } - } - else - { - uvalue = 0; - SetEditTextCFString(control, CFSTR("0"), true); - } - - result = (SInt64) uvalue; - - break; - } - - case kCFHexadecimal: - { - if (sscanf(num, "%lx", &uvalue) == 1) - { - switch (cfViewNumBytes) - { - case 1: - { - if (uvalue > 0xFF) - { - uvalue = 0xFF; - SetEditTextCFString(control, CFSTR("FF"), true); - } - - break; - } - - case 2: - { - if (uvalue > 0xFFFF) - { - uvalue = 0xFFFF; - SetEditTextCFString(control, CFSTR("FFFF"), true); - } - - break; - } - - case 3: - { - if (uvalue > 0xFFFFFF) - { - uvalue = 0xFFFFFF; - SetEditTextCFString(control, CFSTR("FFFFFF"), true); - } - - break; - } - } - } - else - { - uvalue = 0; - SetEditTextCFString(control, CFSTR("0"), true); - } - - result = (SInt64) uvalue; - - break; - } - } - - return (result); -} - -static void CheatFinderSearch (WindowData *cf) -{ -// SInt64 cmpvalue; -// UInt8 *mem; -// -// if (cfCompWith == kCFCompWithThis) -// { -// HIViewRef ctl; -// HIViewID cid = { kCFCompValueTxt, 0 }; -// -// HIViewFindByID(HIViewGetRoot(cf->main), cid, &ctl); -// cmpvalue = CheatFinderGetValueEditText(ctl); -// -// for (int i = 0; i < cfNumRows; i++) -// if (!CheatFinderCompare(CheatFinderReadBytes(cfCurrentRAM, cfAddress[i]), cmpvalue)) -// cfStatusFlag[cfAddress[i]] = 0; -// } -// else -// { -// mem = (cfCompWith == kCFCompWithStored) ? cfStoredRAM : cfLastRAM; -// -// for (int i = 0; i < cfNumRows; i++) -// if (!CheatFinderCompare(CheatFinderReadBytes(cfCurrentRAM, cfAddress[i]), CheatFinderReadBytes(mem, cfAddress[i]))) -// cfStatusFlag[cfAddress[i]] = 0; -// } -// -// CheatFinderBuildResultList(); -// -// SetControl32BitMaximum(cf->list, cfNumRows); -// SetControl32BitValue(cf->list, 1); -} - -static Boolean CheatFinderCompare (SInt64 ramvalue, SInt64 cmpvalue) -{ - switch (cfCompMode) - { - case kCFSearchEqual: return (ramvalue == cmpvalue); - case kCFSearchNotEqual: return (ramvalue != cmpvalue); - case kCFSearchGreater: return (ramvalue > cmpvalue); - case kCFSearchGreaterOrEqual: return (ramvalue >= cmpvalue); - case kCFSearchLess: return (ramvalue < cmpvalue); - case kCFSearchLessOrEqual: return (ramvalue <= cmpvalue); - } - - return (false); -} - -static void CheatFinderBuildResultList (void) -{ - cfNumRows = 0; - - for (int i = 0; i < MAIN_MEMORY_SIZE; i++) - { - if (cfStatusFlag[i] == 0xFF) - { - cfAddress[cfNumRows] = i; - cfNumRows++; - } - } - - cfListSelection = 0; -} - -static void CheatFinderAdjustButtons (WindowData *cf) -{ -// HIViewRef ctl, root; -// HIViewID cid; -// -// cid.id = 0; -// root = HIViewGetRoot(cf->main); -// -// if (cfNumRows > 0) -// { -// cid.signature = kCFAddEntryBtn; -// HIViewFindByID(root, cid, &ctl); -// ActivateControl(ctl); -// -// cid.signature = kCFRemoveBtn; -// HIViewFindByID(root, cid, &ctl); -// ActivateControl(ctl); -// -// cid.signature = kCFWatchBtn; -// HIViewFindByID(root, cid, &ctl); -// ActivateControl(ctl); -// } -// else -// { -// cid.signature = kCFAddEntryBtn; -// HIViewFindByID(root, cid, &ctl); -// DeactivateControl(ctl); -// -// cid.signature = kCFRemoveBtn; -// HIViewFindByID(root, cid, &ctl); -// DeactivateControl(ctl); -// -// if (!cfIsWatching) -// { -// cid.signature = kCFWatchBtn; -// HIViewFindByID(root, cid, &ctl); -// DeactivateControl(ctl); -// } -// } -} - -static void CheatFinderRemoveFromList (WindowData *cf) -{ -// if (cfNumRows > 0) -// { -// cfStatusFlag[cfAddress[cfListSelection]] = 0; -// -// if (cfNumRows == 1) -// { -// cfNumRows = 0; -// -// SetControl32BitMaximum(cf->list, 0); -// SetControl32BitValue(cf->list, 1); -// } -// else -// { -// for (int i = cfListSelection; i < cfNumRows - 1; i++) -// cfAddress[i] = cfAddress[i + 1]; -// -// cfNumRows--; -// if (cfListSelection >= cfNumRows) -// cfListSelection = cfNumRows - 1; -// -// SetControl32BitMaximum(cf->list, cfNumRows); -// SetControl32BitValue(cf->list, cfListSelection + 1); -// } -// } -} - -static void CheatFinderRestoreList (WindowData *cf) -{ -// memset(cfStatusFlag, 0xFF, MAIN_MEMORY_SIZE); -// CheatFinderBuildResultList(); -// -// SetControl32BitMaximum(cf->list, cfNumRows); -// SetControl32BitValue(cf->list, 1); -} - -static void CheatFinderMakeValueFormat (char *text) -{ -// switch (cfViewMode) -// { -// case kCFSignedDecimal: -// case kCFUnsignedDecimal: -// { -// strcpy(text, "%lld"); -// break; -// } -// -// case kCFHexadecimal: -// { -// sprintf(text, "%%0%lullX", cfViewNumBytes * 2); -// break; -// } -// } -} - -void CheatFinderDrawWatchAddr (void) -{ -// static char code[256]; -// -// uint16 *basePtr; -// int len; -// -// sprintf(code, cfWatchTextFormat, CheatFinderReadBytes(Memory.RAM, cfWatchAddr)); -// -// basePtr = GFX.Screen + 1; -// len = strlen(code); -// -// for (int i = 0; i < len; i++) -// { -// S9xDisplayChar(basePtr, code[i]); -// basePtr += (8 - 1); -// } -} - -static void CheatFinderHandleAddEntryButton (WindowData *cf) -{ -// if (cfAddress[cfListSelection] > (0x20000 - cfViewNumBytes)) -// NSBeep(); -// else -// if (Cheat.g.size() + cfViewNumBytes > MAC_MAX_CHEATS) -// AppearanceAlert(kAlertCautionAlert, kS9xMacAlertCFCantAddEntry, kS9xMacAlertCFCantAddEntryHint); -// else -// CheatFinderBeginAddEntrySheet(cf); -} - -static void CheatFinderBeginAddEntrySheet (WindowData *cf) -{ -// OSStatus err; -// HIViewRef ctl, root; -// HIViewID cid; -// UInt32 addr; -// char str[256], form[256]; -// EventTypeSpec sEvents[] = { { kEventClassCommand, kEventCommandProcess }, -// { kEventClassCommand, kEventCommandUpdateStatus } }; -// -// err = CreateWindowFromNib(cf->nibRef, CFSTR("CFAddEntry"), &(cf->sheet)); -// if (err == noErr) -// { -// addr = cfAddress[cfListSelection]; -// -// root = HIViewGetRoot(cf->sheet); -// cid.id = 0; -// -// cid.signature = kCFSheetAddrTxt; -// HIViewFindByID(root, cid, &ctl); -// sprintf(str, "%06lX", addr + 0x7E0000); -// SetStaticTextCStr(ctl, str, false); -// -// cid.signature = kCFSheetCurrentValueTxt; -// HIViewFindByID(root, cid, &ctl); -// CheatFinderMakeValueFormat(form); -// sprintf(str, form, CheatFinderReadBytes(cfCurrentRAM, addr)); -// SetStaticTextCStr(ctl, str, false); -// -// cid.signature = kCFSheetCheetValueTxt; -// HIViewFindByID(root, cid, &ctl); -// SetEditTextCStr(ctl, str, false); -// -// err = ClearKeyboardFocus(cf->sheet); -// err = SetKeyboardFocus(cf->sheet, ctl, kControlFocusNextPart); -// -// cid.signature = kCFSheetDescriptionTxt; -// HIViewFindByID(root, cid, &ctl); -// sprintf(str, "%06lX-%06lX", addr + 0x7E0000, addr + cfViewNumBytes - 1 + 0x7E0000); -// SetStaticTextCStr(ctl, str, false); -// -// cf->sUPP = NewEventHandlerUPP(CheatFinderSheetEventHandler); -// err = InstallWindowEventHandler(cf->sheet, cf->sUPP, GetEventTypeCount(sEvents), sEvents, (void *) cf, &(cf->sEref)); -// -// err = ShowSheetWindow(cf->sheet, cf->main); -// } -} - -static void CheatFinderEndAddEntrySheet (WindowData *cf) -{ -// if (cf->sheet) -// { -// OSStatus err; -// -// err = HideSheetWindow(cf->sheet); -// -// err = RemoveEventHandler(cf->sEref); -// DisposeEventHandlerUPP(cf->sUPP); -// -// CFRelease(cf->sheet); -// } -} - - -static void CheatFinderAddEntry (SInt64 value, char *description) -{ - UInt32 addr, v; - - addr = cfAddress[cfListSelection]; - v = (UInt32) (SInt32) value; - - for (unsigned int i = 0; i < cfViewNumBytes; i++) - { - char code[10]; - snprintf(code, 10, "%x=%x", addr + i + 0x7E0000, (UInt8) ((v & (0x000000FF << (i * 8))) >> (i * 8))); - int index = S9xAddCheatGroup(description, code); - if(index >= 0) - S9xEnableCheatGroup(index); - } -} - -static void CheatFinderListViewDraw (CGContextRef ctx, HIRect *bounds, ListViewData *myData) -{ -// static Boolean init = true; -// -// if (systemVersion >= 0x1050) -// { -// static CGRect aRct, vRct; -// -// CTLineRef line; -// CFDictionaryRef attr; -// CFAttributedStringRef astr; -// CFStringRef str; -// HIRect lineBounds; -// SInt32 start, end, val, max; -// float ax, vx, y, f; -// char format[32], t1[64], t2[64]; -// -// CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName }; -// CFTypeRef bval[] = { cfListLineCTFontRef, CGColorGetConstantColor(kCGColorBlack) }, -// wval[] = { cfListLineCTFontRef, CGColorGetConstantColor(kCGColorWhite) }; -// -// CheatFinderMakeValueFormat(format); -// -// start = (SInt32) (myData->originPoint.y / myData->lineSize.height); -// end = (SInt32) ((myData->originPoint.y + bounds->size.height) / myData->lineSize.height) + 1; -// -// y = start * myData->lineSize.height - myData->originPoint.y; -// -// lineBounds = *bounds; -// lineBounds.size.height = myData->lineSize.height; -// lineBounds.origin.y = y; -// -// val = GetControl32BitValue(myData->view) - 1; -// max = GetControl32BitMaximum(myData->view); -// -// attr = CFDictionaryCreate(kCFAllocatorDefault, (const void **) &keys, (const void **) &bval, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); -// -// CGContextSetTextMatrix(ctx, CGAffineTransformIdentity); -// -// if (init) -// { -// CGContextSetTextPosition(ctx, 0.0f, 0.0f); -// -// astr = CFAttributedStringCreate(kCFAllocatorDefault, CFSTR("FFFFFF"), attr); -// line = CTLineCreateWithAttributedString(astr); -// aRct = CTLineGetImageBounds(line, ctx); -// CFRelease(line); -// CFRelease(astr); -// -// astr = CFAttributedStringCreate(kCFAllocatorDefault, CFSTR("FFFFFFFFFFF"), attr); -// line = CTLineCreateWithAttributedString(astr); -// vRct = CTLineGetImageBounds(line, ctx); -// CFRelease(line); -// CFRelease(astr); -// -// init = false; -// } -// -// ax = (float) (int) (((float) cfListAddrColumnWidth - 2.0 - aRct.size.width) / 2.0); -// vx = (float) (int) (lineBounds.origin.x + lineBounds.size.width - vRct.size.width - 12.0); -// -// for (int i = start; i <= end; i++) -// { -// if ((i == val) && cfNumRows) -// CGContextSetRGBFillColor(ctx, 59.0f / 256.0f, 124.0f / 256.0f, 212.0f / 256.0f, 1.0f); -// else -// if ((i - start) % 2 == 0) -// CGContextSetRGBFillColor(ctx, 256.0f / 256.0f, 256.0f / 256.0f, 256.0f / 256.0f, 1.0f); -// else -// CGContextSetRGBFillColor(ctx, 237.0f / 256.0f, 244.0f / 256.0f, 254.0f / 256.0f, 1.0f); -// -// CGContextFillRect(ctx, lineBounds); -// -// if (i < max) -// { -// CGContextScaleCTM(ctx, 1, -1); -// -// if (i == val) -// { -// CFRelease(attr); -// attr = CFDictionaryCreate(kCFAllocatorDefault, (const void **) &keys, (const void **) &wval, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); -// } -// -// f = -(y + 12.0f); -// -// sprintf(t1, "%06lX", cfAddress[i] + 0x7E0000); -// str = CFStringCreateWithCString(kCFAllocatorDefault, t1, kCFStringEncodingUTF8); -// astr = CFAttributedStringCreate(kCFAllocatorDefault, str, attr); -// line = CTLineCreateWithAttributedString(astr); -// CGContextSetTextPosition(ctx, ax, f); -// CTLineDraw(line, ctx); -// CFRelease(line); -// CFRelease(astr); -// CFRelease(str); -// -// sprintf(t2, format, CheatFinderReadBytes(cfCurrentRAM, cfAddress[i])); -// strcpy(t1, " "); -// t1[11 - strlen(t2)] = 0; -// strcat(t1, t2); -// str = CFStringCreateWithCString(kCFAllocatorDefault, t1, kCFStringEncodingUTF8); -// astr = CFAttributedStringCreate(kCFAllocatorDefault, str, attr); -// line = CTLineCreateWithAttributedString(astr); -// CGContextSetTextPosition(ctx, vx, f); -// CTLineDraw(line, ctx); -// CFRelease(line); -// CFRelease(astr); -// CFRelease(str); -// -// CGContextScaleCTM(ctx, 1, -1); -// -// if (i == val) -// { -// CFRelease(attr); -// attr = CFDictionaryCreate(kCFAllocatorDefault, (const void **) &keys, (const void **) &bval, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); -// } -// } -// -// y += myData->lineSize.height; -// lineBounds.origin.y += myData->lineSize.height; -// } -// -// CFRelease(attr); -// } -//#ifdef MAC_TIGER_PANTHER_SUPPORT -// else -// { -// static Rect aRect = { 0, 0, 0, 0 }, vRect = { 0, 0, 0, 0 }; -// -// OSStatus err; -// ATSUTextLayout layout; -// HIRect lineBounds; -// UniCharCount runLength[1], len; -// SInt32 start, end, val, max; -// Fixed ax, vx, f; -// float y; -// UniChar unistr[64]; -// char format[32], t1[64], t2[64]; -// -// ATSUAttributeTag theTags[] = { kATSUCGContextTag }; -// ByteCount theSizes[] = { sizeof(CGContextRef) }; -// ATSUAttributeValuePtr theValues[] = { &ctx }; -// -// CheatFinderMakeValueFormat(format); -// -// start = (SInt32) (myData->originPoint.y / myData->lineSize.height); -// end = (SInt32) ((myData->originPoint.y + bounds->size.height) / myData->lineSize.height) + 1; -// -// y = start * myData->lineSize.height - myData->originPoint.y; -// -// lineBounds = *bounds; -// lineBounds.size.height = myData->lineSize.height; -// lineBounds.origin.y = y; -// -// val = GetControl32BitValue(myData->view) - 1; -// max = GetControl32BitMaximum(myData->view); -// -// if (init) -// { -// f = Long2Fix(0); -// for (unsigned int n = 0; n < 11; n++) -// unistr[n] = 'F'; -// -// len = runLength[0] = 6; -// err = ATSUCreateTextLayoutWithTextPtr(unistr, kATSUFromTextBeginning, kATSUToTextEnd, len, 1, runLength, &cfListLineATSUStyle, &layout); -// err = ATSUSetLayoutControls(layout, sizeof(theTags) / sizeof(theTags[0]), theTags, theSizes, theValues); -// err = ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, f, f, &aRect); -// err = ATSUDisposeTextLayout(layout); -// -// len = runLength[0] = 11; -// err = ATSUCreateTextLayoutWithTextPtr(unistr, kATSUFromTextBeginning, kATSUToTextEnd, len, 1, runLength, &cfListLineATSUStyle, &layout); -// err = ATSUSetLayoutControls(layout, sizeof(theTags) / sizeof(theTags[0]), theTags, theSizes, theValues); -// err = ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, f, f, &vRect); -// err = ATSUDisposeTextLayout(layout); -// -// init = false; -// } -// -// ax = Long2Fix((cfListAddrColumnWidth - 2 - (aRect.right - aRect.left)) >> 1); -// vx = Long2Fix((int) (lineBounds.origin.x + lineBounds.size.width) - (vRect.right - vRect.left) - 13); -// -// for (int i = start; i <= end; i++) -// { -// if ((i == val) && cfNumRows) -// CGContextSetRGBFillColor(ctx, 59.0f / 256.0f, 124.0f / 256.0f, 212.0f / 256.0f, 1.0f); -// else -// if ((i - start) % 2 == 0) -// CGContextSetRGBFillColor(ctx, 256.0f / 256.0f, 256.0f / 256.0f, 256.0f / 256.0f, 1.0f); -// else -// CGContextSetRGBFillColor(ctx, 237.0f / 256.0f, 244.0f / 256.0f, 254.0f / 256.0f, 1.0f); -// -// CGContextFillRect(ctx, lineBounds); -// -// if (i < max) -// { -// CGContextScaleCTM(ctx, 1, -1); -// -// if (i == val) -// CGContextSetRGBFillColor(ctx, 1.0f, 1.0f, 1.0f, 1.0f); -// else -// CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f); -// -// f = Long2Fix(-((int) y + 12)); -// -// sprintf(t1, "%06lX", cfAddress[i] + 0x7E0000); -// len = runLength[0] = strlen(t1); -// for (unsigned int n = 0; n < len; n++) -// unistr[n] = t1[n]; -// err = ATSUCreateTextLayoutWithTextPtr(unistr, kATSUFromTextBeginning, kATSUToTextEnd, len, 1, runLength, &cfListLineATSUStyle, &layout); -// err = ATSUSetLayoutControls(layout, sizeof(theTags) / sizeof(theTags[0]), theTags, theSizes, theValues); -// err = ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd, ax, f); -// err = ATSUDisposeTextLayout(layout); -// -// sprintf(t2, format, CheatFinderReadBytes(cfCurrentRAM, cfAddress[i])); -// strcpy(t1, " "); -// t1[11 - strlen(t2)] = 0; -// strcat(t1, t2); -// len = runLength[0] = strlen(t1); -// for (unsigned int n = 0; n < len; n++) -// unistr[n] = t1[n]; -// err = ATSUCreateTextLayoutWithTextPtr(unistr, kATSUFromTextBeginning, kATSUToTextEnd, len, 1, runLength, &cfListLineATSUStyle, &layout); -// err = ATSUSetLayoutControls(layout, sizeof(theTags) / sizeof(theTags[0]), theTags, theSizes, theValues); -// err = ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd, vx, f); -// err = ATSUDisposeTextLayout(layout); -// -// CGContextScaleCTM(ctx, 1, -1); -// } -// -// y += myData->lineSize.height; -// lineBounds.origin.y += myData->lineSize.height; -// } -// } -//#endif -} - -static HIViewPartCode CheatFinderListViewFindPart (EventRef inEvent, ListViewData *myData, SInt32 *whichLine) -{ -// OSStatus err; -// HIViewPartCode part; -// HIPoint hipt; -// SInt32 start, line; -// float y; -// -// part = kControlNoPart; -// -// start = (SInt32) (myData->originPoint.y / myData->lineSize.height); -// y = start * myData->lineSize.height - myData->originPoint.y; -// -// err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(hipt), NULL, &hipt); -// if (err == noErr) -// { -// line = start + (SInt32) ((hipt.y - y - 1) / myData->lineSize.height) + 1; -// -// if (line <= GetControl32BitMaximum(myData->view)) -// part = kControlListLinePart; -// -// if (whichLine != NULL) -// *whichLine = line; -// } -// -// return (part); - return 0; -} - -static float CheatFinderListViewSanityCheck (float where, ListViewData *myData) -{ - HIRect bounds; - HISize imageSize; - -// HIViewGetBounds(myData->view, &bounds); -// imageSize = myData->lineSize; -// imageSize.height *= GetControl32BitMaximum(myData->view); - - if (where + bounds.size.height > imageSize.height) - where = imageSize.height - bounds.size.height; - if (where < 0) - where = 0; - - return (where); -} - -static void CheatFinderListViewScrollToThere (float where, ListViewData *myData) -{ - OSStatus err; - EventRef theEvent; - HIPoint whereP = { 0.0f, where }; - - err = CreateEvent(kCFAllocatorDefault, kEventCheatFinderList, kEventScrollableScrollThere, GetCurrentEventTime(), kEventAttributeUserEvent, &theEvent); - if (err == noErr) - { - err = SetEventParameter(theEvent, kEventParamOrigin, typeHIPoint, sizeof(whereP), &whereP); -// if (err == noErr) -// err = SendEventToEventTarget(theEvent, GetControlEventTarget(myData->view)); - - ReleaseEvent(theEvent); - } -} diff --git a/macosx/mac-os.h b/macosx/mac-os.h index 704ab6c7..1b3a6083 100644 --- a/macosx/mac-os.h +++ b/macosx/mac-os.h @@ -137,8 +137,16 @@ extern bool8 pressedKeys[MAC_MAX_PLAYERS][kNumButtons]; extern bool8 pressedGamepadButtons[MAC_MAX_PLAYERS][kNumButtons]; extern pthread_mutex_t keyLock; +@protocol S9xEmulationDelegate +- (void)gameLoaded; +- (void)emulationPaused; +- (void)emulationResumed; +@end + @interface S9xView: MTKView - (void)updatePauseOverlay; + +@property (nonatomic, weak) id emulationDelegate; @end extern S9xView *s9xView; @@ -166,6 +174,21 @@ void CopyPressedKeys(uint8 keys[MAC_MAX_PLAYERS][kNumButtons], uint8 gamepadButt @property (nonatomic, assign) S9xButtonCode buttonCode; @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 - (BOOL)handleInput:(S9xJoypadInput *)input fromJoypad:(S9xJoypad *)joypad; - (void)deviceSettingChanged:(S9xDeviceSetting)deviceSetting; @@ -173,9 +196,10 @@ void CopyPressedKeys(uint8 keys[MAC_MAX_PLAYERS][kNumButtons], uint8 gamepadButt extern id inputDelegate; -@interface S9xEngine : NSObject +@interface S9xEngine : NSObject @property (nonatomic, weak) id inputDelegate; +@property (nonatomic, weak) id emulationDelegate; @property (nonatomic, assign) BOOL cheatsEnabled; @@ -221,6 +245,11 @@ extern id inputDelegate; - (void)setSeparateEchoBufferFromRAM:(BOOL)flag; - (void)setDisableSpriteLimit:(BOOL)flag; +- (void)copyRAM:(uint8_t *)buffer length:(size_t)length; + +- (NSArray *)getWatchPoints; +- (void)setWatchPoints:(NSArray *)watchPoints; + @end #endif diff --git a/macosx/mac-os.mm b/macosx/mac-os.mm index 6f9dda9f..2a80febf 100644 --- a/macosx/mac-os.mm +++ b/macosx/mac-os.mm @@ -47,7 +47,6 @@ #import "mac-prefix.h" #import "mac-audio.h" #import "mac-cheat.h" -#import "mac-cheatfinder.h" #import "mac-cocoatools.h" #import "mac-controls.h" #import "mac-dialog.h" @@ -339,11 +338,15 @@ static inline void EmulationLoop (void) bool8 olddisplayframerate = false; int storedMacFrameSkip = macFrameSkip; + if (pauseEmulation) + { + [s9xView.emulationDelegate emulationResumed]; + } + pauseEmulation = false; frameAdvance = false; [s9xView updatePauseOverlay]; - if (macQTRecord) { olddisplayframerate = Settings.DisplayFrameRate; @@ -2227,6 +2230,16 @@ static void ProcessInput (void) case ToggleEmulationPause: pauseEmulation = !pauseEmulation; + + if (pauseEmulation) + { + [s9xView.emulationDelegate emulationPaused]; + } + else + { + [s9xView.emulationDelegate emulationResumed]; + } + [s9xView updatePauseOverlay]; break; @@ -2252,6 +2265,16 @@ static void ProcessInput (void) { escKeyDown = true; pauseEmulation = !pauseEmulation; + + if (pauseEmulation) + { + [s9xView.emulationDelegate emulationPaused]; + } + else + { + [s9xView.emulationDelegate emulationResumed]; + } + [s9xView updatePauseOverlay]; dispatch_async(dispatch_get_main_queue(), ^ @@ -2504,6 +2527,7 @@ static void Initialize (void) Settings.MultiPlayer5Master = true; Settings.FrameTimePAL = 20000; Settings.FrameTimeNTSC = 16667; + Settings.DisplayWatchedAddresses = true; Settings.SixteenBitSound = true; Settings.Stereo = true; Settings.SoundPlaybackRate = 32000; @@ -2540,7 +2564,6 @@ static void Initialize (void) InitKeyboard(); InitAutofire(); - InitCheatFinder(); InitGraphics(); InitMacSound(); @@ -2577,7 +2600,6 @@ static void Deinitialize (void) DeinitMultiCart(); ReleaseHID(); - DeinitCheatFinder(); DeinitGraphics(); DeinitKeyboard(); DeinitMacSound(); @@ -2914,6 +2936,8 @@ void QuitWithFatalError ( NSString *message) else { pauseEmulation = true; + [self.emulationDelegate emulationPaused]; + [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:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SNES_HEIGHT * 2.0]]; s9xView.device = MTLCreateSystemDefaultDevice(); + s9xView.emulationDelegate = self; S9xInitDisplay(NULL, NULL); } @@ -3175,6 +3200,7 @@ void QuitWithFatalError ( NSString *message) - (void)pause { pauseEmulation = true; + [self.emulationDelegate emulationPaused]; [s9xView updatePauseOverlay]; } @@ -3187,6 +3213,7 @@ void QuitWithFatalError ( NSString *message) - (void)resume { pauseEmulation = false; + [self.emulationDelegate emulationResumed]; [s9xView updatePauseOverlay]; } @@ -3313,6 +3340,8 @@ void QuitWithFatalError ( NSString *message) if ( SNES9X_OpenCart(fileURL) ) { + [self.emulationDelegate gameLoaded]; + SNES9X_Go(); s9xView.window.title = fileURL.lastPathComponent.stringByDeletingPathExtension; [s9xView.window makeKeyAndOrderFront:nil]; @@ -3420,6 +3449,86 @@ void QuitWithFatalError ( NSString *message) Cheat.enabled = cheatsEnabled; } +- (void)copyRAM:(uint8_t *)buffer length:(size_t)length +{ + if ( length > 0x20000) + { + length = 0x20000; + } + + memcpy(buffer, Memory.RAM, length); +} + +- (NSArray *)getWatchPoints +{ + NSMutableArray *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 *)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 @implementation S9xJoypad @@ -3439,3 +3548,6 @@ void QuitWithFatalError ( NSString *message) @implementation S9xJoypadInput @end + +@implementation S9xWatchPoint +@end diff --git a/macosx/mac-render.mm b/macosx/mac-render.mm index a04f2a40..3955582b 100644 --- a/macosx/mac-render.mm +++ b/macosx/mac-render.mm @@ -21,6 +21,7 @@ #import #include "snes9x.h" +#include "cheats.h" #include "memmap.h" #include "apu.h" #include "display.h" @@ -29,7 +30,6 @@ #include #include "mac-prefix.h" -#include "mac-cheatfinder.h" #include "mac-os.h" #include "mac-screenshot.h" #include "mac-render.h" @@ -234,8 +234,29 @@ bool8 S9xContinueUpdate (int width, int height) void S9xPutImage (int width, int height) { - if (cfIsWatching) - CheatFinderDrawWatchAddr(); + for(unsigned int i = 0 ; i < sizeof(watches)/sizeof(*watches) ; i++) + { + 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) { diff --git a/macosx/mac-snes9x.mm b/macosx/mac-snes9x.mm index c751378b..2a83d635 100755 --- a/macosx/mac-snes9x.mm +++ b/macosx/mac-snes9x.mm @@ -32,7 +32,6 @@ #include "mac-prefix.h" #include "mac-audio.h" #include "mac-cart.h" -#include "mac-cheatfinder.h" #include "mac-dialog.h" #include "mac-file.h" #include "mac-multicart.h" @@ -62,8 +61,6 @@ bool8 SNES9X_OpenCart (NSURL *inRef) S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); } - ResetCheatFinder(); - if (!inRef) { cartRef = NavOpenROMImage(); @@ -133,8 +130,6 @@ bool8 SNES9X_OpenMultiCart (void) S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); } - ResetCheatFinder(); - if (!MultiCartDialog()) { cartOpen = false; diff --git a/macosx/snes9x.xcodeproj/project.pbxproj b/macosx/snes9x.xcodeproj/project.pbxproj index 2791245e..ebdb24e5 100755 --- a/macosx/snes9x.xcodeproj/project.pbxproj +++ b/macosx/snes9x.xcodeproj/project.pbxproj @@ -49,7 +49,6 @@ 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 */; }; 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 */; }; 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 */; }; @@ -238,6 +237,9 @@ 30D709C1236F7E3200AAB7C3 /* S9xPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D709BF236F7E3200AAB7C3 /* S9xPreferencesWindowController.m */; }; 30D709C2236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */; }; 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 */ /* Begin PBXContainerItemProxy section */ @@ -347,6 +349,11 @@ 30D709C0236F7E3200AAB7C3 /* S9xPreferencesWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xPreferencesWindowController.xib; sourceTree = ""; }; 30D709C3236F90DF00AAB7C3 /* S9xButtonConfigTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xButtonConfigTextField.h; sourceTree = ""; }; 30D709C4236F90DF00AAB7C3 /* S9xButtonConfigTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xButtonConfigTextField.m; sourceTree = ""; }; + 30F727EB29C7B365000235A8 /* S9xCheatFinderViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xCheatFinderViewController.h; sourceTree = ""; }; + 30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xCheatFinderViewController.m; sourceTree = ""; }; + 30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = S9xCheatFinderViewController.xib; sourceTree = ""; }; + 30F72A8C29CCF8E2000235A8 /* S9xHexNumberFormatter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S9xHexNumberFormatter.h; sourceTree = ""; }; + 30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = S9xHexNumberFormatter.m; sourceTree = ""; }; 85FEF90620DDB15B00C038E9 /* bml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bml.cpp; sourceTree = ""; usesTabs = 1; }; 85FEF90720DDB15C00C038E9 /* bml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bml.h; sourceTree = ""; usesTabs = 1; }; 85FEF90A20DDB18D00C038E9 /* sha256.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sha256.cpp; sourceTree = ""; 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 = ""; }; EAECB67204AC7FCE00A80003 /* mac-cheat.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheat.mm"; sourceTree = ""; }; EAECB67304AC7FCE00A80003 /* mac-cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheat.h"; sourceTree = ""; }; - EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-cheatfinder.mm"; sourceTree = ""; }; - EAECB67504AC7FCE00A80003 /* mac-cheatfinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-cheatfinder.h"; sourceTree = ""; }; EAECB67904AC7FCE00A80003 /* mac-gworld.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-gworld.mm"; sourceTree = ""; }; EAECB67A04AC7FCE00A80003 /* mac-gworld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-gworld.h"; sourceTree = ""; }; EAECB67B04AC7FCE00A80003 /* mac-joypad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = "mac-joypad.mm"; sourceTree = ""; }; @@ -715,6 +720,11 @@ 30CF849927AF0C61002B37A9 /* S9xCheatEditViewController.h */, 30CF849A27AF0C61002B37A9 /* S9xCheatEditViewController.m */, 30CF849B27AF0C61002B37A9 /* S9xCheatEditViewController.xib */, + 30F727EB29C7B365000235A8 /* S9xCheatFinderViewController.h */, + 30F727EC29C7B365000235A8 /* S9xCheatFinderViewController.m */, + 30F727ED29C7B365000235A8 /* S9xCheatFinderViewController.xib */, + 30F72A8C29CCF8E2000235A8 /* S9xHexNumberFormatter.h */, + 30F72A8D29CCF8E2000235A8 /* S9xHexNumberFormatter.m */, ); path = Cheats; sourceTree = ""; @@ -998,7 +1008,6 @@ EADE6349052E5C5300A80003 /* mac-audio.h */, EAECB67104AC7FCE00A80003 /* mac-cart.h */, EAECB67304AC7FCE00A80003 /* mac-cheat.h */, - EAECB67504AC7FCE00A80003 /* mac-cheatfinder.h */, EA85C24D0B4EC13300F5F9C9 /* mac-cocoatools.h */, EA809F9D08F8F2190072CDFB /* mac-controls.h */, EA2DBC0A0510ABE700A80003 /* mac-file.h */, @@ -1021,7 +1030,6 @@ EADE6347052E5C4300A80003 /* mac-audio.mm */, EAECB67004AC7FCE00A80003 /* mac-cart.mm */, EAECB67204AC7FCE00A80003 /* mac-cheat.mm */, - EAECB67404AC7FCE00A80003 /* mac-cheatfinder.mm */, EA85C24E0B4EC13300F5F9C9 /* mac-cocoatools.mm */, EA809FA108F8F2420072CDFB /* mac-controls.mm */, EA2DBC0C0510ABE700A80003 /* mac-file.mm */, @@ -1256,6 +1264,7 @@ 306937CB2635EE5800007ABB /* S9xDisplayPreferencesViewController.xib in Resources */, 306937E92636365100007ABB /* S9xFilesPreferencesViewController.xib in Resources */, 30D709B0236F583600AAB7C3 /* Localizable.strings in Resources */, + 30F727EF29C7B365000235A8 /* S9xCheatFinderViewController.xib in Resources */, 304B364A262E328400F8DC8E /* S9xControlsPreferencesViewController.xib in Resources */, 30D709B1236F585100AAB7C3 /* Snes9x Help in Resources */, 30D709B3236F731B00AAB7C3 /* SRAM.icns in Resources */, @@ -1295,6 +1304,8 @@ 309C54802627F3060055DD95 /* S9xControlsPreferencesViewController.m in Sources */, 30D709C5236F90DF00AAB7C3 /* S9xButtonConfigTextField.m in Sources */, 306937E82636365100007ABB /* S9xFilesPreferencesViewController.m in Sources */, + 30F72A8E29CCF8E2000235A8 /* S9xHexNumberFormatter.m in Sources */, + 30F727EE29C7B365000235A8 /* S9xCheatFinderViewController.m in Sources */, 30CF849C27AF0C61002B37A9 /* S9xCheatEditViewController.m in Sources */, 306937D02636253900007ABB /* S9xPreferencesTabViewController.m in Sources */, 30714721230E379600917F82 /* main.m in Sources */, @@ -1315,7 +1326,6 @@ 307C862122D29E29001B879E /* mac-audio.mm in Sources */, 307C862222D29E29001B879E /* mac-cart.mm in Sources */, 307C862322D29E29001B879E /* mac-cheat.mm in Sources */, - 307C862422D29E29001B879E /* mac-cheatfinder.mm in Sources */, 307C862622D29E29001B879E /* mac-cocoatools.mm in Sources */, 307C862922D29E29001B879E /* mac-gworld.mm in Sources */, 307C862A22D29E29001B879E /* mac-keyboard.mm in Sources */,