git.y1.nz

SameBoy

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

Cocoa/GBCheatSearchController.m

      1 #import "GBCheatSearchController.h"
      2 #import "GBWarningPopover.h"
      3 #import "GBCheatWindowController.h"
      4 #import "GBPanel.h"
      5 
      6 @interface GBCheatSearchController() <NSTableViewDelegate, NSTableViewDataSource>
      7 @property IBOutlet NSPopUpButton *dataTypeButton;
      8 @property IBOutlet NSPopUpButton *conditionTypeButton;
      9 @property IBOutlet NSTextField *operandField;
     10 @property IBOutlet NSTextField *conditionField;
     11 @property IBOutlet NSTextField *resultsLabel;
     12 @property (strong) IBOutlet NSButton *addCheatButton;
     13 @end
     14 
     15 @implementation GBCheatSearchController
     16 {
     17     __weak Document *_document;
     18     size_t _resultCount;
     19     GB_cheat_search_result_t *_results;
     20     GBPanel *_window;
     21 }
     22 
     23 + (instancetype)controllerWithDocument:(Document *)document
     24 {
     25     GBCheatSearchController *ret = [[self alloc] init];
     26     ret->_document = document;
     27     NSArray *objects;
     28     [[NSBundle mainBundle] loadNibNamed:@"CheatSearch" owner:ret topLevelObjects:&objects];
     29     ret->_resultsLabel.stringValue = @"";
     30     ret->_resultsLabel.cell.backgroundStyle = NSBackgroundStyleRaised;
     31     ret->_window.ownerWindow = document.mainWindow;
     32     return ret;
     33 }
     34 
     35 - (IBAction)reset:(id)sender
     36 {
     37     _dataTypeButton.enabled = true;
     38     [_document performAtomicBlock:^{
     39         GB_cheat_search_reset(_document.gb);
     40     }];
     41     _resultCount = 0;
     42     if (_results) {
     43         free(_results);
     44         _results = NULL;
     45     }
     46     [_tableView reloadData];
     47     _resultsLabel.stringValue = @"";
     48 }
     49 
     50 - (IBAction)search:(id)sender
     51 {
     52     // Dispatch to work around firstResponder oddities
     53     dispatch_async(dispatch_get_main_queue(), ^{
     54         if ([sender isKindOfClass:[NSTextField class]]) {
     55             // Action sent by losing focus rather than pressing enter
     56             if (![sender currentEditor]) return;
     57         }
     58         _dataTypeButton.enabled = false;
     59         [_document performAtomicBlock:^{
     60             __block bool success = false;
     61             NSString *error = [_document captureOutputForBlock:^{
     62                 success = GB_cheat_search_filter(_document.gb, _conditionField.stringValue.UTF8String, _dataTypeButton.selectedTag);
     63             }];
     64             if (!success) {
     65                 dispatch_async(dispatch_get_main_queue(), ^{
     66                     [GBWarningPopover popoverWithContents:error onView:_conditionField];
     67                     NSBeep();
     68                 });
     69                 return;
     70             }
     71             _resultCount = GB_cheat_search_result_count(_document.gb);
     72             _results = malloc(sizeof(*_results) * _resultCount);
     73             GB_cheat_search_get_results(_document.gb, _results);
     74         }];
     75         if (_resultCount == 0) {
     76             _dataTypeButton.enabled = true;
     77             _resultsLabel.stringValue = @"No results.";
     78         }
     79         else {
     80             _resultsLabel.stringValue = [NSString stringWithFormat:@"%@ result%s",
     81                                          [NSNumberFormatter localizedStringFromNumber:@(_resultCount)
     82                                                                           numberStyle:NSNumberFormatterDecimalStyle],
     83                                          _resultCount > 1? "s" : ""];
     84         }
     85         [_tableView reloadData];
     86     });
     87 }
     88 
     89 - (IBAction)conditionChanged:(id)sender
     90 {
     91     unsigned index = [_conditionTypeButton indexOfSelectedItem];
     92     _conditionField.enabled = index == 11;
     93     _operandField.enabled = index >= 1 && index <= 6;
     94     switch ([_conditionTypeButton indexOfSelectedItem]) {
     95         case 0: _conditionField.stringValue = @"1"; break;
     96         case 1: _conditionField.stringValue = [NSString stringWithFormat:@"new == (%@)", _operandField.stringValue]; break;
     97         case 2: _conditionField.stringValue = [NSString stringWithFormat:@"new != (%@)", _operandField.stringValue]; break;
     98         case 3: _conditionField.stringValue = [NSString stringWithFormat:@"new > (%@)", _operandField.stringValue]; break;
     99         case 4: _conditionField.stringValue = [NSString stringWithFormat:@"new >= (%@)", _operandField.stringValue]; break;
    100         case 5: _conditionField.stringValue = [NSString stringWithFormat:@"new < (%@)", _operandField.stringValue]; break;
    101         case 6: _conditionField.stringValue = [NSString stringWithFormat:@"new <= (%@)", _operandField.stringValue]; break;
    102         case 7: _conditionField.stringValue = @"new != old"; break;
    103         case 8: _conditionField.stringValue = @"new == old"; break;
    104         case 9: _conditionField.stringValue = @"new > old"; break;
    105         case 10: _conditionField.stringValue = @"new < old"; break;
    106     }
    107 }
    108 
    109 - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
    110 {
    111     return _resultCount;
    112 }
    113 
    114 - (uint8_t *)addressForRow:(unsigned)row
    115 {
    116     uint8_t *base;
    117     uint32_t offset;
    118     if (_results[row].addr < 0xc000) {
    119         base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_CART_RAM, NULL, NULL);
    120         offset = (_results[row].addr & 0x1FFF) + _results[row].bank * 0x2000;
    121     }
    122     else if (_results[row].addr < 0xe000) {
    123         base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_RAM, NULL, NULL);
    124         offset = (_results[row].addr & 0xFFF) + _results[row].bank * 0x1000;
    125     }
    126     else {
    127         base = GB_get_direct_access(_document.gb, GB_DIRECT_ACCESS_HRAM, NULL, NULL);
    128         offset = (_results[row].addr & 0x7F);
    129     }
    130     return base + offset;
    131 }
    132 
    133 - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
    134 {
    135     switch ([[tableView tableColumns] indexOfObject:tableColumn]) {
    136         case 0:
    137             return [NSString stringWithFormat:@"$%02x:$%04x", _results[row].bank, _results[row].addr];
    138         case 1:
    139             if (_dataTypeButton.selectedTag & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) {
    140                 return [NSString stringWithFormat:@"$%04x", _results[row].value];
    141             }
    142             return [NSString stringWithFormat:@"$%02x", _results[row].value];
    143         default: {
    144             const uint8_t *data = [self addressForRow:row];
    145             GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag;
    146             uint16_t value = data[0];
    147             if (!(dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)) {
    148                 return [NSString stringWithFormat:@"$%02x", value];
    149             }
    150             value |= data[1] << 8;
    151             if ((dataType & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT)) {
    152                 value = __builtin_bswap16(value);
    153             }
    154             return [NSString stringWithFormat:@"$%04x", value];
    155         }
    156     }
    157 }
    158 
    159 - (void)tableView:(NSTableView *)tableView setObjectValue:(NSString *)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
    160 {
    161     [_document performAtomicBlock:^{
    162         __block bool success = false;
    163         __block uint16_t value;
    164         NSString *error = [_document captureOutputForBlock:^{
    165             success = !GB_debugger_evaluate(_document.gb, object.UTF8String, &value, NULL);
    166         }];
    167         if (!success) {
    168             dispatch_async(dispatch_get_main_queue(), ^{
    169                 [GBWarningPopover popoverWithContents:error onView:tableView];
    170                 NSBeep();
    171             });
    172             return;
    173         }
    174         uint8_t *dest = [self addressForRow:row];
    175         GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag;
    176         if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_BE_BIT) {
    177             value = __builtin_bswap16(value);
    178         }
    179         dest[0] = value;
    180         if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) {
    181             dest[1] = value >> 8;
    182         }
    183         dispatch_async(dispatch_get_main_queue(), ^{
    184             [tableView reloadData];
    185         });
    186     }];
    187 }
    188 
    189 - (void)controlTextDidChange:(NSNotification *)obj
    190 {
    191     [self conditionChanged:nil];
    192 }
    193 
    194 - (IBAction)addCheat:(id)sender
    195 {
    196     GB_cheat_search_result_t *result = _results + _tableView.selectedRow;
    197     uint8_t *data = [self addressForRow:_tableView.selectedRow];
    198     GB_cheat_search_data_type_t dataType = _dataTypeButton.selectedTag;
    199     size_t rowToSelect = 0;
    200     GB_get_cheats(_document.gb, &rowToSelect);
    201     [_document performAtomicBlock:^{
    202         GB_add_cheat(_document.gb,
    203                      (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)? "New Cheat (Part 1)" : "New Cheat",
    204                      result->addr, result->bank,
    205                      *data,
    206                      0, false,
    207                      true);
    208         if (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT) {
    209             GB_add_cheat(_document.gb,
    210                          (dataType & GB_CHEAT_SEARCH_DATA_TYPE_16BIT)? "New Cheat (Part 2)" : "New Cheat",
    211                          result->addr + 1, result->bank,
    212                          data[1],
    213                          0, false,
    214                          true);
    215         }
    216         GB_set_cheats_enabled(_document.gb, true);
    217     }];
    218     [_document.cheatsWindow makeKeyAndOrderFront:nil];
    219     [_document.cheatWindowController.cheatsTable reloadData];
    220     [_document.cheatWindowController.cheatsTable selectRow:rowToSelect byExtendingSelection:false];
    221     [_document.cheatWindowController.cheatsTable.delegate tableViewSelectionDidChange:nil];
    222 }
    223 
    224 - (void)tableViewSelectionDidChange:(NSNotification *)notification
    225 {
    226     _addCheatButton.enabled = _tableView.numberOfSelectedRows != 0;
    227 }
    228 
    229 - (void)dealloc
    230 {
    231     if (_results) free(_results);
    232 }
    233 
    234 @end

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