git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

commit 6178ff2a783f592e02effcecb27c8bbb9b60acfd
parent fc508427b8fedba133832b669f473eadc1635b3b
Author: Lior Halphon <LIJI32@gmail.com>
Date:   Thu, 29 Aug 2024 01:11:47 +0300

Cheat Search API, Cheat Search in Cocoa, and new cheats window layout

Diffstat:
ACocoa/CheatSearch.xib254+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MCocoa/Document.h11++++++-----
MCocoa/Document.m16++++++++++++++++
MCocoa/Document.xib322++++++++++++++++++++++++++++++++++++++++---------------------------------------
ACocoa/GBCenteredTextCell.h5+++++
ACocoa/GBCenteredTextCell.m29+++++++++++++++++++++++++++++
ACocoa/GBCheatSearchController.h8++++++++
ACocoa/GBCheatSearchController.m231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MCocoa/MainMenu.xib10++++++++--
ACore/cheat_search.c142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ACore/cheat_search.h25+++++++++++++++++++++++++
MCore/debugger.c122+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
MCore/debugger.h3+++
MCore/gb.c10+++++++++-
MCore/gb.h15+++++++++++++++
15 files changed, 995 insertions(+), 208 deletions(-)

diff --git a/Cocoa/CheatSearch.xib b/Cocoa/CheatSearch.xib @@ -0,0 +1,254 @@ +<?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="GBCheatSearchController"> + <connections> + <outlet property="addCheatButton" destination="o1I-5D-V4k" id="lRE-uQ-vul"/> + <outlet property="conditionField" destination="XN7-BO-THS" id="vzh-y2-CcN"/> + <outlet property="conditionTypeButton" destination="6RO-h8-lZ8" id="5wx-NY-lbK"/> + <outlet property="dataTypeButton" destination="5Db-vP-S60" id="wdR-m7-fEI"/> + <outlet property="operandField" destination="Q42-Vu-TJW" id="hRn-67-UmU"/> + <outlet property="resultsLabel" destination="wbN-MX-lEy" id="gJB-fD-eKK"/> + <outlet property="tableView" destination="fSU-85-fVM" id="1kO-kP-yBb"/> + <outlet property="window" destination="QvC-M9-y7g" id="g09-DO-GsE"/> + </connections> + </customObject> + <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> + <customObject id="-3" userLabel="Application" customClass="NSObject"/> + <window title="Cheat Search" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="NSPanel"> + <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> + <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> + <rect key="contentRect" x="196" y="240" width="480" height="372"/> + <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/> + <value key="minSize" type="size" width="480" height="372"/> + <value key="maxSize" type="size" width="480" height="99999"/> + <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ"> + <rect key="frame" x="0.0" y="0.0" width="480" height="372"/> + <autoresizingMask key="autoresizingMask"/> + <subviews> + <scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fvf-Co-5Ga"> + <rect key="frame" x="-1" y="155" width="482" height="218"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <clipView key="contentView" drawsBackground="NO" id="1kJ-HR-keu"> + <rect key="frame" x="1" y="1" width="480" height="216"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" tableStyle="plain" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="24" headerView="oyv-sh-ulk" id="fSU-85-fVM"> + <rect key="frame" x="0.0" y="0.0" width="480" height="188"/> + <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" editable="NO" width="143" minWidth="40" maxWidth="1000" id="8z0-o5-dNI"> + <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" controlSize="large" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" title="Text Cell" id="bmG-fw-HDR" customClass="GBCenteredTextCell"> + <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"/> + </tableColumn> + <tableColumn identifier="AutomaticTableColumnIdentifier.1" editable="NO" width="143" minWidth="40" maxWidth="1000" id="mBc-yv-f00"> + <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Previous Value"> + <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> + </tableHeaderCell> + <textFieldCell key="dataCell" controlSize="large" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" title="Text Cell" id="BSe-S3-KNH" customClass="GBCenteredTextCell"> + <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"/> + </tableColumn> + <tableColumn width="143" minWidth="10" maxWidth="3.4028234663852886e+38" id="F7j-ck-3H0"> + <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Current Value"> + <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </tableHeaderCell> + <textFieldCell key="dataCell" controlSize="large" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="wjH-Ei-6hv" customClass="GBCenteredTextCell"> + <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"/> + </tableColumn> + </tableColumns> + <connections> + <outlet property="dataSource" destination="-2" id="Yqt-V5-OkG"/> + <outlet property="delegate" destination="-2" id="TRM-gh-TG4"/> + </connections> + </tableView> + </subviews> + <nil key="backgroundColor"/> + </clipView> + <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="ZbQ-IG-kyP"> + <rect key="frame" x="1" y="201" width="480" height="16"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="wK3-8v-kAQ"> + <rect key="frame" x="224" y="17" width="15" height="102"/> + <autoresizingMask key="autoresizingMask"/> + </scroller> + <tableHeaderView key="headerView" wantsLayer="YES" id="oyv-sh-ulk"> + <rect key="frame" x="0.0" y="0.0" width="480" height="28"/> + <autoresizingMask key="autoresizingMask"/> + </tableHeaderView> + </scrollView> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KdM-lW-WbP"> + <rect key="frame" x="371" y="25" width="96" height="32"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="push" title="Search" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="t4Y-Ud-mJm"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="search:" target="-2" id="7pG-JY-vEF"/> + </connections> + </button> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="veO-Qn-0Sz"> + <rect key="frame" x="60" y="126" width="70" height="16"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Data Type:" id="KuT-rz-eHm"> + <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> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fTv-nr-5FT"> + <rect key="frame" x="18" y="96" width="112" height="16"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Search Condition:" id="9C2-Xp-JIA"> + <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> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vMd-zb-8jT"> + <rect key="frame" x="56" y="67" width="74" height="16"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Expression:" id="Jgg-sA-jjs"> + <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" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5Db-vP-S60"> + <rect key="frame" x="133" y="119" width="197" height="25"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <popUpButtonCell key="cell" type="push" title="8-Bit" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="al4-Jb-OJB" id="dkg-V5-wsX"> + <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="menu"/> + <menu key="menu" id="e5r-qR-pg7"> + <items> + <menuItem title="8-Bit" state="on" id="al4-Jb-OJB"/> + <menuItem title="16-Bit" tag="1" id="G2m-fU-8Lt"/> + <menuItem title="16-Bit (Big Endian)" tag="3" id="JRa-DB-dyG"/> + </items> + </menu> + </popUpButtonCell> + </popUpButton> + <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6RO-h8-lZ8"> + <rect key="frame" x="133" y="89" width="197" height="25"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <popUpButtonCell key="cell" type="push" title="Is Equal To..." bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Vfb-Dg-Jkb" id="DPm-QO-c64"> + <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="menu"/> + <menu key="menu" id="Kg9-Rd-1GQ"> + <items> + <menuItem title="Any" id="cEg-eI-4hb"/> + <menuItem title="Is Equal To..." state="on" id="Vfb-Dg-Jkb"/> + <menuItem title="Is Different From..." id="JDg-d9-5Ux"/> + <menuItem title="Is Greater Than..." id="Rir-w0-737"/> + <menuItem title="Is Equal or Greater Than..." id="Lvo-pV-Syt"/> + <menuItem title="Is Less Than..." id="VUW-DY-2cI"/> + <menuItem title="Is Equal or Less Than..." id="rDN-UF-tIo"/> + <menuItem title="Did Change" id="JdI-CW-E8H"/> + <menuItem title="Did Not Change" id="sWc-Yz-Cve"/> + <menuItem title="Did Increase" id="LHF-Lf-7tK"/> + <menuItem title="Did Decrease" id="8s2-8n-aQO"/> + <menuItem title="Custom..." id="8xc-2v-YQj"/> + </items> + </menu> + </popUpButtonCell> + <connections> + <action selector="conditionChanged:" target="-2" id="KF9-vz-yNC"/> + </connections> + </popUpButton> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q42-Vu-TJW"> + <rect key="frame" x="334" y="93" width="126" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" continuous="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="$0" drawsBackground="YES" usesSingleLineMode="YES" id="WDs-GG-7Lc"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + <allowedInputSourceLocales> + <string>NSAllRomanInputSourcesLocaleIdentifier</string> + </allowedInputSourceLocales> + </textFieldCell> + <connections> + <action selector="search:" target="-2" id="BDa-5j-qEz"/> + <outlet property="delegate" destination="-2" id="1bO-hp-igc"/> + </connections> + </textField> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XN7-BO-THS"> + <rect key="frame" x="136" y="64" width="324" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" borderStyle="bezel" title="new == ($0)" drawsBackground="YES" usesSingleLineMode="YES" id="Krh-8w-4ug"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + <allowedInputSourceLocales> + <string>NSAllRomanInputSourcesLocaleIdentifier</string> + </allowedInputSourceLocales> + </textFieldCell> + <connections> + <action selector="search:" target="-2" id="sv5-eX-Kb9"/> + </connections> + </textField> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tBa-6c-9AY"> + <rect key="frame" x="13" y="25" width="96" height="32"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Pge-SU-Y1n"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="reset:" target="-2" id="KCy-Ob-tlg"/> + </connections> + </button> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wbN-MX-lEy"> + <rect key="frame" x="-3" y="4" width="486" height="14"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> + <textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Status" id="CM3-4U-qao"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="o1I-5D-V4k"> + <rect key="frame" x="264" y="25" width="110" height="32"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="push" title="Add Cheat" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="GGV-nm-ASn"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="addCheat:" target="-2" id="7ax-kM-TeV"/> + </connections> + </button> + </subviews> + </view> + <contentBorderThickness minY="22"/> + <point key="canvasLocation" x="161" y="182"/> + </window> + </objects> +</document> diff --git a/Cocoa/Document.h b/Cocoa/Document.h @@ -83,10 +83,11 @@ enum model { + (NSImage *) imageFromData:(NSData *)data width:(NSUInteger) width height:(NSUInteger) height scale:(double) scale; --(uint8_t) readMemory:(uint16_t) addr; --(void) writeMemory:(uint16_t) addr value:(uint8_t)value; --(void) performAtomicBlock: (void (^)())block; --(void) connectLinkCable:(NSMenuItem *)sender; --(int)loadStateFile:(const char *)path noErrorOnNotFound:(bool)noErrorOnFileNotFound; +- (uint8_t) readMemory:(uint16_t) addr; +- (void) writeMemory:(uint16_t) addr value:(uint8_t)value; +- (void) performAtomicBlock: (void (^)())block; +- (void) connectLinkCable:(NSMenuItem *)sender; +- (int)loadStateFile:(const char *)path noErrorOnNotFound:(bool)noErrorOnFileNotFound; +- (NSString *)captureOutputForBlock: (void (^)())block; @end diff --git a/Cocoa/Document.m b/Cocoa/Document.m @@ -11,6 +11,7 @@ #import "GBTerminalTextFieldCell.h" #import "BigSurToolbar.h" #import "GBPaletteEditorController.h" +#import "GBCheatSearchController.h" #import "GBObjectView.h" #import "GBPaletteView.h" #import "GBHexStatusBarRepresenter.h" @@ -117,6 +118,8 @@ NSDate *_fileModificationTime; __weak NSThread *_emulationThread; + + GBCheatSearchController *_cheatSearchController; } static void boot_rom_load(GB_gameboy_t *gb, GB_boot_rom_t type) @@ -1775,6 +1778,11 @@ enum GBWindowResizeAction if (self.memoryWindow.isVisible) { [_hexController reloadData]; } + if (_cheatSearchController.window.isVisible) { + if ([_cheatSearchController.tableView editedColumn] != 2) { + [_cheatSearchController.tableView reloadData]; + } + } } - (IBAction) reloadVRAMData: (id) sender @@ -2400,6 +2408,14 @@ enum GBWindowResizeAction [self.cheatsWindow makeKeyAndOrderFront:nil]; } +- (IBAction)showCheatSearch:(id)sender +{ + if (!_cheatSearchController) { + _cheatSearchController = [GBCheatSearchController controllerWithDocument:self]; + } + [_cheatSearchController.window makeKeyAndOrderFront:sender]; +} + - (IBAction)toggleCheats:(id)sender { GB_set_cheats_enabled(&_gb, !GB_cheats_enabled(&_gb)); diff --git a/Cocoa/Document.xib b/Cocoa/Document.xib @@ -720,165 +720,24 @@ <point key="canvasLocation" x="-159" y="356"/> </window> <window title="Cheats" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="4Yb-Np-JrF" customClass="NSPanel"> - <windowStyleMask key="styleMask" titled="YES" closable="YES"/> - <rect key="contentRect" x="0.0" y="0.0" width="692" height="272"/> + <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> + <rect key="contentRect" x="0.0" y="0.0" width="604" height="400"/> <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/> + <value key="minSize" type="size" width="604" height="400"/> + <value key="maxSize" type="size" width="604" height="99999"/> <view key="contentView" id="gBP-5p-BTh"> - <rect key="frame" x="0.0" y="0.0" width="692" height="272"/> + <rect key="frame" x="0.0" y="0.0" width="604" height="400"/> <autoresizingMask key="autoresizingMask"/> <subviews> - <view id="fWr-0i-K1d" customClass="GBOptionalVisualEffectView"> - <rect key="frame" x="0.0" y="0.0" width="294" height="272"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" heightSizable="YES"/> - <subviews> - <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="hqi-ob-NW9"> - <rect key="frame" x="16" y="174" width="154" height="19"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" lineBreakMode="clipping" title="To value:" id="Ycx-oE-aA4"> - <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> - <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kq8-6F-9GK"> - <rect key="frame" x="16" y="142" width="154" height="19"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="check" title="Only if old value was: " bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="LkB-WQ-9Qd"> - <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="updateCheat:" target="v7q-gT-jHT" id="kNc-cj-bmF"/> - </connections> - </button> - <box verticalHuggingPriority="750" boxType="separator" id="D6k-Pe-23u"> - <rect key="frame" x="10" y="129" width="274" height="5"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - </box> - <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="r5T-ol-Dod"> - <rect key="frame" x="16" y="107" width="270" height="16"/> - <autoresizingMask key="autoresizingMask" flexibleMinY="YES"/> - <textFieldCell key="cell" lineBreakMode="clipping" title="Import GameShark or GameGenie cheat:" id="0mf-EN-cKc"> - <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> - <textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="X7K-nJ-alF"> - <rect key="frame" x="39" y="78" width="233" height="21"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" focusRingType="none" placeholderString="Code" drawsBackground="YES" usesSingleLineMode="YES" id="2bz-dT-7Fi"> - <font key="font" metaFont="system"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> - <allowedInputSourceLocales> - <string>NSAllRomanInputSourcesLocaleIdentifier</string> - </allowedInputSourceLocales> - </textFieldCell> - <connections> - <action selector="selectText:" target="KHj-uX-Wbk" id="11z-0U-tMA"/> - </connections> - </textField> - <textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KHj-uX-Wbk"> - <rect key="frame" x="39" y="47" width="233" height="21"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" focusRingType="none" placeholderString="Description" drawsBackground="YES" usesSingleLineMode="YES" id="50d-va-Cen"> - <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> - <action selector="performClick:" target="C3V-Ep-bMj" id="kIN-jl-A8d"/> - </connections> - </textField> - <textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C6E-oI-hDC"> - <rect key="frame" x="20" y="233" width="252" height="21"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" focusRingType="none" placeholderString="Description" drawsBackground="YES" usesSingleLineMode="YES" id="2uR-9N-hBb"> - <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="v7q-gT-jHT" id="zyw-h0-hRP"/> - </connections> - </textField> - <button verticalHuggingPriority="750" id="C3V-Ep-bMj"> - <rect key="frame" x="203" y="12" width="83" height="23"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="roundTextured" title="Import" bezelStyle="texturedRounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mMP-KW-YNy"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="importCheat:" target="v7q-gT-jHT" id="lkX-N5-wD1"/> - </connections> - </button> - <textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="qHx-1z-daR"> - <rect key="frame" x="176" y="204" width="96" height="21"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="none" drawsBackground="YES" usesSingleLineMode="YES" id="edq-46-JeP" customClass="GBCheatTextFieldCell"> - <font key="font" metaFont="system"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> - <allowedInputSourceLocales> - <string>NSAllRomanInputSourcesLocaleIdentifier</string> - </allowedInputSourceLocales> - </textFieldCell> - <connections> - <outlet property="delegate" destination="v7q-gT-jHT" id="79v-33-R1X"/> - </connections> - </textField> - <textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="N3I-PP-X85"> - <rect key="frame" x="176" y="174" width="96" height="21"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="none" drawsBackground="YES" usesSingleLineMode="YES" id="CV2-D9-WsB" customClass="GBCheatTextFieldCell"> - <font key="font" metaFont="system"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> - <allowedInputSourceLocales> - <string>NSAllRomanInputSourcesLocaleIdentifier</string> - </allowedInputSourceLocales> - </textFieldCell> - <connections> - <outlet property="delegate" destination="v7q-gT-jHT" id="P69-nT-oOt"/> - </connections> - </textField> - <textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="S6O-LB-gSj"> - <rect key="frame" x="176" y="144" width="96" height="21"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="none" drawsBackground="YES" usesSingleLineMode="YES" id="tpM-ys-MEO" customClass="GBCheatTextFieldCell"> - <font key="font" metaFont="system"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> - <allowedInputSourceLocales> - <string>NSAllRomanInputSourcesLocaleIdentifier</string> - </allowedInputSourceLocales> - </textFieldCell> - <connections> - <outlet property="delegate" destination="v7q-gT-jHT" id="6RH-dg-SL7"/> - </connections> - </textField> - <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="uFo-ly-Veq"> - <rect key="frame" x="16" y="204" width="152" height="19"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" lineBreakMode="clipping" title="Change byte at address:" id="xwa-TF-eY1"> - <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> - </subviews> - </view> - <scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="6rU-Xg-KHc"> - <rect key="frame" x="293" y="-1" width="400" height="275"/> - <autoresizingMask key="autoresizingMask" flexibleMinX="YES" heightSizable="YES"/> + <scrollView autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="6rU-Xg-KHc"> + <rect key="frame" x="-1" y="143" width="606" height="259"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <clipView key="contentView" id="mzf-yu-RID"> - <rect key="frame" x="1" y="1" width="398" height="273"/> - <autoresizingMask key="autoresizingMask"/> + <rect key="frame" x="1" y="1" width="604" height="257"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" headerView="pvX-uJ-qK5" id="tA3-8T-bxb"> - <rect key="frame" x="0.0" y="0.0" width="398" height="256"/> + <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="24" rowSizeStyle="large" headerView="pvX-uJ-qK5" id="tA3-8T-bxb"> + <rect key="frame" x="0.0" y="0.0" width="604" height="240"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <size key="intercellSpacing" width="3" height="2"/> <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> @@ -895,7 +754,7 @@ </buttonCell> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> </tableColumn> - <tableColumn width="40" minWidth="40" maxWidth="1000" id="9DZ-oW-Scx"> + <tableColumn width="52" minWidth="52" maxWidth="1000" id="9DZ-oW-Scx"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Enabled"> <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> @@ -906,24 +765,24 @@ </buttonCell> <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> </tableColumn> - <tableColumn editable="NO" width="142" minWidth="40" maxWidth="1000" id="4Qa-FQ-QWY"> + <tableColumn editable="NO" width="320" minWidth="320" maxWidth="1000" id="4Qa-FQ-QWY"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Description"> <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="Description" id="1hX-Sr-bGz"> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Description" id="1hX-Sr-bGz" customClass="GBCenteredTextCell"> <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"/> </tableColumn> - <tableColumn editable="NO" width="134" minWidth="40" maxWidth="1000" id="ACq-gU-K36"> + <tableColumn editable="NO" width="172" minWidth="172" maxWidth="1000" id="ACq-gU-K36"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Action"> <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="Action" id="8Sq-h9-eV7"> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Action" id="8Sq-h9-eV7" customClass="GBCenteredTextCell"> <font key="font" metaFont="fixedUser" size="11"/> <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> @@ -947,13 +806,156 @@ <autoresizingMask key="autoresizingMask"/> </scroller> <tableHeaderView key="headerView" wantsLayer="YES" id="pvX-uJ-qK5"> - <rect key="frame" x="0.0" y="0.0" width="398" height="17"/> + <rect key="frame" x="0.0" y="0.0" width="604" height="17"/> <autoresizingMask key="autoresizingMask"/> </tableHeaderView> </scrollView> + <customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TFe-hA-XJc"> + <rect key="frame" x="-1" y="0.0" width="308" height="135"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="hqi-ob-NW9"> + <rect key="frame" x="20" y="51" width="176" height="19"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="To value:" id="Ycx-oE-aA4"> + <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> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kq8-6F-9GK"> + <rect key="frame" x="42" y="21" width="152" height="19"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES"/> + <buttonCell key="cell" type="check" title="Only if old value was: " bezelStyle="regularSquare" imagePosition="left" alignment="right" state="on" inset="2" id="LkB-WQ-9Qd"> + <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="updateCheat:" target="v7q-gT-jHT" id="kNc-cj-bmF"/> + </connections> + </button> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C6E-oI-hDC"> + <rect key="frame" x="22" y="112" width="276" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Description" drawsBackground="YES" usesSingleLineMode="YES" id="2uR-9N-hBb"> + <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="v7q-gT-jHT" id="zyw-h0-hRP"/> + </connections> + </textField> + <textField verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="qHx-1z-daR"> + <rect key="frame" x="202" y="82" width="96" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="edq-46-JeP" customClass="GBCheatTextFieldCell"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + <allowedInputSourceLocales> + <string>NSAllRomanInputSourcesLocaleIdentifier</string> + </allowedInputSourceLocales> + </textFieldCell> + <connections> + <outlet property="delegate" destination="v7q-gT-jHT" id="79v-33-R1X"/> + </connections> + </textField> + <textField verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="N3I-PP-X85"> + <rect key="frame" x="202" y="51" width="96" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="CV2-D9-WsB" customClass="GBCheatTextFieldCell"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + <allowedInputSourceLocales> + <string>NSAllRomanInputSourcesLocaleIdentifier</string> + </allowedInputSourceLocales> + </textFieldCell> + <connections> + <outlet property="delegate" destination="v7q-gT-jHT" id="P69-nT-oOt"/> + </connections> + </textField> + <textField verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="S6O-LB-gSj"> + <rect key="frame" x="202" y="20" width="96" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="tpM-ys-MEO" customClass="GBCheatTextFieldCell"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + <allowedInputSourceLocales> + <string>NSAllRomanInputSourcesLocaleIdentifier</string> + </allowedInputSourceLocales> + </textFieldCell> + <connections> + <outlet property="delegate" destination="v7q-gT-jHT" id="6RH-dg-SL7"/> + </connections> + </textField> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="uFo-ly-Veq"> + <rect key="frame" x="18" y="82" width="178" height="19"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Change byte at address:" id="xwa-TF-eY1"> + <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> + </subviews> + </customView> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="r5T-ol-Dod"> + <rect key="frame" x="316" y="115" width="270" height="16"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Import GameShark or GameGenie cheat:" id="0mf-EN-cKc"> + <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> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="X7K-nJ-alF"> + <rect key="frame" x="351" y="82" width="233" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" placeholderString="Code" drawsBackground="YES" usesSingleLineMode="YES" id="2bz-dT-7Fi"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + <allowedInputSourceLocales> + <string>NSAllRomanInputSourcesLocaleIdentifier</string> + </allowedInputSourceLocales> + </textFieldCell> + <connections> + <action selector="selectText:" target="KHj-uX-Wbk" id="11z-0U-tMA"/> + </connections> + </textField> + <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KHj-uX-Wbk"> + <rect key="frame" x="351" y="51" width="233" height="21"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" placeholderString="Description" drawsBackground="YES" usesSingleLineMode="YES" id="50d-va-Cen"> + <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> + <action selector="performClick:" target="C3V-Ep-bMj" id="kIN-jl-A8d"/> + </connections> + </textField> + <button verticalHuggingPriority="750" id="C3V-Ep-bMj"> + <rect key="frame" x="508" y="12" width="83" height="32"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES"/> + <buttonCell key="cell" type="push" title="Import" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mMP-KW-YNy"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="importCheat:" target="v7q-gT-jHT" id="lkX-N5-wD1"/> + </connections> + </button> + <box horizontalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="P90-u5-8ko"> + <rect key="frame" x="304" y="12" width="5" height="123"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> + </box> </subviews> </view> - <point key="canvasLocation" x="254" y="-463"/> + <point key="canvasLocation" x="210" y="-399"/> </window> <customObject id="v7q-gT-jHT" customClass="GBCheatWindowController"> <connections> diff --git a/Cocoa/GBCenteredTextCell.h b/Cocoa/GBCenteredTextCell.h @@ -0,0 +1,5 @@ +#import <Cocoa/Cocoa.h> + +@interface GBCenteredTextCell : NSTextFieldCell + +@end diff --git a/Cocoa/GBCenteredTextCell.m b/Cocoa/GBCenteredTextCell.m @@ -0,0 +1,29 @@ +#import "GBCenteredTextCell.h" + +@implementation GBCenteredTextCell +- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView +{ + double height = round([self.attributedStringValue size].height); + cellFrame.origin.y += (cellFrame.size.height - height) / 2; + cellFrame.size.height = height; + [super drawInteriorWithFrame:cellFrame inView:controlView]; +} + + +- (void)selectWithFrame:(NSRect)rect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)delegate start:(NSInteger)selStart length:(NSInteger)selLength +{ + double height = round([self.attributedStringValue size].height); + rect.origin.y += (rect.size.height - height) / 2; + rect.size.height = height; + [super selectWithFrame:rect inView:controlView editor:textObj delegate:delegate start:selStart length:selLength]; +} + +- (void)editWithFrame:(NSRect)rect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)delegate event:(NSEvent *)event +{ + double height = round([self.attributedStringValue size].height); + rect.origin.y += (rect.size.height - height) / 2; + rect.size.height = height; + [super editWithFrame:rect inView:controlView editor:textObj delegate:delegate event:event]; + +} +@end diff --git a/Cocoa/GBCheatSearchController.h b/Cocoa/GBCheatSearchController.h @@ -0,0 +1,8 @@ +#import <AppKit/AppKit.h> +#import "Document.h" + +@interface GBCheatSearchController<NSTableViewDelegate, NSTableViewDataSource, NSControlTextEditingDelegate> : NSObject +@property IBOutlet NSWindow *window; +@property IBOutlet NSTableView *tableView; ++ (instancetype)controllerWithDocument:(Document *)document; +@end diff --git a/Cocoa/GBCheatSearchController.m b/Cocoa/GBCheatSearchController.m @@ -0,0 +1,231 @@ +#import "GBCheatSearchController.h" +#import "GBWarningPopover.h" +#import "GBCheatWindowController.h" + +@interface GBCheatSearchController() <NSTableViewDelegate, NSTableViewDataSource> +@property IBOutlet NSPopUpButton *dataTypeButton; +@property IBOutlet NSPopUpButton *conditionTypeButton; +@property IBOutlet NSTextField *operandField; +@property IBOutlet NSTextField *conditionField; +@property IBOutlet NSTextField *resultsLabel; +@property (strong) IBOutlet NSButton *addCheatButton; +@end + +@implementation GBCheatSearchController +{ + __weak Document *_document; + size_t _resultCount; + GB_cheat_search_result_t *_results; +} + ++ (instancetype)controllerWithDocument:(Document *)document +{ + GBCheatSearchController *ret = [[self alloc] init]; + ret->_document = document; + NSArray *objects; + [[NSBundle mainBundle] loadNibNamed:@"CheatSearch" owner:ret topLevelObjects:&objects]; + ret->_resultsLabel.stringValue = @""; + ret->_resultsLabel.cell.backgroundStyle = NSBackgroundStyleRaised; + return ret; +} + +- (IBAction)reset:(id)sender +{ + _dataTypeButton.enabled = true; + [_document performAtomicBlock:^{ + GB_cheat_search_reset(_document.gb); + }]; + _resultCount = 0; + if (_results) { + free(_results); + _results = NULL; + } + [_tableView reloadData]; + _resultsLabel.stringValue = @""; +} + +- (IBAction)search:(id)sender +{ + // Dispatch to work around firstResponder oddities + dispatch_async(dispatch_get_main_queue(), ^{ + if ([sender isKindOfClass:[NSTextField class]]) { + // Action sent by losing focus rather than pressing enter + if (![sender currentEditor]) return; + } + _dataTypeButton.enabled = false; + [_document performAtomicBlock:^{ + __block bool success = false; + NSString *error = [_document captureOutputForBlock:^{ + success = GB_cheat_search_filter(_document.gb, _conditionField.stringValue.UTF8String, _dataTypeButton.selectedTag); + }]; + if (!success) { + dispatch_async(dispatch_get_main_queue(), ^{ + [GBWarningPopover popoverWithContents:error onView:_conditionField]; + NSBeep(); + }); + return; + } + _resultCount = GB_cheat_search_result_count(_document.gb); + _results = malloc(sizeof(*_results) * _resultCount); + GB_cheat_search_get_results(_document.gb, _results); + }]; + if (_resultCount == 0) { + _dataTypeButton.enabled = true; + _resultsLabel.stringValue = @"No results."; + } + else { + _resultsLabel.stringValue = [NSString stringWithFormat:@"%@ result%s", + [NSNumberFormatter localizedStringFromNumber:@(_resultCount) + numberStyle:NSNumberFormatterDecimalStyle], + _resultCount > 1? "s" : ""]; + } + [_tableView reloadData]; + }); +} + +- (IBAction)conditionChanged:(id)sender +{ + unsigned index = [_conditionTypeButton indexOfSelectedItem]; + _conditionField.enabled = index == 11; + _operandField.enabled = index >= 1 && index <= 6; + switch ([_conditionTypeButton indexOfSelectedItem]) { + case 0: _conditionField.stringValue = @"1"; break; + case 1: _conditionField.stringValue = [NSString stringWithFormat:@"new == (%@)", _operandField.stringValue]; break; + case 2: _conditionField.stringValue = [NSString stringWithFormat:@"new != (%@)", _operandField.stringValue]; break; + case 3: _conditionField.stringValue = [NSString stringWithFormat:@"new > (%@)", _operandField.stringValue]; break; + case 4: _conditionField.stringValue = [NSString stringWithFormat:@"new >= (%@)", _operandField.stringValue]; break; + case 5: _conditionField.stringValue = [NSString stringWithFormat:@"new < (%@)", _operandField.stringValue]; break; + case 6: _conditionField.stringValue = [NSString stringWithFormat:@"new <= (%@)", _operandField.stringValue]; break; + case 7: _conditionField.stringValue = @"new != old"; break; + case 8: _conditionField.stringValue = @"new == old"; break; + case 9: _conditionField.stringValue = @"new > old"; break; + case 10: _conditionField.stringValue = @"new < old"; break; + } +} + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return _resultCount; +} + +- (uint8_t *)addressForRow:(unsigned)row +{ + uint8_t *base; + uint32_t offset; + if (_results[row].addr < 0xc000) { + base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_CART_RAM, NULL, NULL); + offset = (_results[row].addr & 0x1FFF) + _results[row].bank * 0x2000; + } + else if (_results[row].addr < 0xe000) { + base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_RAM, NULL, NULL); + offset = (_results[row].addr & 0xFFF) + _results[row].bank * 0x1000; + } + else { + base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_HRAM, NULL, NULL); + offset = (_results[row].addr & 0x7F); + } + return base + offset; +} + +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + switch ([[tableView tableColumns] indexOfObject:tableColumn]) { + case 0: + return [NSString stringWithFormat:@"$%02x:$%04x", _results[row].bank, _results[row].addr]; + case 1: + if (_dataTypeButton.selectedTag & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) { + return [NSString stringWithFormat:@"$%04x", _results[row].value]; + } + return [NSString stringWithFormat:@"$%02x", _results[row].value]; + default: { + const uint8_t *data = [self addressForRow:row]; + GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag; + uint16_t value = data[0]; + if (!(dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)) { + return [NSString stringWithFormat:@"$%02x", value]; + } + value |= data[1] << 8; + if ((dataType & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT)) { + value = __builtin_bswap16(value); + } + return [NSString stringWithFormat:@"$%04x", value]; + } + } +} + +- (void)tableView:(NSTableView *)tableView setObjectValue:(NSString *)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + [_document performAtomicBlock:^{ + __block bool success = false; + __block uint16_t value; + NSString *error = [_document captureOutputForBlock:^{ + success = !GB_debugger_evaluate(_document.gb, object.UTF8String, &value, NULL); + }]; + if (!success) { + dispatch_async(dispatch_get_main_queue(), ^{ + [GBWarningPopover popoverWithContents:error onView:tableView]; + NSBeep(); + }); + return; + } + uint8_t *dest = [self addressForRow:row]; + GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag; + if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT) { + value = __builtin_bswap16(value); + } + dest[0] = value; + if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) { + dest[1] = value >> 8; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [tableView reloadData]; + }); + }]; +} + +- (void)controlTextDidChange:(NSNotification *)obj +{ + [self conditionChanged:nil]; +} + +- (IBAction)addCheat:(id)sender +{ + GB_cheat_search_result_t *result = _results + _tableView.selectedRow; + uint8_t *data = [self addressForRow:_tableView.selectedRow]; + GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag; + size_t rowToSelect = 0; + GB_get_cheats(_document.gb, &rowToSelect); + [_document performAtomicBlock:^{ + GB_add_cheat(_document.gb, + (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)? "New Cheat (Part 1)" : "New Cheat", + result->addr, result->bank, + *data, + 0, false, + true); + if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) { + GB_add_cheat(_document.gb, + (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)? "New Cheat (Part 2)" : "New Cheat", + result->addr + 1, result->bank, + data[1], + 0, false, + true); + } + GB_set_cheats_enabled(_document.gb, true); + }]; + [_document.cheatsWindow makeKeyAndOrderFront:nil]; + [_document.cheatWindowController.cheatsTable reloadData]; + [_document.cheatWindowController.cheatsTable selectRow:rowToSelect byExtendingSelection:false]; + [_document.cheatWindowController.cheatsTable.delegate tableViewSelectionDidChange:nil]; +} + +- (void)tableViewSelectionDidChange:(NSNotification *)notification +{ + _addCheatButton.enabled = _tableView.numberOfSelectedRows != 0; +} + +- (void)dealloc +{ + if (_results) free(_results); +} + +@end diff --git a/Cocoa/MainMenu.xib b/Cocoa/MainMenu.xib @@ -427,10 +427,16 @@ <action selector="toggleCheats:" target="-1" id="gsw-UY-fhu"/> </connections> </menuItem> - <menuItem title="Show Cheats" id="LZV-QK-YXi"> + <menuItem title="Show Cheats" id="Nf8-F1-YyD"> <modifierMask key="keyEquivalentModifierMask"/> <connections> - <action selector="showCheats:" target="-1" id="tfr-qM-q8X"/> + <action selector="showCheats:" target="-1" id="stn-Ei-aFE"/> + </connections> + </menuItem> + <menuItem title="Search Cheats" id="LZV-QK-YXi"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="showCheatSearch:" target="-1" id="eI1-x0-ykn"/> </connections> </menuItem> </items> diff --git a/Core/cheat_search.c b/Core/cheat_search.c @@ -0,0 +1,142 @@ +#include "gb.h" + +void GB_cheat_search_reset(GB_gameboy_t *gb) +{ + if (gb->cheat_search_data) { + free(gb->cheat_search_data); + gb->cheat_search_data = NULL; + } + if (gb->cheat_search_bitmap) { + free(gb->cheat_search_bitmap); + gb->cheat_search_bitmap = NULL; + } + gb->cheat_search_count = 0; +} + +bool GB_cheat_search_filter(GB_gameboy_t *gb, const char *expression, GB_cheat_search_data_type_t data_type) +{ + GB_ASSERT_NOT_RUNNING(gb) + + // Make sure the expression is valid first + if (GB_debugger_evaluate_cheat_filter(gb, expression, NULL, 0, 0)) { + return false; + } + gb->cheat_search_data_type = data_type; + + if (gb->cheat_search_count == 0) { + GB_cheat_search_reset(gb); + gb->cheat_search_count = gb->ram_size + gb->mbc_ram_size + sizeof(gb->hram); + gb->cheat_search_data = malloc(gb->cheat_search_count); + gb->cheat_search_bitmap = malloc((gb->cheat_search_count + 7) / 8); + memset(gb->cheat_search_data, 0, gb->cheat_search_count); + memset(gb->cheat_search_bitmap, 0, (gb->cheat_search_count + 7) / 8); + } + + uint8_t mask = 1; + uint8_t *old_data = gb->cheat_search_data; + uint8_t *bitmap = gb->cheat_search_bitmap; + uint8_t *new_data = gb->ram; + + for (unsigned i = gb->ram_size + gb->mbc_ram_size + sizeof(gb->hram); i--;) { + if (*bitmap & mask) { + goto skip; + } + bool result = false; + if (data_type & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) { + // The last byte of each section always fails on 16-bit searches + if ((new_data != gb->ram + gb->ram_size - 1 && + new_data != gb->mbc_ram + gb->mbc_ram_size - 1 && + new_data != gb->hram + sizeof(gb->hram) - 1)) { + uint16_t old = old_data[0] | (old_data[1] << 8); + uint16_t new = new_data[0] | (new_data[1] << 8); + if (data_type & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT) { + old = __builtin_bswap16(old); + new = __builtin_bswap16(new); + } + GB_debugger_evaluate_cheat_filter(gb, expression, &result, old, new); + } + } + else { + GB_debugger_evaluate_cheat_filter(gb, expression, &result, *old_data, *new_data); + } + if (result) { + // Filter passed, update old value + *old_data = *new_data; + if (data_type & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) { + old_data[1] = new_data[1]; + } + } + else { + // Did not pass filter, remove address + *bitmap |= mask; + gb->cheat_search_count--; + } + skip:; + old_data++; + if (new_data == gb->ram + gb->ram_size - 1) { + new_data = gb->mbc_ram; + } + else if (new_data == gb->mbc_ram + gb->mbc_ram_size - 1) { + new_data = gb->hram; + } + else { + new_data++; + } + mask <<= 1; + if (mask == 0) { + mask = 1; + bitmap++; + } + } + + return true; +} + +size_t GB_cheat_search_result_count(GB_gameboy_t *gb) +{ + return gb->cheat_search_count; +} + +void GB_cheat_search_get_results(GB_gameboy_t *gb, GB_cheat_search_result_t *results) +{ + uint8_t mask = 1; + uint8_t *old_data = gb->cheat_search_data; + uint8_t *bitmap = gb->cheat_search_bitmap; + size_t count = gb->cheat_search_count; + while (count) { + if (!(*bitmap & mask)) { + count--; + if (gb->cheat_search_data_type & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) { + // Do not check for end of section, data_type is required to be the same as the last filter call + uint16_t old = old_data[0] | (old_data[1] << 8); + if (gb->cheat_search_data_type & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT) { + old = __builtin_bswap16(old); + } + results->value = old; + } + else { + results->value = *old_data; + } + size_t offset = old_data - gb->cheat_search_data; + if (offset < gb->ram_size) { + results->bank = offset / 0x1000; + results->addr = (offset & 0xfff) + (results->bank? 0xd000 : 0xc000); + } + else if (offset < gb->ram_size + gb->mbc_ram_size) { + results->addr = (offset & 0x1fff) + 0xa000; + results->bank = (offset - gb->ram_size) / 0x2000; + } + else { + results->addr = (offset & 0x7f) + 0xff80; + results->bank = 0; + } + results++; + } + old_data++; + mask <<= 1; + if (mask == 0) { + mask = 1; + bitmap++; + } + } +} diff --git a/Core/cheat_search.h b/Core/cheat_search.h @@ -0,0 +1,25 @@ +#pragma once +#ifndef GB_DISABLE_CHEAT_SEARCH +#include "defs.h" +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +typedef struct { + uint16_t addr; + uint16_t bank; + uint16_t value; +} GB_cheat_search_result_t; + +typedef enum { + GB_CHEAT_SEARCH_DATA_TYPE_8BIT = 0, + GB_CHEAT_SEARCH_DATA_TYPE_16BIT = 1, + GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT = 2, // Not used alone + GB_CHEAT_SEARCH_DATA_TYPE_16BIT_BE = GB_CHEAT_SEARCH_DATA_TYPE_16BIT | GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT, +} GB_cheat_search_data_type_t; + +void GB_cheat_search_reset(GB_gameboy_t *gb); +bool GB_cheat_search_filter(GB_gameboy_t *gb, const char *expression, GB_cheat_search_data_type_t data_type); +size_t GB_cheat_search_result_count(GB_gameboy_t *gb); +void GB_cheat_search_get_results(GB_gameboy_t *gb, GB_cheat_search_result_t *results); +#endif diff --git a/Core/debugger.c b/Core/debugger.c @@ -369,13 +369,22 @@ static struct { {":", 3, bank}, }; -value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, - size_t length, bool *error, - uint16_t *watchpoint_address, uint8_t *watchpoint_new_value); +typedef struct { + union { + uint16_t old_address; + uint16_t old_value; + }; + uint16_t new_value; + bool old_as_value; +} evaluate_conf_t; + +static value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, + size_t length, bool *error, + const evaluate_conf_t *conf); static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, size_t length, bool *error, - uint16_t *watchpoint_address, uint8_t *watchpoint_new_value) + const evaluate_conf_t *conf) { *error = false; // Strip whitespace @@ -403,7 +412,7 @@ static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, } if (string[i] == ')') depth--; } - if (depth == 0) return debugger_evaluate_lvalue(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + if (depth == 0) return debugger_evaluate_lvalue(gb, string + 1, length - 2, error, conf); } else if (string[0] == '[' && string[length - 1] == ']') { // Attempt to strip square parentheses (memory dereference) @@ -418,7 +427,7 @@ static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, if (string[i] == ']') depth--; } if (depth == 0) { - return (lvalue_t){LVALUE_MEMORY, .memory_address = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value)}; + return (lvalue_t){LVALUE_MEMORY, .memory_address = debugger_evaluate(gb, string + 1, length - 2, error, conf)}; } } else if (string[0] == '{' && string[length - 1] == '}') { @@ -434,7 +443,7 @@ static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, if (string[i] == '}') depth--; } if (depth == 0) { - return (lvalue_t){LVALUE_MEMORY16, .memory_address = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value)}; + return (lvalue_t){LVALUE_MEMORY16, .memory_address = debugger_evaluate(gb, string + 1, length - 2, error, conf)}; } } @@ -473,9 +482,9 @@ static lvalue_t debugger_evaluate_lvalue(GB_gameboy_t *gb, const char *string, } #define ERROR ((value_t){0,}) -value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, - size_t length, bool *error, - uint16_t *watchpoint_address, uint8_t *watchpoint_new_value) +static value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, + size_t length, bool *error, + const evaluate_conf_t *conf) { /* Disable watchpoints while evaluating expressions */ uint16_t n_watchpoints = gb->n_watchpoints; @@ -510,7 +519,7 @@ value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, if (string[i] == ')') depth--; } if (depth == 0) { - ret = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + ret = debugger_evaluate(gb, string + 1, length - 2, error, conf); goto exit; } } @@ -528,7 +537,7 @@ value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, } if (depth == 0) { - value_t addr = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + value_t addr = debugger_evaluate(gb, string + 1, length - 2, error, conf); banking_state_t state; if (addr.bank) { save_banking_state(gb, &state); @@ -555,7 +564,7 @@ value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, } if (depth == 0) { - value_t addr = debugger_evaluate(gb, string + 1, length - 2, error, watchpoint_address, watchpoint_new_value); + value_t addr = debugger_evaluate(gb, string + 1, length - 2, error, conf); banking_state_t state; if (addr.bank) { save_banking_state(gb, &state); @@ -600,15 +609,15 @@ value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, } if (operator_index != -1) { unsigned right_start = (unsigned)(operator_pos + strlen(operators[operator_index].string)); - value_t right = debugger_evaluate(gb, string + right_start, length - right_start, error, watchpoint_address, watchpoint_new_value); + value_t right = debugger_evaluate(gb, string + right_start, length - right_start, error, conf); if (*error) goto exit; if (operators[operator_index].lvalue_operator) { - lvalue_t left = debugger_evaluate_lvalue(gb, string, operator_pos, error, watchpoint_address, watchpoint_new_value); + lvalue_t left = debugger_evaluate_lvalue(gb, string, operator_pos, error, conf); if (*error) goto exit; ret = operators[operator_index].lvalue_operator(gb, left, right.value); goto exit; } - value_t left = debugger_evaluate(gb, string, operator_pos, error, watchpoint_address, watchpoint_new_value); + value_t left = debugger_evaluate(gb, string, operator_pos, error, conf); if (*error) goto exit; ret = operators[operator_index].operator(left, right); goto exit; @@ -640,22 +649,22 @@ value_t debugger_evaluate(GB_gameboy_t *gb, const char *string, case 'p': if (string[1] == 'c') {ret = (value_t){true, bank_for_addr(gb, gb->pc), gb->pc}; goto exit;} } } - else if (length == 3) { - if (watchpoint_address && memcmp(string, "old", 3) == 0) { - ret = VALUE_16(GB_read_memory(gb, *watchpoint_address)); + else if (length == 3 && conf) { + if (memcmp(string, "old", 3) == 0) { + if (conf->old_as_value) { + ret = VALUE_16(conf->old_value); + } + else { + ret = VALUE_16(GB_read_memory(gb, conf->old_address)); + } goto exit; } - if (watchpoint_new_value && memcmp(string, "new", 3) == 0) { - ret = VALUE_16(*watchpoint_new_value); + if (memcmp(string, "new", 3) == 0) { + ret = VALUE_16(conf->new_value); goto exit; } - /* $new is identical to $old in read conditions */ - if (watchpoint_address && memcmp(string, "new", 3) == 0) { - ret = VALUE_16(GB_read_memory(gb, *watchpoint_address)); - goto exit; - } } char symbol_name[length + 1]; @@ -1036,7 +1045,7 @@ static bool breakpoint(GB_gameboy_t *gb, char *arguments, char *modifiers, const condition += strlen(" if "); /* Verify condition is sane (Todo: This might have side effects!) */ bool error; - debugger_evaluate(gb, condition, (unsigned)strlen(condition), &error, NULL, NULL); + debugger_evaluate(gb, condition, (unsigned)strlen(condition), &error, NULL); if (error) return true; } @@ -1050,13 +1059,13 @@ static bool breakpoint(GB_gameboy_t *gb, char *arguments, char *modifiers, const } bool error; - value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL); if (error) return true; uint16_t length = 0; value_t end = result; if (to) { - end = debugger_evaluate(gb, to, (unsigned)strlen(to), &error, NULL, NULL); + end = debugger_evaluate(gb, to, (unsigned)strlen(to), &error, NULL); if (error) return true; if (end.has_bank && result.has_bank && end.bank != result.bank) { GB_log(gb, "Breakpoint range start and end points have different banks\n"); @@ -1211,9 +1220,12 @@ static bool watch(GB_gameboy_t *gb, char *arguments, char *modifiers, const debu /* Verify condition is sane (Todo: This might have side effects!) */ bool error; /* To make new and old legal */ - uint16_t dummy = 0; - uint8_t dummy2 = 0; - debugger_evaluate(gb, condition, (unsigned)strlen(condition), &error, &dummy, &dummy2); + static const evaluate_conf_t conf = { + .old_as_value = true, + .old_value = 0, + .new_value = 0, + }; + debugger_evaluate(gb, condition, (unsigned)strlen(condition), &error, &conf); if (error) return true; } @@ -1226,13 +1238,13 @@ static bool watch(GB_gameboy_t *gb, char *arguments, char *modifiers, const debu } bool error; - value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL); uint32_t key = WP_KEY(result); uint16_t length = 0; value_t end = result; if (to) { - end = debugger_evaluate(gb, to, (unsigned)strlen(to), &error, NULL, NULL); + end = debugger_evaluate(gb, to, (unsigned)strlen(to), &error, NULL); if (error) return true; if (end.has_bank && result.has_bank && end.bank != result.bank) { GB_log(gb, "Watchpoint range start and end points have different banks\n"); @@ -1413,7 +1425,7 @@ static unsigned should_break(GB_gameboy_t *gb, uint16_t addr, bool jump_to) bool error; bool condition = debugger_evaluate(gb, breakpoint->condition, (unsigned)strlen(breakpoint->condition), - &error, NULL, NULL).value; + &error, NULL).value; if (error) { GB_log(gb, "The condition for breakpoint %u is no longer a valid expression\n", breakpoint->id); return breakpoint->id; @@ -1453,7 +1465,7 @@ static bool print(GB_gameboy_t *gb, char *arguments, char *modifiers, const debu } bool error; - value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + value_t result = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL); if (!error) { switch (modifiers[0]) { case 'a': @@ -1499,7 +1511,7 @@ static bool examine(GB_gameboy_t *gb, char *arguments, char *modifiers, const de } bool error; - value_t addr = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + value_t addr = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL); uint16_t count = 32; if (modifiers) { @@ -1551,7 +1563,7 @@ static bool disassemble(GB_gameboy_t *gb, char *arguments, char *modifiers, cons } bool error; - value_t addr = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL, NULL); + value_t addr = debugger_evaluate(gb, arguments, (unsigned)strlen(arguments), &error, NULL); uint16_t count = 5; if (modifiers) { @@ -2320,9 +2332,19 @@ static void test_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t flags, uint return; } bool error; + evaluate_conf_t conf = { + .old_as_value = flags == WATCHPOINT_READ, + .new_value = value, + }; + if (flags == WATCHPOINT_READ) { + conf.old_value = value; + } + else { + conf.old_address = addr; + } bool condition = debugger_evaluate(gb, watchpoint->condition, (unsigned)strlen(watchpoint->condition), - &error, &addr, flags == WATCHPOINT_WRITE? &value : NULL).value; + &error, &conf).value; if (error) { GB_log(gb, "The condition for watchpoint %u is no longer a valid expression\n", watchpoint->id); GB_debugger_break(gb); @@ -2714,7 +2736,7 @@ bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result GB_ASSERT_NOT_RUNNING_OTHER_THREAD(gb) bool error = false; - value_t value = debugger_evaluate(gb, string, strlen(string), &error, NULL, NULL); + value_t value = debugger_evaluate(gb, string, strlen(string), &error, NULL); if (result) { *result = value.value; } @@ -2724,6 +2746,26 @@ bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result return error; } +#ifndef GB_DISABLE_CHEAT_SEARCH +internal bool GB_debugger_evaluate_cheat_filter(GB_gameboy_t *gb, const char *string, bool *result, uint16_t old, uint16_t new) +{ + GB_ASSERT_NOT_RUNNING_OTHER_THREAD(gb) + + bool error = false; + evaluate_conf_t conf = { + .old_as_value = true, + .old_value = old, + .new_value = new, + }; + value_t value = debugger_evaluate(gb, string, strlen(string), &error, &conf); + if (result) { + *result = value.value; + } + + return error; +} +#endif + void GB_debugger_break(GB_gameboy_t *gb) { gb->debug_stopped = true; diff --git a/Core/debugger.h b/Core/debugger.h @@ -31,6 +31,9 @@ internal void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, internal void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr); internal const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr, bool prefer_local); internal void GB_debugger_add_symbol(GB_gameboy_t *gb, uint16_t bank, uint16_t address, const char *symbol); +#ifndef GB_DISABLE_CHEAT_SEARCH +internal bool GB_debugger_evaluate_cheat_filter(GB_gameboy_t *gb, const char *string, bool *result, uint16_t old, uint16_t new); +#endif #endif #else // GB_DISABLE_DEBUGGER diff --git a/Core/gb.c b/Core/gb.c @@ -230,6 +230,9 @@ void GB_free(GB_gameboy_t *gb) GB_remove_cheat(gb, gb->cheats[0]); } #endif +#ifndef GB_DISABLE_CHEAT_SEARCH + GB_cheat_search_reset(gb); +#endif GB_stop_audio_recording(gb); memset(gb, 0, sizeof(*gb)); } @@ -1690,7 +1693,7 @@ static void GB_reset_internal(GB_gameboy_t *gb, bool quick) uint8_t extra_oam[sizeof(gb->extra_oam)]; uint8_t dma, obp0, obp1; } *preserved_state = NULL; - + if (quick) { preserved_state = alloca(sizeof(*preserved_state)); memcpy(preserved_state->hram, gb->hram, sizeof(gb->hram)); @@ -1810,6 +1813,11 @@ void GB_quick_reset(GB_gameboy_t *gb) void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model) { GB_ASSERT_NOT_RUNNING(gb) + +#ifndef GB_DISABLE_CHEAT_SEARCH + GB_cheat_search_reset(gb); +#endif + gb->model = model; if (GB_is_cgb(gb)) { gb->ram = realloc(gb->ram, gb->ram_size = 0x1000 * 8); diff --git a/Core/gb.h b/Core/gb.h @@ -9,6 +9,14 @@ extern "C" { #include <stdalign.h> #include <time.h> +#ifdef GB_DISABLE_CHEATS +#define GB_DISABLE_CHEAT_SEARCH +#else +#ifdef GB_DISABLE_DEBUGGER +#define GB_DISABLE_CHEAT_SEARCH +#endif +#endif + #include "model.h" #include "defs.h" #include "save_state.h" @@ -27,6 +35,7 @@ extern "C" { #include "symbol_hash.h" #include "sgb.h" #include "cheats.h" +#include "cheat_search.h" #include "rumble.h" #include "workboy.h" #include "random.h" @@ -819,6 +828,12 @@ struct GB_gameboy_internal_s { GB_cheat_t **cheats; GB_cheat_hash_t *cheat_hash[256]; #endif +#ifndef GB_DISABLE_CHEAT_SEARCH + uint8_t *cheat_search_data; + uint8_t *cheat_search_bitmap; + size_t cheat_search_count; + GB_cheat_search_data_type_t cheat_search_data_type; +#endif /* Misc */ bool turbo;

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.