home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / GBCheatsDlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  24.1 KB  |  1,010 lines

  1. // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
  2. // Copyright (C) 1999-2003 Forgotten
  3. // Copyright (C) 2004 Forgotten and the VBA development team
  4.  
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2, or(at your option)
  8. // any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software Foundation,
  17. // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  
  19. // GBCheats.cpp : implementation file
  20. //
  21.  
  22. #include "stdafx.h"
  23. #include "vba.h"
  24. #include "GBCheatsDlg.h"
  25. #include "Reg.h"
  26. #include "StringTokenizer.h"
  27. #include "WinResUtil.h"
  28.  
  29. #include "../System.h"
  30. #include "../CheatSearch.h"
  31. #include "../gb/gbCheats.h"
  32. #include "../gb/gbGlobals.h"
  33.  
  34. #ifdef _DEBUG
  35. #define new DEBUG_NEW
  36. #undef THIS_FILE
  37. static char THIS_FILE[] = __FILE__;
  38. #endif
  39.  
  40. static bool winGbCheatAddVerifyGs(const char *code, const char *desc)
  41. {
  42.   gbAddGsCheat(code, desc);
  43.   return true;
  44. }
  45.  
  46. static bool winGbCheatAddVerifyGg(const char *code, const char *desc)
  47. {
  48.   gbAddGgCheat(code, desc);
  49.   return true;
  50. }
  51.  
  52. /////////////////////////////////////////////////////////////////////////////
  53. // GBCheatSearch dialog
  54.  
  55. GBCheatSearch::GBCheatSearch(CWnd* pParent /*=NULL*/)
  56.   : CDialog(GBCheatSearch::IDD, pParent)
  57. {
  58.   //{{AFX_DATA_INIT(GBCheatSearch)
  59.   searchType = -1;
  60.   numberType = -1;
  61.   sizeType = -1;
  62.   updateValues = FALSE;
  63.   valueType = -1;
  64.   //}}AFX_DATA_INIT
  65.   data = NULL;
  66. }
  67.  
  68. GBCheatSearch::~GBCheatSearch()
  69. {
  70.   if(data)
  71.     free(data);
  72. }
  73.  
  74. void GBCheatSearch::DoDataExchange(CDataExchange* pDX)
  75. {
  76.   CDialog::DoDataExchange(pDX);
  77.   //{{AFX_DATA_MAP(GBCheatSearch)
  78.   DDX_Control(pDX, IDC_VALUE, m_value);
  79.   DDX_Control(pDX, IDC_CHEAT_LIST, m_list);
  80.   DDX_Radio(pDX, IDC_EQ, searchType);
  81.   DDX_Radio(pDX, IDC_SIGNED, numberType);
  82.   DDX_Radio(pDX, IDC_SIZE_8, sizeType);
  83.   DDX_Check(pDX, IDC_UPDATE, updateValues);
  84.   DDX_Radio(pDX, IDC_OLD_VALUE, valueType);
  85.   //}}AFX_DATA_MAP
  86. }
  87.  
  88.  
  89. BEGIN_MESSAGE_MAP(GBCheatSearch, CDialog)
  90.   //{{AFX_MSG_MAP(GBCheatSearch)
  91.   ON_BN_CLICKED(ID_OK, OnOk)
  92.   ON_BN_CLICKED(IDC_ADD_CHEAT, OnAddCheat)
  93.   ON_BN_CLICKED(IDC_SEARCH, OnSearch)
  94.   ON_BN_CLICKED(IDC_START, OnStart)
  95.   ON_BN_CLICKED(IDC_UPDATE, OnUpdate)
  96.   ON_NOTIFY(LVN_GETDISPINFO, IDC_CHEAT_LIST, OnGetdispinfoCheatList)
  97.   ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHEAT_LIST, OnItemchangedCheatList)
  98.   ON_CONTROL_RANGE(BN_CLICKED, IDC_OLD_VALUE, IDC_SPECIFIC_VALUE, OnValueType)
  99.   ON_CONTROL_RANGE(BN_CLICKED, IDC_EQ, IDC_GE, OnSearchType)
  100.   ON_CONTROL_RANGE(BN_CLICKED, IDC_SIGNED, IDC_HEXADECIMAL, OnNumberType)
  101.   ON_CONTROL_RANGE(BN_CLICKED, IDC_SIZE_8, IDC_SIZE_32, OnSizeType)
  102.   //}}AFX_MSG_MAP
  103. END_MESSAGE_MAP()
  104.  
  105.   /////////////////////////////////////////////////////////////////////////////
  106. // GBCheatSearch message handlers
  107.  
  108. void GBCheatSearch::OnOk() 
  109. {
  110.   if(data)
  111.     free(data);
  112.   data = NULL;
  113.   EndDialog(TRUE);
  114. }
  115.  
  116. void GBCheatSearch::OnAddCheat() 
  117. {
  118.   int mark = m_list.GetSelectionMark();
  119.   
  120.   if(mark != -1) {
  121.     LVITEM item;
  122.     memset(&item,0, sizeof(item));
  123.     item.mask = LVIF_PARAM;
  124.     item.iItem = mark;
  125.     if(m_list.GetItem(&item)) {
  126.       AddGBCheat dlg((u32)item.lParam);
  127.       dlg.DoModal();
  128.     }
  129.   }
  130. }
  131.  
  132. void GBCheatSearch::OnSearch() 
  133. {
  134.   CString buffer;
  135.   if(valueType == 0)
  136.     cheatSearch(&cheatSearchData,
  137.         searchType,
  138.         sizeType,
  139.         numberType == 0);
  140.   else {
  141.     m_value.GetWindowText(buffer);
  142.     if(buffer.IsEmpty()) {
  143.       systemMessage(IDS_NUMBER_CANNOT_BE_EMPTY, "Number cannot be empty");
  144.       return;
  145.     }
  146.     int value = 0;
  147.     switch(numberType) {
  148.     case 0:
  149.       sscanf(buffer, "%d", &value);
  150.       break;
  151.     case 1:
  152.       sscanf(buffer, "%u", &value);
  153.       break;
  154.     default:
  155.       sscanf(buffer, "%x", &value);
  156.     }
  157.     cheatSearchValue(&cheatSearchData,
  158.                      searchType,
  159.                      sizeType,
  160.                      numberType == 0,
  161.                      value);
  162.   }
  163.   
  164.   addChanges(true);
  165.  
  166.   if(updateValues)
  167.     cheatSearchUpdateValues(&cheatSearchData);
  168. }
  169.  
  170. void GBCheatSearch::OnStart() 
  171. {
  172.   if(cheatSearchData.count == 0) {
  173.     int i = 0;
  174.  
  175.     CheatSearchBlock *block = &cheatSearchData.blocks[0];
  176.  
  177.     if(gbRamSize) {
  178.       block->offset = 0xa000;
  179.       if(gbRam)
  180.     block->data = gbRam;
  181.       else
  182.     block->data = &gbMemory[0xa000];
  183.       block->saved = (u8*)malloc(gbRamSize);
  184.       block->size = gbRamSize;
  185.       block->bits = (u8 *)malloc(gbRamSize >> 3);
  186.       i++;
  187.     }
  188.     block = &cheatSearchData.blocks[i];
  189.     if(gbCgbMode) {
  190.       block->offset = 0xc000;
  191.       block->data = &gbMemory[0xc000];
  192.       block->saved = (u8*)malloc(0x1000);
  193.       block->size = 0x1000;
  194.       block->bits = (u8 *)malloc(0x1000 >> 3);
  195.       i++;
  196.       block =&cheatSearchData.blocks[i];
  197.       block->offset = 0xd000;
  198.       block->data = gbWram;
  199.       block->saved = (u8*)malloc(0x8000);
  200.       block->size = 0x8000;
  201.       block->bits = (u8 *)malloc(0x8000 >> 3);
  202.       i++;        
  203.     } else {
  204.       block->offset = 0xc000;
  205.       block->data = &gbMemory[0xc000];
  206.       block->saved = (u8*)malloc(0x2000);
  207.       block->size = 0x2000;
  208.       block->bits = (u8 *)malloc(0x2000 >> 3);
  209.       i++;    
  210.     }
  211.     cheatSearchData.count = i;
  212.   }
  213.  
  214.   cheatSearchStart(&cheatSearchData);
  215.   GetDlgItem(IDC_SEARCH)->EnableWindow(TRUE);
  216. }
  217.  
  218. void GBCheatSearch::OnUpdate() 
  219. {
  220.   if(GetDlgItem(IDC_UPDATE)->SendMessage(BM_GETCHECK,
  221.                                          0,
  222.                                          0) & BST_CHECKED)
  223.     updateValues = true;
  224.   else
  225.     updateValues = false;
  226.   regSetDwordValue("gbCheatsUpdate", updateValues);
  227. }
  228.  
  229. BOOL GBCheatSearch::OnInitDialog() 
  230. {
  231.   CDialog::OnInitDialog();
  232.  
  233.   CString temp = winResLoadString(IDS_ADDRESS);
  234.  
  235.   m_list.InsertColumn(0, temp, LVCFMT_CENTER, 125, 0);
  236.  
  237.   temp = winResLoadString(IDS_OLD_VALUE);
  238.   m_list.InsertColumn(1, temp, LVCFMT_CENTER, 125, 1);
  239.  
  240.   temp = winResLoadString(IDS_NEW_VALUE);
  241.   m_list.InsertColumn(2, temp, LVCFMT_CENTER, 125, 2);
  242.   
  243.   m_list.SetFont(CFont::FromHandle((HFONT)GetStockObject(SYSTEM_FIXED_FONT)),
  244.                  TRUE);
  245.  
  246.   m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT);
  247.   
  248.   if(!cheatSearchData.count) {
  249.     GetDlgItem(IDC_SEARCH)->EnableWindow(FALSE);
  250.     GetDlgItem(IDC_ADD_CHEAT)->EnableWindow(FALSE);
  251.   }
  252.  
  253.   valueType = regQueryDwordValue("gbCheatsValueType", 0);
  254.   if(valueType < 0 || valueType > 1)
  255.     valueType = 2;
  256.   
  257.   searchType = regQueryDwordValue("gbCheatsSearchType",
  258.                                   SEARCH_EQ);
  259.   if(searchType < 0 || searchType > 5)
  260.     searchType = 0;
  261.   
  262.   numberType = regQueryDwordValue("gbCheatsNumberType", 2);
  263.   if(numberType < 0 || numberType > 2)
  264.     numberType = 2;
  265.   
  266.   sizeType = regQueryDwordValue("gbCheatsSizeType", 0);
  267.   if(sizeType < 0 || sizeType > 2)
  268.     sizeType = 0;
  269.   
  270.   updateValues = regQueryDwordValue("gbCheatsUpdate", 0) ?
  271.     true : false;
  272.   
  273.   UpdateData(FALSE);
  274.  
  275.   if(valueType == 0)
  276.     m_value.EnableWindow(FALSE);
  277.   
  278.   CenterWindow();
  279.  
  280.   if(cheatSearchData.count) {
  281.     addChanges(false);
  282.   }
  283.  
  284.   
  285.   return TRUE;  // return TRUE unless you set the focus to a control
  286.                 // EXCEPTION: OCX Property Pages should return FALSE
  287. }
  288.  
  289. void GBCheatSearch::OnGetdispinfoCheatList(NMHDR* pNMHDR, LRESULT* pResult) 
  290. {
  291.   LV_DISPINFO* info = (LV_DISPINFO*)pNMHDR;
  292.   if(info->item.mask & LVIF_TEXT) {
  293.     int index = info->item.iItem;
  294.     int col = info->item.iSubItem;
  295.     
  296.     switch(col) {
  297.     case 0:
  298.       strcpy(info->item.pszText, data[index].address);
  299.       break;
  300.     case 1:
  301.       strcpy(info->item.pszText, data[index].oldValue);
  302.       break;
  303.     case 2:
  304.       strcpy(info->item.pszText, data[index].newValue);
  305.       break;
  306.     }
  307.   }
  308.   *pResult = TRUE;
  309. }
  310.  
  311. void GBCheatSearch::OnItemchangedCheatList(NMHDR* pNMHDR, LRESULT* pResult) 
  312. {
  313.   GetDlgItem(IDC_ADD_CHEAT)->EnableWindow(m_list.GetSelectionMark() != -1);
  314. }
  315.  
  316. int GBCheatSearch::getBank(u16 addr, int j)
  317. {
  318.   switch(addr >> 12) {
  319.   case 0x0a:
  320.     return j / 0x2000;
  321.   case 0x0d:
  322.     return j / 0x1000;
  323.   }
  324.   return 0;
  325. }
  326.  
  327. void GBCheatSearch::addChange(int index, int bank, u16 address, int offset, u32 oldValue, u32 newValue)
  328. {
  329.   data[index].bank = bank;
  330.   if(bank) {
  331.     if(address == 0xa000)
  332.       address |= offset & 0x1fff;
  333.     else
  334.       address |= offset & 0xfff;
  335.   } else
  336.     address |= offset;
  337.   data[index].addr = address;
  338.   sprintf(data[index].address, "%02x:%04x",bank,address);
  339.   switch(numberType) {
  340.   case 0:
  341.     sprintf(data[index].oldValue, "%d", oldValue);
  342.     sprintf(data[index].newValue, "%d", newValue);
  343.     break;        
  344.   case 1:
  345.     sprintf(data[index].oldValue, "%u", oldValue);
  346.     sprintf(data[index].newValue, "%u", newValue);
  347.     break;    
  348.   case 2:
  349.     switch(sizeType) {
  350.     case 0:
  351.       sprintf(data[index].oldValue, "%02x", oldValue);
  352.       sprintf(data[index].newValue, "%02x", newValue);      
  353.       break;
  354.     case 1:
  355.       sprintf(data[index].oldValue, "%04x", oldValue);
  356.       sprintf(data[index].newValue, "%04x", newValue);      
  357.       break;
  358.     case 2:
  359.       sprintf(data[index].oldValue, "%08x", oldValue);
  360.       sprintf(data[index].newValue, "%08x", newValue);      
  361.       break;
  362.     }
  363.   }
  364. }
  365.  
  366. void GBCheatSearch::addChanges(bool showMsg)
  367. {
  368.   int count = cheatSearchGetCount(&cheatSearchData, sizeType);
  369.     
  370.   m_list.DeleteAllItems();
  371.  
  372.   if(count > 1000) {
  373.     if(showMsg)
  374.       systemMessage(IDS_SEARCH_PRODUCED_TOO_MANY,
  375.                     "Search produced %d results. Please refine better",
  376.                     count);
  377.     return;
  378.   }  
  379.  
  380.   if(count == 0) {
  381.     if(showMsg)
  382.       systemMessage(IDS_SEARCH_PRODUCED_NO_RESULTS,
  383.                     "Search produced no results");
  384.     return;
  385.   }
  386.   
  387.   m_list.SetItemCount(count);  
  388.   if(data)
  389.     free(data);
  390.  
  391.   data = (WinGbCheatsData *)calloc(count, sizeof(WinGbCheatsData));
  392.   
  393.   int inc = 1;
  394.   switch(sizeType) {
  395.   case 1:
  396.     inc = 2;
  397.     break;
  398.   case 2:
  399.     inc = 4;
  400.     break;
  401.   }
  402.   
  403.   int index = 0;
  404.   if(numberType == 0) {
  405.     for(int i = 0; i < cheatSearchData.count; i++) {
  406.       CheatSearchBlock *block = &cheatSearchData.blocks[i];
  407.       
  408.       for(int j = 0; j < block->size; j+= inc) {
  409.         if(IS_BIT_SET(block->bits, j)) {
  410.           addChange(index++,
  411.             getBank(block->offset|j, j),
  412.                     block->offset,
  413.             j,
  414.                     cheatSearchSignedRead(block->saved,
  415.                                           j,
  416.                                           sizeType),
  417.                     cheatSearchSignedRead(block->data,
  418.                                           j,
  419.                                           sizeType));
  420.         }
  421.       }
  422.     }
  423.   } else {
  424.     for(int i = 0; i < cheatSearchData.count; i++) {
  425.       CheatSearchBlock *block = &cheatSearchData.blocks[i];
  426.       
  427.       for(int j = 0; j < block->size; j+= inc) {
  428.         if(IS_BIT_SET(block->bits, j)) {
  429.           addChange(index++,
  430.             getBank(block->offset|j, j),
  431.                     block->offset,
  432.             j,
  433.                     cheatSearchRead(block->saved,
  434.                     j,
  435.                     sizeType),
  436.                     cheatSearchRead(block->data,
  437.                     j,
  438.                     sizeType));
  439.         }
  440.       }
  441.     }
  442.   }
  443.  
  444.   for(int i = 0; i < count; i++) {
  445.     LVITEM item;
  446.  
  447.     item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  448.     item.iItem = i;
  449.     item.iSubItem = 0;
  450.     item.lParam = data[i].addr|
  451.       (data[i].bank << 16);
  452.     item.state = 0;
  453.     item.stateMask = 0;
  454.     item.pszText = LPSTR_TEXTCALLBACK;
  455.     m_list.InsertItem(&item);
  456.  
  457.     m_list.SetItemText(i, 1, LPSTR_TEXTCALLBACK);
  458.     m_list.SetItemText(i, 2, LPSTR_TEXTCALLBACK);
  459.   }  
  460. }
  461.  
  462. void GBCheatSearch::OnValueType(UINT id)
  463. {
  464.   switch(id) {
  465.   case IDC_OLD_VALUE:
  466.     valueType = 0;
  467.     m_value.EnableWindow(FALSE);
  468.     regSetDwordValue("gbCheatsValueType", 0);
  469.     break;
  470.   case IDC_SPECIFIC_VALUE:
  471.     valueType = 1;
  472.     m_value.EnableWindow(TRUE);
  473.     regSetDwordValue("gbCheatsValueType", 1);   
  474.     break;
  475.   }
  476. }
  477.  
  478. void GBCheatSearch::OnSearchType(UINT id)
  479. {
  480.   switch(id) {
  481.   case IDC_EQ:
  482.     searchType = SEARCH_EQ;
  483.     regSetDwordValue("gbCheatsSearchType", 0);
  484.     break;
  485.   case IDC_NE:
  486.     searchType = SEARCH_NE;
  487.     regSetDwordValue("gbCheatsSearchType", 1);
  488.     break;
  489.   case IDC_LT:
  490.     searchType = SEARCH_LT;
  491.     regSetDwordValue("gbCheatsSearchType", 2);
  492.     break;
  493.   case IDC_LE:
  494.     searchType = SEARCH_LE;
  495.     regSetDwordValue("gbCheatsSearchType", 3);
  496.     break;
  497.   case IDC_GT:
  498.     searchType = SEARCH_GT;
  499.     regSetDwordValue("gbCheatsSearchType", 4);
  500.     break;
  501.   case IDC_GE:
  502.     searchType = SEARCH_GE;
  503.     regSetDwordValue("gbCheatsSearchType", 5);
  504.     break;
  505.   }
  506. }
  507.  
  508. void GBCheatSearch::OnNumberType(UINT id)
  509. {
  510.   switch(id) {
  511.   case IDC_SIGNED:
  512.     numberType = 0;
  513.     regSetDwordValue("gbCheatsNumberType", 0);
  514.     if(m_list.GetItemCount()) {
  515.       addChanges(false);
  516.     }
  517.     break;
  518.   case IDC_UNSIGNED:
  519.     numberType = 1;
  520.     regSetDwordValue("gbCheatsNumberType", 1);
  521.     if(m_list.GetItemCount()) {
  522.       addChanges(false);
  523.     }
  524.     break;
  525.   case IDC_HEXADECIMAL:
  526.     numberType = 2;
  527.     regSetDwordValue("gbCheatsNumberType", 2);
  528.     if(m_list.GetItemCount()) {
  529.       addChanges(false);
  530.     }
  531.     break;
  532.   }
  533. }
  534.  
  535. void GBCheatSearch::OnSizeType(UINT id)
  536. {
  537.   switch(id) {
  538.   case IDC_SIZE_8:
  539.     sizeType = BITS_8;
  540.     regSetDwordValue("gbCheatsSizeType", 0);
  541.     if(m_list.GetItemCount()) {
  542.       addChanges(false);
  543.     }
  544.     break;
  545.   case IDC_SIZE_16:
  546.     sizeType = BITS_16;
  547.     regSetDwordValue("gbCheatsSizeType", 1);
  548.     if(m_list.GetItemCount()) {
  549.       addChanges(false);
  550.     }
  551.     break;
  552.   case IDC_SIZE_32:
  553.     sizeType = BITS_32;
  554.     regSetDwordValue("gbCheatsSizeType", 2);
  555.     if(m_list.GetItemCount()) {
  556.       addChanges(false);
  557.     }
  558.     break;
  559.   }
  560. }
  561. /////////////////////////////////////////////////////////////////////////////
  562. // AddGBCheat dialog
  563.  
  564.  
  565. AddGBCheat::AddGBCheat(u32 addr, CWnd* pParent /*=NULL*/)
  566.   : CDialog(AddGBCheat::IDD, pParent)
  567. {
  568.   //{{AFX_DATA_INIT(AddGBCheat)
  569.   sizeType = -1;
  570.   numberType = -1;
  571.   //}}AFX_DATA_INIT
  572.   address = addr;
  573. }
  574.  
  575.  
  576. void AddGBCheat::DoDataExchange(CDataExchange* pDX)
  577. {
  578.   CDialog::DoDataExchange(pDX);
  579.   //{{AFX_DATA_MAP(AddGBCheat)
  580.   DDX_Control(pDX, IDC_VALUE, m_value);
  581.   DDX_Control(pDX, IDC_ADDRESS, m_address);
  582.   DDX_Control(pDX, IDC_DESC, m_desc);
  583.   DDX_Radio(pDX, IDC_SIZE_8, sizeType);
  584.   DDX_Radio(pDX, IDC_SIGNED, numberType);
  585.   //}}AFX_DATA_MAP
  586. }
  587.  
  588.  
  589. BEGIN_MESSAGE_MAP(AddGBCheat, CDialog)
  590.   //{{AFX_MSG_MAP(AddGBCheat)
  591.   ON_BN_CLICKED(ID_OK, OnOk)
  592.   ON_BN_CLICKED(ID_CANCEL, OnCancel)
  593.   ON_CONTROL_RANGE(BN_CLICKED, IDC_SIGNED, IDC_HEXADECIMAL, OnNumberType)
  594.   ON_CONTROL_RANGE(BN_CLICKED, IDC_SIZE_8, IDC_SIZE_32, OnSizeType)
  595.   //}}AFX_MSG_MAP
  596.   END_MESSAGE_MAP()
  597.  
  598.   /////////////////////////////////////////////////////////////////////////////
  599. // AddGBCheat message handlers
  600.  
  601. void AddGBCheat::OnCancel() 
  602. {
  603.   EndDialog(FALSE);
  604. }
  605.  
  606. void AddGBCheat::OnOk() 
  607. {
  608.   // add cheat
  609.   if(addCheat()) {
  610.     EndDialog(TRUE);
  611.   }
  612. }
  613.  
  614. bool AddGBCheat::addCheat()
  615. {
  616.   CString buffer;
  617.   CString code;
  618.  
  619.   u32 value;
  620.   m_value.GetWindowText(buffer);
  621.   
  622.   if(buffer.IsEmpty()) {
  623.     systemMessage(IDS_VALUE_CANNOT_BE_EMPTY, "Value cannot be empty");
  624.     return false;
  625.   }
  626.   
  627.   switch(numberType) {
  628.   case 0:
  629.     sscanf(buffer, "%d", &value);
  630.     break;
  631.   case 1:
  632.     sscanf(buffer, "%u", &value);
  633.     break;
  634.   default:
  635.     sscanf(buffer, "%x", &value);
  636.   }
  637.  
  638.   m_desc.GetWindowText(buffer);
  639.  
  640.   int bank = (address >> 16);
  641.   address &= 0xFFFF;
  642.  
  643.   if(address >= 0xd000)
  644.     bank += 0x90;
  645.   else
  646.     bank = 0x01;
  647.   
  648.   switch(sizeType) {
  649.   case 0:
  650.     code.Format("%02X%02X%02X%02X", bank, value, address&0xFF, address>>8);
  651.     gbAddGsCheat(code, buffer);
  652.     break;
  653.   case 1:
  654.     code.Format("%02X%02X%02X%02X", bank, value&0xFF, address&0xFF,
  655.                 address>>8);
  656.     gbAddGsCheat(code, buffer);
  657.     address++;
  658.     code.Format("%02X%02X%02X%02X", bank, value>>8, address&0xFF,
  659.                 address>>8);
  660.     gbAddGsCheat(code, buffer);    
  661.     break;
  662.   case 2:
  663.     code.Format("%02X%02X%02X%02X", bank, value&0xFF, address&0xFF,
  664.                 address>>8);
  665.     gbAddGsCheat(code, buffer);
  666.     address++;
  667.     code.Format("%02X%02X%02X%02X", bank, (value>>8) & 0xFF, address&0xFF,
  668.                 address>>8);
  669.     gbAddGsCheat(code, buffer);
  670.     address++;
  671.     code.Format("%02X%02X%02X%02X", bank, (value>>16)&0xFF, address&0xFF,
  672.                 address>>8);
  673.     gbAddGsCheat(code, buffer);
  674.     address++;
  675.     code.Format("%02X%02X%02X%02X", bank, value>>24, address&0xFF,
  676.                 address>>8);
  677.     gbAddGsCheat(code, buffer);    
  678.     break;
  679.   }
  680.   
  681.   return true;
  682. }
  683.  
  684. BOOL AddGBCheat::OnInitDialog() 
  685. {
  686.   CDialog::OnInitDialog();
  687.   
  688.   CString buffer;
  689.   buffer.Format("%02x:%08x", (address>>16), address&0xFFFF);
  690.   m_address.SetWindowText(buffer);
  691.   m_address.EnableWindow(FALSE);
  692.   ::SetWindowLong(m_address,
  693.                   GWL_USERDATA,
  694.                   address);
  695.   
  696.   numberType = regQueryDwordValue("gbCheatsNumberType", 2);
  697.   if(numberType < 0 || numberType > 2)
  698.     numberType = 2;
  699.   
  700.   sizeType = regQueryDwordValue("gbCheatsSizeType", 0);
  701.   if(sizeType < 0 || sizeType > 2)
  702.     sizeType = 0;
  703.  
  704.   UpdateData(FALSE);
  705.   
  706.   m_desc.LimitText(32);
  707.   
  708.   if(address != 0) {
  709.     GetDlgItem(IDC_SIZE_8)->EnableWindow(FALSE);
  710.     GetDlgItem(IDC_SIZE_16)->EnableWindow(FALSE);
  711.     GetDlgItem(IDC_SIZE_32)->EnableWindow(FALSE);
  712.     GetDlgItem(IDC_HEXADECIMAL)->EnableWindow(FALSE);
  713.     GetDlgItem(IDC_UNSIGNED)->EnableWindow(FALSE);
  714.     GetDlgItem(IDC_SIGNED)->EnableWindow(FALSE);        
  715.   }
  716.   CenterWindow();
  717.   
  718.   return TRUE;  // return TRUE unless you set the focus to a control
  719.                 // EXCEPTION: OCX Property Pages should return FALSE
  720. }
  721.  
  722. void AddGBCheat::OnNumberType(UINT id)
  723. {
  724.   switch(id) {
  725.   case IDC_SIGNED:
  726.     numberType = 0;
  727.     regSetDwordValue("gbCheatsNumberType", 0);
  728.     break;
  729.   case IDC_UNSIGNED:
  730.     numberType = 1;
  731.     regSetDwordValue("gbCheatsNumberType", 1);
  732.     break;
  733.   case IDC_HEXADECIMAL:
  734.     numberType = 2;
  735.     regSetDwordValue("gbCheatsNumberType", 2);
  736.     break;
  737.   }
  738. }
  739.  
  740. void AddGBCheat::OnSizeType(UINT id)
  741. {
  742.   switch(id) {
  743.   case IDC_SIZE_8:
  744.     sizeType = BITS_8;
  745.     regSetDwordValue("gbCheatsSizeType", 0);
  746.     break;
  747.   case IDC_SIZE_16:
  748.     sizeType = BITS_16;
  749.     regSetDwordValue("gbCheatsSizeType", 1);
  750.     break;
  751.   case IDC_SIZE_32:
  752.     sizeType = BITS_32;
  753.     regSetDwordValue("gbCheatsSizeType", 2);
  754.     break;
  755.   }
  756. }
  757.  
  758. /////////////////////////////////////////////////////////////////////////////
  759. // GBCheatList dialog
  760.  
  761.  
  762. GBCheatList::GBCheatList(CWnd* pParent /*=NULL*/)
  763.   : CDialog(GBCheatList::IDD, pParent)
  764. {
  765.   //{{AFX_DATA_INIT(GBCheatList)
  766.   // NOTE: the ClassWizard will add member initialization here
  767.   //}}AFX_DATA_INIT
  768.   duringRefresh = false;
  769. }
  770.  
  771.  
  772. void GBCheatList::DoDataExchange(CDataExchange* pDX)
  773. {
  774.   CDialog::DoDataExchange(pDX);
  775.   //{{AFX_DATA_MAP(GBCheatList)
  776.   DDX_Control(pDX, IDC_CHEAT_LIST, m_list);
  777.   //}}AFX_DATA_MAP
  778. }
  779.  
  780.  
  781. BEGIN_MESSAGE_MAP(GBCheatList, CDialog)
  782.   //{{AFX_MSG_MAP(GBCheatList)
  783.   ON_BN_CLICKED(ID_OK, OnOk)
  784.   ON_BN_CLICKED(IDC_ADD_GG_CHEAT, OnAddGgCheat)
  785.   ON_BN_CLICKED(IDC_ADD_GS_CHEAT, OnAddGsCheat)
  786.   ON_BN_CLICKED(IDC_ENABLE, OnEnable)
  787.   ON_BN_CLICKED(IDC_REMOVE, OnRemove)
  788.   ON_BN_CLICKED(IDC_REMOVE_ALL, OnRemoveAll)
  789.   ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHEAT_LIST, OnItemchangedCheatList)
  790.   //}}AFX_MSG_MAP
  791.   END_MESSAGE_MAP()
  792.  
  793.   /////////////////////////////////////////////////////////////////////////////
  794. // GBCheatList message handlers
  795.  
  796. void GBCheatList::OnOk() 
  797. {
  798.   EndDialog(TRUE);
  799. }
  800.  
  801. void GBCheatList::OnAddGgCheat() 
  802. {
  803.   CString temp = winResLoadString(IDS_ADD_GG_CODE);
  804.   AddGBCode dlg(winGbCheatAddVerifyGg, 11, temp);
  805.   dlg.DoModal();
  806.   refresh();
  807. }
  808.  
  809. void GBCheatList::OnAddGsCheat() 
  810. {
  811.   CString temp = winResLoadString(IDS_ADD_GS_CODE);
  812.  
  813.   AddGBCode dlg(winGbCheatAddVerifyGs, 8, temp);
  814.   dlg.DoModal();
  815.   refresh();
  816. }
  817.  
  818. void GBCheatList::OnEnable() 
  819. {
  820.   int mark = m_list.GetSelectionMark();
  821.   
  822.   if(mark != -1) {
  823.     LVITEM item;
  824.     memset(&item,0, sizeof(item));
  825.     item.mask = LVIF_PARAM;
  826.     item.iItem = mark;
  827.     if(m_list.GetItem(&item)) {
  828.       if(gbCheatList[item.lParam].enabled)
  829.         gbCheatDisable(item.lParam);
  830.       else
  831.         gbCheatEnable(item.lParam);
  832.       refresh();
  833.     }       
  834.   }
  835. }
  836.  
  837. void GBCheatList::OnRemove() 
  838. {
  839.   int mark = m_list.GetSelectionMark();
  840.   
  841.   if(mark != -1) {
  842.     LVITEM item;
  843.     memset(&item,0, sizeof(item));
  844.     item.mask = LVIF_PARAM;
  845.     item.iItem = mark;
  846.     if(m_list.GetItem(&item)) {
  847.       gbCheatRemove(item.lParam);
  848.       refresh();
  849.     }       
  850.   }
  851. }
  852.  
  853. void GBCheatList::OnRemoveAll() 
  854. {
  855.   gbCheatRemoveAll();
  856.   refresh();
  857. }
  858.  
  859. void GBCheatList::OnItemchangedCheatList(NMHDR* pNMHDR, LRESULT* pResult) 
  860. {
  861.   if(m_list.GetSelectionMark() != -1) {
  862.     GetDlgItem(IDC_REMOVE)->EnableWindow(TRUE);
  863.     GetDlgItem(IDC_ENABLE)->EnableWindow(TRUE);
  864.   } else {
  865.     GetDlgItem(IDC_REMOVE)->EnableWindow(FALSE);
  866.     GetDlgItem(IDC_ENABLE)->EnableWindow(FALSE);
  867.   }
  868.   
  869.   if(!duringRefresh) {
  870.     LPNMLISTVIEW l = (LPNMLISTVIEW)pNMHDR;
  871.     if(l->uChanged & LVIF_STATE) {
  872.       if(((l->uOldState & LVIS_STATEIMAGEMASK)>>12) !=
  873.          (((l->uNewState & LVIS_STATEIMAGEMASK)>>12))) {
  874.         if(m_list.GetCheck(l->iItem))
  875.           gbCheatEnable(l->lParam);
  876.         else
  877.           gbCheatDisable(l->lParam);
  878.         refresh();
  879.       }
  880.     }
  881.   }    
  882. }
  883.  
  884. BOOL GBCheatList::OnInitDialog() 
  885. {
  886.   CDialog::OnInitDialog();
  887.  
  888.   CString temp = winResLoadString(IDS_CODE);
  889.   m_list.InsertColumn(0, temp, LVCFMT_LEFT, 120, 0);
  890.   temp = winResLoadString(IDS_DESCRIPTION);
  891.   m_list.InsertColumn(1, temp, LVCFMT_LEFT, 200, 1);
  892.   temp = winResLoadString(IDS_STATUS);
  893.   m_list.InsertColumn(2, temp, LVCFMT_LEFT, 80, 2);
  894.   
  895.   m_list.SetFont(CFont::FromHandle((HFONT)GetStockObject(SYSTEM_FIXED_FONT)),
  896.                  TRUE);
  897.  
  898.   m_list.SetExtendedStyle(LVS_EX_CHECKBOXES |
  899.                           LVS_EX_FULLROWSELECT);
  900.   
  901.   refresh();
  902.   GetDlgItem(IDC_REMOVE)->EnableWindow(FALSE);
  903.   GetDlgItem(IDC_ENABLE)->EnableWindow(FALSE);
  904.   CenterWindow();
  905.   
  906.   return TRUE;  // return TRUE unless you set the focus to a control
  907.                 // EXCEPTION: OCX Property Pages should return FALSE
  908. }
  909.  
  910. void GBCheatList::refresh()
  911. {
  912.   duringRefresh = true;
  913.   
  914.   m_list.DeleteAllItems();
  915.   
  916.   char buffer[2];
  917.   
  918.   for(int i = 0; i < gbCheatNumber; i++) {
  919.     LVITEM item;
  920.     
  921.     item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
  922.     item.iItem = i;
  923.     item.iSubItem = 0;
  924.     item.lParam = i;
  925.     item.state = 0;
  926.     item.stateMask = 0;
  927.     item.pszText = gbCheatList[i].cheatCode;
  928.     m_list.InsertItem(&item);
  929.  
  930.     m_list.SetCheck(i, (gbCheatList[i].enabled ? TRUE : FALSE));
  931.     
  932.     m_list.SetItemText(i, 1, gbCheatList[i].cheatDesc);
  933.     
  934.     buffer[0] = (gbCheatList[i].enabled) ? 'E' : 'D';    
  935.     buffer[1] = 0;
  936.     m_list.SetItemText(i, 2, buffer);
  937.   }
  938.   duringRefresh = false;
  939. }
  940.  
  941. /////////////////////////////////////////////////////////////////////////////
  942. // AddGBCode dialog
  943.  
  944.  
  945. AddGBCode::AddGBCode(bool (*verify)(const char *,const char*), int len, const char *title, CWnd* pParent /*=NULL*/)
  946.   : CDialog(AddGBCode::IDD, pParent)
  947. {
  948.   //{{AFX_DATA_INIT(AddGBCode)
  949.   // NOTE: the ClassWizard will add member initialization here
  950.   //}}AFX_DATA_INIT
  951.   addVerify = verify;
  952.   addLength = len;
  953.   addTitle = title;
  954. }
  955.  
  956.  
  957. void AddGBCode::DoDataExchange(CDataExchange* pDX)
  958. {
  959.   CDialog::DoDataExchange(pDX);
  960.   //{{AFX_DATA_MAP(AddGBCode)
  961.   DDX_Control(pDX, IDC_DESC, m_desc);
  962.   DDX_Control(pDX, IDC_CODE, m_code);
  963.   //}}AFX_DATA_MAP
  964. }
  965.  
  966.  
  967. BEGIN_MESSAGE_MAP(AddGBCode, CDialog)
  968.   //{{AFX_MSG_MAP(AddGBCode)
  969.   ON_BN_CLICKED(ID_OK, OnOk)
  970.   ON_BN_CLICKED(ID_CANCEL, OnCancel)
  971.   //}}AFX_MSG_MAP
  972.   END_MESSAGE_MAP()
  973.  
  974.   /////////////////////////////////////////////////////////////////////////////
  975. // AddGBCode message handlers
  976.  
  977. void AddGBCode::OnOk() 
  978. {
  979.   CString desc;
  980.   CString buffer;
  981.   m_code.GetWindowText(buffer);
  982.   m_desc.GetWindowText(desc);
  983.   
  984.   StringTokenizer st(buffer, " \t\n\r");
  985.   const char *t = st.next();
  986.   while(t) {
  987.     addVerify(t, desc);
  988.     t = st.next();
  989.   }
  990.   EndDialog(TRUE);
  991. }
  992.  
  993. void AddGBCode::OnCancel() 
  994. {
  995.   EndDialog(FALSE);
  996. }
  997.  
  998. BOOL AddGBCode::OnInitDialog() 
  999. {
  1000.   CDialog::OnInitDialog();
  1001.   
  1002.   m_code.LimitText(1024);
  1003.   m_desc.LimitText(32);
  1004.   SetWindowText(addTitle);
  1005.   CenterWindow();
  1006.   
  1007.   return TRUE;  // return TRUE unless you set the focus to a control
  1008.                 // EXCEPTION: OCX Property Pages should return FALSE
  1009. }
  1010.