fceux/src/drivers/win/cheat.cpp

1561 lines
48 KiB
C++

/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Ben Parnell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "common.h"
#include "cheat.h"
#include "memview.h"
#include "memwatch.h"
#include "debugger.h"
#include "ramwatch.h"
#include "../../fceu.h"
#include "../../cart.h"
#include "../../cheat.h" // For FCEU_LoadGameCheats()
#include <map>
// static HWND pwindow = 0; // owomomo: removed pwindow because ambiguous, perhaps it is some obseleted early future plan from half developed old FCEUX?
HWND hCheat = 0; //Handle to Cheats dialog
HWND hCheatTip = 0; //Handle to tooltip
HMENU hCheatcontext = 0; //Handle to cheat context menu
bool pauseWhileActive = false; //For checkbox "Pause while active"
extern int globalCheatDisabled;
extern int disableAutoLSCheats;
extern bool wasPausedByCheats;
int CheatWindow;
int CheatStyle = 1;
int CheatMapUsers = 0; // how many windows using cheatmap
#define GGLISTSIZE 128 //hopefully this is enough for all cases
int selcheat;
int selcheatcount;
int ChtPosX,ChtPosY;
int GGConv_wndx=0, GGConv_wndy=0;
static HFONT hFont,hNewFont;
// static int scrollindex;
// static int scrollnum;
// static int scrollmax;
std::map<int, SEARCHPOSSIBLE> possiList;
int possiStart = 0;
int possiItemCount = 0;
int possiTotalCount = 0;
bool possibleUpdate = false;
int lbfocus = 0;
int searchdone;
static int knownvalue = 0;
// int GGaddr, GGcomp, GGval;
// char GGcode[10];
int GGlist[GGLISTSIZE];
static int dontupdateGG; //this eliminates recursive crashing
char* GameGenieLetters = "APZLGITYEOXUKSVN";
// bool dodecode;
HWND hGGConv = 0;
void EncodeGG(char *str, int a, int v, int c);
void ListGGAddresses(HWND hwndDlg);
uint16 StrToU16(char *s)
{
unsigned int ret=0;
sscanf(s,"%4x",&ret);
return ret;
}
uint8 StrToU8(char *s)
{
unsigned int ret=0;
sscanf(s,"%2x",&ret);
return ret;
}
char *U16ToStr(uint16 a)
{
static char str[5];
sprintf(str,"%04X",a);
return str;
}
char *U8ToStr(uint8 a)
{
static char str[3];
sprintf(str,"%02X",a);
return str;
}
//int RedoCheatsCallB(char *name, uint32 a, uint8 v, int s) { //bbit edited: this commented out line was changed to the below for the new fceud
int RedoCheatsCallB(char *name, uint32 a, uint8 v, int c, int s, int type, void* data)
{
char str[256] = { 0 };
GetCheatStr(str, a, v, c);
LVITEM lvi = { 0 };
lvi.mask = LVIF_TEXT;
lvi.iItem = data ? *((int*)data) : GGLISTSIZE;
lvi.pszText = str;
if (data)
SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_SETITEM, 0, (LPARAM)&lvi);
else
lvi.iItem = SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_INSERTITEM, 0, (LPARAM)&lvi);
lvi.iSubItem = 1;
lvi.pszText = name;
SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_SETITEM, 0, (LPARAM)&lvi);
lvi.mask = LVIF_STATE;
lvi.stateMask = LVIS_STATEIMAGEMASK;
lvi.state = INDEXTOSTATEIMAGEMASK(s ? 2 : 1);
SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_SETITEMSTATE, lvi.iItem, (LPARAM)&lvi);
return 1;
}
void RedoCheatsLB(HWND hwndDlg)
{
SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_DELETEALLITEMS, 0, 0);
FCEUI_ListCheats(RedoCheatsCallB, 0);
if (selcheat >= 0)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_DEL), TRUE);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_UPD), TRUE);
} else
{
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_DEL), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_UPD), FALSE);
}
}
HWND InitializeResultsList(HWND hwnd)
{
HWND hwndResults = GetDlgItem(hwnd, IDC_CHEAT_LIST_POSSIBILITIES);
// prepare columns
LVCOLUMN lv = { 0 };
lv.mask = LVCF_TEXT | LVCF_WIDTH;
lv.pszText = "Addr";
lv.cx = 50;
SendMessage(hwndResults, LVM_INSERTCOLUMN, 0, (LPARAM)&lv);
lv.pszText = "Pre";
lv.mask |= LVCF_FMT;
lv.fmt = LVCFMT_RIGHT;
lv.cx = 36;
SendMessage(hwndResults, LVM_INSERTCOLUMN, 1, (LPARAM)&lv);
lv.pszText = "Cur";
SendMessage(hwndResults, LVM_INSERTCOLUMN, 2, (LPARAM)&lv);
// set style to full row select
SendMessage(hwndResults, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
return hwndResults;
}
int ShowResultsCallB(uint32 a, uint8 last, uint8 current)
{
if (hCheat)
{
if (possiList[possiItemCount].update =
(possiList[possiItemCount].addr != a ||
possiList[possiItemCount].previous != last ||
possiList[possiItemCount].current != current))
{
possiList[possiItemCount].addr = a;
possiList[possiItemCount].previous = last;
possiList[possiItemCount].current = current;
possibleUpdate |= possiList[possiItemCount].update;
}
++possiItemCount;
}
return 1;
}
int ShowResults(HWND hwndDlg, bool supressUpdate = false)
{
if (possiList.size() > 64)
possiList.clear();
int count = FCEUI_CheatSearchGetCount();
if (count != possiTotalCount)
{
char str[20];
sprintf(str, "%d Possibilit%s", count, count == 1 ? "y" : "ies");
SetDlgItemText(hwndDlg, IDC_CHEAT_BOX_POSSIBILITIES, str);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_SETITEMCOUNT, count, 0);
possiTotalCount = count;
}
if (count)
{
int first = SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_GETTOPINDEX, 0, 0);
if (first < 0)
first = 0;
int last = first + possiItemCount + 1;
if (last > count)
last = count;
int tmpPossiItemCount = possiItemCount;
possiItemCount = first;
FCEUI_CheatSearchGetRange(first, last, ShowResultsCallB);
possiItemCount = tmpPossiItemCount;
if (possibleUpdate && !supressUpdate)
{
int start = -1, end = -1;
for (int i = first; i < last; ++i)
if (possiList[i - first].update)
{
if (start == -1)
start = i;
end = i;
}
SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_REDRAWITEMS, start, end);
}
possibleUpdate = false;
possiStart = first;
}
return 1;
}
void EnableCheatButtons(HWND hwndDlg, int enable)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_KNOWN), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_KNOWN), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_LABEL_KNOWN), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_EQ), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_NE), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_CHECK_NE_BY), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_NE_BY), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_GT), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_CHECK_GT_BY), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_GT_BY), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_LT), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_CHECK_LT_BY), enable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_LT_BY), enable);
}
HWND InitializeCheatList(HWND hwnd)
{
HWND hwndChtList = GetDlgItem(hwnd, IDC_LIST_CHEATS);
// prepare the columns
LVCOLUMN lv = { 0 };
lv.mask = LVCF_TEXT | LVCF_WIDTH;
lv.pszText = "Code";
lv.cx = 100;
SendMessage(hwndChtList, LVM_INSERTCOLUMN, 0, (LPARAM)&lv);
lv.pszText = "Name";
lv.cx = 132;
SendMessage(hwndChtList, LVM_INSERTCOLUMN, 1, (LPARAM)&lv);
// Add a checkbox to indicate if the cheat is activated
SendMessage(hwndChtList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
return hwndChtList;
}
INT_PTR CALLBACK CheatConsoleCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
POINT pt;
if (ChtPosX != 0 && ChtPosY != 0)
{
pt.x = ChtPosX;
pt.y = ChtPosY;
pt = CalcSubWindowPos(hwndDlg, &pt);
}
else
pt = CalcSubWindowPos(hwndDlg, NULL);
ChtPosX = pt.x;
ChtPosY = pt.y;
// SetWindowPos(hwndDlg, 0, ChtPosX, ChtPosY, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
CheckDlgButton(hwndDlg, IDC_CHEAT_PAUSEWHENACTIVE, pauseWhileActive ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hwndDlg, IDC_CHEAT_GLOBAL_SWITCH, globalCheatDisabled ? BST_UNCHECKED : BST_CHECKED);
CheckDlgButton(hwndDlg, IDC_CHEAT_AUTOLOADSAVE, disableAutoLSCheats == 2 ? BST_UNCHECKED : disableAutoLSCheats == 1 ? BST_INDETERMINATE : BST_CHECKED);
//setup font
SetupCheatFont(hwndDlg);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_ADDR, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_COM, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_KNOWN, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_NE_BY, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_GT_BY, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_LT_BY, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_TEXT, WM_SETFONT, (WPARAM)hNewFont, FALSE);
//text limits
SendDlgItemMessage(hwndDlg, IDC_CHEAT_ADDR, EM_SETLIMITTEXT, 4, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL, EM_SETLIMITTEXT, 2, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_COM, EM_SETLIMITTEXT, 2, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_NAME, EM_SETLIMITTEXT, 256, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_KNOWN, EM_SETLIMITTEXT, 2, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_NE_BY, EM_SETLIMITTEXT, 2, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_GT_BY, EM_SETLIMITTEXT, 2, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_VAL_LT_BY, EM_SETLIMITTEXT, 2, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_TEXT, EM_SETLIMITTEXT, 10, 0);
SendDlgItemMessage(hwndDlg, IDC_CHEAT_GAME_GENIE_TEXT, EM_SETLIMITTEXT, 8, 0);
// limit their characters
DefaultEditCtrlProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_ADDR), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_ADDR), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_VAL), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_COM), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_KNOWN), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_NE_BY), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_GT_BY), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_VAL_LT_BY), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_TEXT), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHEAT_GAME_GENIE_TEXT), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
// Create popup to "Auto load / save with game", since it has 3 states and the text need some explanation
SetCheatToolTip(hwndDlg, IDC_CHEAT_AUTOLOADSAVE);
possiTotalCount = 0;
possiItemCount = SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_GETCOUNTPERPAGE, 0, 0);
ShowResults(hwndDlg);
EnableCheatButtons(hwndDlg, possiTotalCount != 0);
//add header for cheat list and possibilities
InitializeCheatList(hwndDlg);
InitializeResultsList(hwndDlg);
//misc setup
searchdone = 0;
SetDlgItemText(hwndDlg, IDC_CHEAT_VAL_KNOWN, (LPCSTR)U8ToStr(knownvalue));
// Enable Context Sub-Menus
hCheatcontext = LoadMenu(fceu_hInstance, "CHEATCONTEXTMENUS");
break;
}
case WM_KILLFOCUS:
break;
case WM_NCACTIVATE:
if (pauseWhileActive)
{
if (EmulationPaused == 0)
{
EmulationPaused = 1;
wasPausedByCheats = true;
FCEU_printf("Emulation paused: %d\n", EmulationPaused);
}
}
if (CheatStyle && possiTotalCount) {
if ((!wParam) && searchdone) {
searchdone = 0;
FCEUI_CheatSearchSetCurrentAsOriginal();
}
ShowResults(hwndDlg);
}
break;
case WM_QUIT:
case WM_CLOSE:
DestroyWindow(hCheatTip);
if (CheatStyle)
DestroyWindow(hwndDlg);
else
EndDialog(hwndDlg, 0);
break;
case WM_DESTROY:
CheatWindow = 0;
hCheat = NULL;
DeleteCheatFont();
if (searchdone)
FCEUI_CheatSearchSetCurrentAsOriginal();
possiList.clear();
break;
case WM_MOVE:
if (!IsIconic(hwndDlg)) {
RECT wrect;
GetWindowRect(hwndDlg, &wrect);
ChtPosX = wrect.left;
ChtPosY = wrect.top;
#ifdef WIN32
WindowBoundsCheckNoResize(ChtPosX, ChtPosY, wrect.right);
#endif
}
break;
case WM_CONTEXTMENU:
{
// Handle certain subborn context menus for nearly incapable controls.
HWND itemHwnd = (HWND)wParam;
int dlgId = GetDlgCtrlID(itemHwnd);
int sel = SendMessage(itemHwnd, LVM_GETSELECTIONMARK, 0, 0);
HMENU hCheatcontextsub = NULL;
switch (dlgId) {
case IDC_LIST_CHEATS:
// Only open the menu if a cheat is selected
if (selcheat >= 0)
// Open IDC_LIST_CHEATS Context Menu
hCheatcontextsub = GetSubMenu(hCheatcontext, 0);
break;
case IDC_CHEAT_LIST_POSSIBILITIES:
if (sel != -1) {
hCheatcontextsub = GetSubMenu(hCheatcontext, 1);
SetMenuDefaultItem(hCheatcontextsub, CHEAT_CONTEXT_POSSI_ADDTOMEMORYWATCH, false);
}
}
if (hCheatcontextsub)
{
POINT point;
if (lParam != -1)
{
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
} else {
// Handle the context menu keyboard key
RECT wrect;
wrect.left = LVIR_BOUNDS;
SendMessage(itemHwnd, LVM_GETITEMRECT, sel, (LPARAM)&wrect);
point.x = wrect.left + (wrect.right - wrect.left) / 2;
point.y = wrect.top + (wrect.bottom - wrect.top) / 2;
ClientToScreen(itemHwnd, &point);
}
TrackPopupMenu(hCheatcontextsub, TPM_RIGHTBUTTON, point.x, point.y, 0, hwndDlg, 0); //Create menu
}
}
break;
case WM_COMMAND:
{
static int editMode = -1;
switch (HIWORD(wParam))
{
case BN_CLICKED:
switch (LOWORD(wParam))
{
case CHEAT_CONTEXT_LIST_TOGGLECHEAT:
{
LVITEM lvi;
lvi.mask = LVIF_STATE;
lvi.stateMask = LVIS_STATEIMAGEMASK;
int tmpsel = SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_GETNEXTITEM, -1, LVNI_ALL | LVNI_SELECTED);
char* name = ""; int s;
while (tmpsel != -1)
{
FCEUI_GetCheat(tmpsel, &name, NULL, NULL, NULL, &s, NULL);
FCEUI_SetCheat(tmpsel, name, -1, -1, -2, s ^= 1, 1);
lvi.iItem = tmpsel;
lvi.state = INDEXTOSTATEIMAGEMASK(s ? 2 : 1);
SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_SETITEMSTATE, tmpsel, (LPARAM)&lvi);
tmpsel = SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_GETNEXTITEM, tmpsel, LVNI_ALL | LVNI_SELECTED);
}
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
break;
case CHEAT_CONTEXT_LIST_POKECHEATVALUE:
{
uint32 a; uint8 v;
FCEUI_GetCheat(selcheat, NULL, &a, &v, NULL, NULL, NULL);
BWrite[a](a, v);
}
break;
case CHEAT_CONTEXT_LIST_GOTOINHEXEDITOR:
{
uint32 a;
FCEUI_GetCheat(selcheat, NULL, &a, NULL, NULL, NULL, NULL);
DoMemView();
SetHexEditorAddress(a);
}
break;
case CHEAT_CONTEXT_POSSI_ADDCHEAT:
{
char str[256] = { 0 };
int sel = SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_GETSELECTIONMARK, 0, 0);
if (sel != -1)
{
char str[256] = { 0 };
GetDlgItemText(hwndDlg, IDC_CHEAT_NAME, str, 256);
SEARCHPOSSIBLE& possible = possiList[sel];
if (FCEUI_AddCheat(str, possible.addr, possible.current, -1, 1))
{
RedoCheatsCallB(str, possible.addr, possible.current, -1, 1, 1, NULL);
int newselcheat = SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_GETITEMCOUNT, 0, 0) - 1;
ListView_MoveSelectionMark(GetDlgItem(hwndDlg, IDC_LIST_CHEATS), selcheat, newselcheat);
selcheat = newselcheat;
}
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
}
break;
case CHEAT_CONTEXT_POSSI_ADDTOMEMORYWATCH:
{
char addr[16] = { 0 };
int sel = SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_GETSELECTIONMARK, 0, 0);
if (sel != -1)
{
sprintf(addr, "%04X", possiList[sel].addr);
AddMemWatch(addr);
}
}
break;
case CHEAT_CONTEXT_POSSI_ADDTORAMWATCH:
{
int sel = SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_GETSELECTIONMARK, 0, 0);
if (sel != -1)
{
AddressWatcher tempWatch;
tempWatch.Size = 'b';
tempWatch.Type = 'h';
tempWatch.Address = possiList[sel].addr;
tempWatch.WrongEndian = false;
if (InsertWatch(tempWatch, hwndDlg) && !RamWatchHWnd)
SendMessage(hAppWnd, WM_COMMAND, ID_RAM_WATCH, 0);
SetForegroundWindow(RamWatchHWnd);
}
}
break;
case CHEAT_CONTEXT_POSSI_GOTOINHEXEDITOR:
{
int sel = SendDlgItemMessage(hwndDlg, IDC_CHEAT_LIST_POSSIBILITIES, LVM_GETSELECTIONMARK, 0, 0);
if (sel != -1)
{
DoMemView();
SetHexEditorAddress(possiList[sel].addr);
}
}
break;
case IDC_CHEAT_PAUSEWHENACTIVE:
pauseWhileActive ^= 1;
if ((EmulationPaused == 1 ? true : false) != pauseWhileActive)
{
EmulationPaused = (pauseWhileActive ? 1 : 0);
wasPausedByCheats = pauseWhileActive;
if (EmulationPaused)
FCEU_printf("Emulation paused: %d\n", EmulationPaused);
}
break;
case IDC_BTN_CHEAT_ADD:
{
char name[256] = { 0 }; uint32 a; uint8 v = 0; int c = 0;
GetUICheatInfo(hwndDlg, name, &a, &v, &c);
if (FCEUI_AddCheat(name, a, v, c, 1)) {
RedoCheatsCallB(name, a, v, c, 1, 1, NULL);
int newselcheat = SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_GETITEMCOUNT, 0, 0) - 1;
ListView_MoveSelectionMark(GetDlgItem(hwndDlg, IDC_LIST_CHEATS), selcheat, newselcheat);
selcheat = newselcheat;
ClearCheatListText(hwndDlg);
}
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
break;
}
case CHEAT_CONTEXT_LIST_DELETESELECTEDCHEATS:
case IDC_BTN_CHEAT_DEL:
if (selcheatcount > 1)
{
if (IDYES == MessageBox(hwndDlg, "Multiple cheats selected. Continue with delete?", "Delete multiple cheats?", MB_ICONQUESTION | MB_YESNO)) { //Get message box
selcheat = -1;
int selcheattemp = SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_GETNEXTITEM, -1, LVNI_ALL | LVNI_SELECTED);
LVITEM lvi;
lvi.mask = LVIF_STATE;
lvi.stateMask = LVIS_SELECTED;
lvi.state = 0;
while (selcheattemp != -1)
{
FCEUI_DelCheat(selcheattemp);
SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_DELETEITEM, selcheattemp, 0);
selcheattemp = SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_GETNEXTITEM, -1, LVNI_ALL | LVNI_SELECTED);
}
ClearCheatListText(hwndDlg);
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
}
else {
if (selcheat >= 0) {
FCEUI_DelCheat(selcheat);
SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_DELETEITEM, selcheat, 0);
selcheat = -1;
ClearCheatListText(hwndDlg);
}
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
break;
case IDC_BTN_CHEAT_UPD:
{
selcheat = SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_GETSELECTIONMARK, 0, 0);
if (selcheat < 0)
break;
char name[256]; uint32 a; uint8 v; int s; int c;
GetUICheatInfo(hwndDlg, name, &a, &v, &c);
FCEUI_SetCheat(selcheat, name, a, v, c, -1, 1);
FCEUI_GetCheat(selcheat, NULL, &a, &v, &c, &s, NULL);
RedoCheatsCallB(name, a, v, c, s, 1, &selcheat);
SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_SETSELECTIONMARK, 0, selcheat);
SetDlgItemText(hwndDlg, IDC_CHEAT_ADDR, (LPCSTR)U16ToStr(a));
SetDlgItemText(hwndDlg, IDC_CHEAT_VAL, (LPCSTR)U8ToStr(v));
if (c == -1)
SetDlgItemText(hwndDlg, IDC_CHEAT_COM, (LPCSTR)"");
else
SetDlgItemText(hwndDlg, IDC_CHEAT_COM, (LPCSTR)U8ToStr(c));
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
// UpdateCheatAdded();
break;
}
case IDC_BTN_CHEAT_ADDFROMFILE:
{
char filename[2048];
if (ShowCheatFileBox(hwndDlg, filename, false))
{
FILE* file = FCEUD_UTF8fopen(filename, "rb");
if (file)
{
FCEU_LoadGameCheats(file, 0);
UpdateCheatsAdded();
UpdateCheatRelatedWindow();
savecheats = 1;
}
}
}
break;
case IDC_BTN_CHEAT_EXPORTTOFILE:
SaveCheatAs(hwndDlg);
break;
case IDC_BTN_CHEAT_RESET:
FCEUI_CheatSearchBegin();
ShowResults(hwndDlg);
EnableCheatButtons(hwndDlg, TRUE);
break;
case IDC_BTN_CHEAT_KNOWN:
{
char str[256] = { 0 };
searchdone = 1;
GetDlgItemText(hwndDlg, IDC_CHEAT_VAL_KNOWN, str, 3);
knownvalue = StrToU8(str);
FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_KNOWN, knownvalue, 0);
ShowResults(hwndDlg);
}
break;
case IDC_BTN_CHEAT_EQ:
searchdone = 1;
FCEUI_CheatSearchEnd(FCEU_SEARCH_PUERLY_RELATIVE_CHANGE, 0, 0);
ShowResults(hwndDlg);
break;
case IDC_BTN_CHEAT_NE:
{
char str[256] = { 0 };
searchdone = 1;
if (IsDlgButtonChecked(hwndDlg, IDC_CHEAT_CHECK_NE_BY) == BST_CHECKED) {
GetDlgItemText(hwndDlg, IDC_CHEAT_VAL_NE_BY, str, 3);
FCEUI_CheatSearchEnd(FCEU_SEARCH_PUERLY_RELATIVE_CHANGE, 0, StrToU8(str));
}
else FCEUI_CheatSearchEnd(FCEU_SEARCH_ANY_CHANGE, 0, 0);
ShowResults(hwndDlg);
}
break;
case IDC_BTN_CHEAT_GT:
{
char str[256] = { 0 };
searchdone = 1;
if (IsDlgButtonChecked(hwndDlg, IDC_CHEAT_CHECK_GT_BY) == BST_CHECKED) {
GetDlgItemText(hwndDlg, IDC_CHEAT_VAL_GT_BY, str, 3);
FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_GT_KNOWN, 0, StrToU8(str));
}
else FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_GT, 0, 0);
ShowResults(hwndDlg);
}
break;
case IDC_BTN_CHEAT_LT:
{
char str[256] = { 0 };
searchdone = 1;
if (IsDlgButtonChecked(hwndDlg, IDC_CHEAT_CHECK_LT_BY) == BST_CHECKED) {
GetDlgItemText(hwndDlg, IDC_CHEAT_VAL_LT_BY, str, 3);
FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_LT_KNOWN, 0, StrToU8(str));
}
else FCEUI_CheatSearchEnd(FCEU_SEARCH_NEWVAL_LT, 0, 0);
ShowResults(hwndDlg);
}
break;
case IDC_CHEAT_GLOBAL_SWITCH:
if (FCEUI_GlobalToggleCheat(IsDlgButtonChecked(hwndDlg, IDC_CHEAT_GLOBAL_SWITCH)))
{
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
break;
case IDC_CHEAT_AUTOLOADSAVE:
{
switch (IsDlgButtonChecked(hwndDlg, IDC_CHEAT_AUTOLOADSAVE))
{
case BST_CHECKED: disableAutoLSCheats = 0; break;
case BST_INDETERMINATE: disableAutoLSCheats = 1; break;
case BST_UNCHECKED:
if(MessageBox(hwndDlg, "If this option is unchecked, you must manually save the cheats by yourself, or all the changes you made to the cheat list would be discarded silently without any asking once you close the game!\nDo you really want to do it in this way?", "Cheat warning", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDYES)
disableAutoLSCheats = 2;
else
{
disableAutoLSCheats = 0;
CheckDlgButton(hwndDlg, IDC_CHEAT_AUTOLOADSAVE, BST_CHECKED);
}
}
SetCheatToolTip(hwndDlg, IDC_CHEAT_AUTOLOADSAVE);
}
}
break;
case EN_SETFOCUS:
switch (LOWORD(wParam))
{
case IDC_CHEAT_ADDR:
case IDC_CHEAT_VAL:
case IDC_CHEAT_COM: editMode = 0; break;
case IDC_CHEAT_TEXT: editMode = 1; break;
case IDC_CHEAT_GAME_GENIE_TEXT: editMode = 2; break;
default: editMode = -1;
}
break;
case EN_KILLFOCUS:
switch (LOWORD(wParam))
{
case IDC_CHEAT_ADDR:
case IDC_CHEAT_VAL:
case IDC_CHEAT_COM:
case IDC_CHEAT_TEXT:
case IDC_CHEAT_GAME_GENIE_TEXT:
default: editMode = -1; break;
}
break;
case EN_UPDATE:
switch (LOWORD(wParam))
{
case IDC_CHEAT_ADDR:
case IDC_CHEAT_VAL:
case IDC_CHEAT_COM:
{
if (editMode == 0)
{
char buf[16]; uint32 a; uint8 v; int c;
GetUICheatInfo(hwndDlg, NULL, &a, &v, &c);
buf[0] = 0;
GetCheatCodeStr(buf, a, v, c);
SetDlgItemText(hwndDlg, IDC_CHEAT_TEXT, buf);
buf[0] = 0;
if (a > 0x7FFF && v != -1)
EncodeGG(buf, a, v, c);
SetDlgItemText(hwndDlg, IDC_CHEAT_GAME_GENIE_TEXT, buf);
}
}
break;
case IDC_CHEAT_TEXT:
{
if (editMode == 1)
{
char buf[16];
GetDlgItemText(hwndDlg, IDC_CHEAT_TEXT, buf, 16);
int a = -1, v = -1, c = -1;
if (strchr(buf, ':'))
{
if (strchr(buf, '?'))
sscanf(buf, "%X:%X?%X", &a, &c, &v);
else
sscanf(buf, "%X:%X", &a, &v);
}
SetDlgItemText(hwndDlg, IDC_CHEAT_ADDR, (LPCSTR)(a == -1 ? "" : U16ToStr(a)));
SetDlgItemText(hwndDlg, IDC_CHEAT_VAL, (LPCSTR)(v == -1 ? "" : U8ToStr(v)));
SetDlgItemText(hwndDlg, IDC_CHEAT_COM, (LPCSTR)(c == -1 ? "" : U8ToStr(c)));
buf[0] = 0;
if (a > 0x7FFF && v != -1)
EncodeGG(buf, a, v, c);
SetDlgItemText(hwndDlg, IDC_CHEAT_GAME_GENIE_TEXT, buf);
}
}
break;
case IDC_CHEAT_GAME_GENIE_TEXT:
{
if (editMode == 2)
{
char buf[16];
GetDlgItemText(hwndDlg, IDC_CHEAT_GAME_GENIE_TEXT, buf, 16);
int a = -1, v = -1, c = -1;
if (strlen(buf) == 6 || strlen(buf) == 8)
FCEUI_DecodeGG(buf, &a, &v, &c);
SetDlgItemText(hwndDlg, IDC_CHEAT_ADDR, (LPCSTR)(a == -1 ? "" : U16ToStr(a)));
SetDlgItemText(hwndDlg, IDC_CHEAT_VAL, (LPCSTR)(v == -1 ? "" : U8ToStr(v)));
SetDlgItemText(hwndDlg, IDC_CHEAT_COM, (LPCSTR)(c == -1 ? "" : U8ToStr(c)));
buf[0] = 0;
if (a != -1 && v != -1)
GetCheatCodeStr(buf, a, v, c);
SetDlgItemText(hwndDlg, IDC_CHEAT_TEXT, buf);
}
}
}
}
}
break;
case WM_NOTIFY:
{
switch (wParam)
{
case IDC_LIST_CHEATS:
{
NMHDR* lP = (NMHDR*)lParam;
switch (lP->code) {
case LVN_ITEMCHANGED:
{
NMLISTVIEW* pNMListView = (NMLISTVIEW*)lP;
// selcheat = pNMListView->iItem;
selcheatcount = SendDlgItemMessage(hwndDlg, IDC_LIST_CHEATS, LVM_GETSELECTEDCOUNT, 0, 0);
if (pNMListView->uNewState & LVIS_FOCUSED ||
!(pNMListView->uOldState & LVIS_SELECTED) && pNMListView->uNewState & LVIS_SELECTED)
{
selcheat = pNMListView->iItem;
if (selcheat >= 0)
{
char* name = ""; uint32 a; uint8 v; int s; int c;
FCEUI_GetCheat(selcheat, &name, &a, &v, &c, &s, NULL);
SetDlgItemText(hwndDlg, IDC_CHEAT_NAME, (LPCSTR)name);
SetDlgItemText(hwndDlg, IDC_CHEAT_ADDR, (LPCSTR)U16ToStr(a));
SetDlgItemText(hwndDlg, IDC_CHEAT_VAL, (LPCSTR)U8ToStr(v));
SetDlgItemText(hwndDlg, IDC_CHEAT_COM, (LPCSTR)(c == -1 ? "" : U8ToStr(c)));
char code[32];
code[0] = 0;
GetCheatCodeStr(code, a, v, c);
SetDlgItemText(hwndDlg, IDC_CHEAT_TEXT, code);
code[0] = 0;
if (a > 0x7FFF && v != -1)
EncodeGG(code, a, v, c);
SetDlgItemText(hwndDlg, IDC_CHEAT_GAME_GENIE_TEXT, code);
}
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_DEL), selcheatcount > 0);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_CHEAT_UPD), selcheatcount > 0);
}
if (pNMListView->uChanged & LVIF_STATE)
// uncheck -> check
if (pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(1) &&
pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(2))
{
int tmpsel = pNMListView->iItem;
char* name = ""; int s;
FCEUI_GetCheat(tmpsel, &name, NULL, NULL, NULL, &s, NULL);
if (!s)
{
FCEUI_SetCheat(tmpsel, name, -1, -1, -2, s ^= 1, 1);
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
}
// check -> uncheck
else if (pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(2) &&
pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(1))
{
int tmpsel = pNMListView->iItem;
char* name = ""; int s;
FCEUI_GetCheat(tmpsel, &name, NULL, NULL, NULL, &s, NULL);
if (s)
{
FCEUI_SetCheat(tmpsel, name, -1, -1, -2, s ^= 1, 1);
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
}
}
}
}
break;
case IDC_CHEAT_LIST_POSSIBILITIES:
{
LPNMHDR lP = (LPNMHDR)lParam;
switch (lP->code)
{
case LVN_ITEMCHANGED:
{
NMLISTVIEW* pNMListView = (NMLISTVIEW*)lP;
if (pNMListView->uNewState & LVIS_FOCUSED ||
!(pNMListView->uOldState & LVIS_SELECTED) && pNMListView->uNewState & LVIS_SELECTED)
{
SEARCHPOSSIBLE& possible = possiList[pNMListView->iItem];
char str[16];
sprintf(str, "%04X", possible.addr);
SetDlgItemText(hwndDlg, IDC_CHEAT_ADDR, (LPCSTR)str);
sprintf(str, "%02X", possible.current);
SetDlgItemText(hwndDlg, IDC_CHEAT_VAL, (LPCSTR)str);
SetDlgItemText(hwndDlg, IDC_CHEAT_COM, (LPCSTR)"");
}
}
break;
case LVN_GETDISPINFO:
{
NMLVDISPINFO* info = (NMLVDISPINFO*)lParam;
if (!possiList.count(info->item.iItem))
ShowResults(hwndDlg, true);
static char num[32];
switch (info->item.iSubItem)
{
case 0:
sprintf(num, "$%04X", possiList[info->item.iItem].addr);
break;
case 1:
sprintf(num, "%02X", possiList[info->item.iItem].previous);
break;
case 2:
sprintf(num, "%02X", possiList[info->item.iItem].current);
break;
}
info->item.pszText = num;
}
break;
case NM_DBLCLK:
{
char addr[16];
sprintf(addr, "%04X", possiList[((NMITEMACTIVATE*)lParam)->iItem].addr);
AddMemWatch(addr);
}
break;
}
}
break;
}
}
}
return 0;
}
void ConfigCheats(HWND hParent)
{
if (!GameInfo)
{
FCEUD_PrintError("You must have a game loaded before you can manipulate cheats.");
return;
}
//if (GameInfo->type==GIT_NSF) {
// FCEUD_PrintError("Sorry, you can't cheat with NSFs.");
// return;
//}
if (!CheatWindow)
{
selcheat = -1;
CheatWindow = 1;
if (CheatStyle)
hCheat = CreateDialog(fceu_hInstance, "CHEATCONSOLE", hParent, CheatConsoleCallB);
else
DialogBox(fceu_hInstance, "CHEATCONSOLE", hParent, CheatConsoleCallB);
UpdateCheatsAdded();
UpdateCheatRelatedWindow();
} else
{
ShowWindow(hCheat, SW_SHOWNORMAL);
SetForegroundWindow(hCheat);
}
}
void UpdateCheatList()
{
if (!hCheat)
return;
else
ShowResults(hCheat);
}
void UpdateCheatListGroupBoxUI()
{
char temp[64];
if (FrozenAddressCount < 256)
{
sprintf(temp, "Active Cheats %d", FrozenAddressCount);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_ADD), TRUE);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_ADDFROMFILE), TRUE);
}
else if (FrozenAddressCount == 256)
{
sprintf(temp, "Active Cheats %d (Max Limit)", FrozenAddressCount);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_ADD), FALSE);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_ADDFROMFILE), FALSE);
}
else
{
sprintf(temp, "%d Error: Too many cheats loaded!", FrozenAddressCount);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_ADD), FALSE);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_ADDFROMFILE), FALSE);
}
SetDlgItemText(hCheat, IDC_GROUPBOX_CHEATLIST, temp);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_EXPORTTOFILE), cheats != 0);
}
//Used by cheats and external dialogs such as hex editor to update items in the cheat search dialog
void UpdateCheatsAdded()
{
RedoCheatsLB(hCheat);
UpdateCheatListGroupBoxUI();
}
INT_PTR CALLBACK GGConvCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg) {
case WM_MOVE: {
if (!IsIconic(hwndDlg)) {
RECT wrect;
GetWindowRect(hwndDlg,&wrect);
GGConv_wndx = wrect.left;
GGConv_wndy = wrect.top;
#ifdef WIN32
WindowBoundsCheckNoResize(GGConv_wndx,GGConv_wndy,wrect.right);
#endif
}
break;
};
case WM_INITDIALOG:
{
POINT pt;
if (GGConv_wndx != 0 && GGConv_wndy != 0)
{
pt.x = GGConv_wndx;
pt.y = GGConv_wndy;
pt = CalcSubWindowPos(hwndDlg, &pt);
}
else
pt = CalcSubWindowPos(hwndDlg, NULL);
GGConv_wndx = pt.x;
GGConv_wndy = pt.y;
// text limits;
SendDlgItemMessage(hwndDlg, IDC_GAME_GENIE_CODE, EM_SETLIMITTEXT, 8, 0);
SendDlgItemMessage(hwndDlg, IDC_GAME_GENIE_ADDR, EM_SETLIMITTEXT, 4, 0);
SendDlgItemMessage(hwndDlg, IDC_GAME_GENIE_COMP, EM_SETLIMITTEXT, 2, 0);
SendDlgItemMessage(hwndDlg, IDC_GAME_GENIE_VAL, EM_SETLIMITTEXT, 2, 0);
// setup font
SetupCheatFont(hwndDlg);
SendDlgItemMessage(hwndDlg, IDC_GAME_GENIE_ADDR, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_GAME_GENIE_COMP, WM_SETFONT, (WPARAM)hNewFont, FALSE);
SendDlgItemMessage(hwndDlg, IDC_GAME_GENIE_VAL, WM_SETFONT, (WPARAM)hNewFont, FALSE);
// limit their characters
DefaultEditCtrlProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_GAME_GENIE_CODE), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_GAME_GENIE_ADDR), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_GAME_GENIE_COMP), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_GAME_GENIE_VAL), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc);
}
break;
case WM_CLOSE:
case WM_QUIT:
DestroyWindow(hGGConv);
break;
case WM_DESTROY:
hGGConv = NULL;
DeleteCheatFont();
case WM_COMMAND:
switch(HIWORD(wParam)) {
case EN_UPDATE:
if(dontupdateGG)break;
dontupdateGG = 1;
switch(LOWORD(wParam))
{
//lets find out what edit control got changed
case IDC_GAME_GENIE_CODE: //The Game Genie Code - in this case decode it.
{
char buf[9];
GetDlgItemText(hGGConv, IDC_GAME_GENIE_CODE, buf, 9);
int a = -1, v = -1, c = -1;
if (strlen(buf) == 6 || strlen(buf) == 8)
FCEUI_DecodeGG(buf, &a, &v, &c);
SetDlgItemText(hwndDlg, IDC_GAME_GENIE_ADDR, a == -1 ? "" : U16ToStr(a));
SetDlgItemText(hwndDlg, IDC_GAME_GENIE_COMP, c == -1 ? "" : U8ToStr(c));
SetDlgItemText(hwndDlg, IDC_GAME_GENIE_VAL, v == -1 ? "" : U8ToStr(v));
}
break;
case IDC_GAME_GENIE_ADDR:
case IDC_GAME_GENIE_COMP:
case IDC_GAME_GENIE_VAL:
uint32 a = -1; uint8 v = -1; int c = -1;
GetUIGGInfo(hwndDlg, &a, &v, &c);
char buf[9] = { 0 };
if (a > 0x7FFF && v != -1)
EncodeGG(buf, a, v, c);
SetDlgItemText(hwndDlg, IDC_GAME_GENIE_CODE, buf);
//ListGGAddresses();
break;
}
ListGGAddresses(hwndDlg);
dontupdateGG = 0;
break;
case BN_CLICKED:
switch (LOWORD(wParam)) {
case IDC_BTN_ADD_TO_CHEATS:
//ConfigCheats(fceu_hInstance);
char buf[9];
uint32 a = -1; uint8 v = -1; int c = -1;
GetUIGGInfo(hwndDlg, &a, &v, &c);
GetDlgItemText(hwndDlg, IDC_GAME_GENIE_CODE, buf, 9);
if(a < 0x8000) a += 0x8000;
if (FCEUI_AddCheat(buf, a, v, c, 1) && hCheat) {
RedoCheatsCallB(buf, a, v, c, 1, 1, NULL);
int newselcheat = SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_GETITEMCOUNT, 0, 0) - 1;
ListView_MoveSelectionMark(GetDlgItem(hCheat, IDC_LIST_CHEATS), selcheat, newselcheat);
selcheat = newselcheat;
SetDlgItemText(hCheat, IDC_CHEAT_ADDR, (LPCSTR)U16ToStr(a));
SetDlgItemText(hCheat, IDC_CHEAT_VAL, (LPCSTR)U8ToStr(v));
SetDlgItemText(hCheat, IDC_CHEAT_COM, (LPCSTR)(c == -1 ? "" : U8ToStr(c)));
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_DEL), TRUE);
EnableWindow(GetDlgItem(hCheat, IDC_BTN_CHEAT_UPD), TRUE);
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
}
}
break;
case LBN_DBLCLK:
switch (LOWORD(wParam)) {
case IDC_LIST_GGADDRESSES:
ChangeMemViewFocus(3,GGlist[SendDlgItemMessage(hwndDlg, IDC_LIST_GGADDRESSES, LB_GETCURSEL, 0, 0)],-1);
break;
}
break;
}
break;
}
return FALSE;
}
//The code in this function is a modified version
//of Chris Covell's work - I'd just like to point that out
void EncodeGG(char *str, int a, int v, int c)
{
uint8 num[8];
int i;
a&=0x7fff;
num[0]=(v&7)+((v>>4)&8);
num[1]=((v>>4)&7)+((a>>4)&8);
num[2]=((a>>4)&7);
num[3]=(a>>12)+(a&8);
num[4]=(a&7)+((a>>8)&8);
num[5]=((a>>8)&7);
if (c == -1){
num[5]+=v&8;
for(i = 0;i < 6;i++)str[i] = GameGenieLetters[num[i]];
str[6] = 0;
} else {
num[2]+=8;
num[5]+=c&8;
num[6]=(c&7)+((c>>4)&8);
num[7]=((c>>4)&7)+(v&8);
for(i = 0;i < 8;i++)str[i] = GameGenieLetters[num[i]];
str[8] = 0;
}
return;
}
void ListGGAddresses(HWND hwndDlg)
{
uint32 i, j = 0; //mbg merge 7/18/06 changed from int
char str[20], code[9];
SendDlgItemMessage(hwndDlg, IDC_LIST_GGADDRESSES, LB_RESETCONTENT,0,0);
uint32 a = -1; uint8 v = -1; int c = -1;
GetUIGGInfo(hwndDlg, &a, &v, &c);
// also enable/disable the add GG button here
GetDlgItemText(hwndDlg, IDC_GAME_GENIE_CODE, code, 9);
EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_ADD_TO_CHEATS), a >= 0 && (strlen(code) == 6 || strlen(code) == 8));
if (a != -1 && v != -1)
for(i = 0; i < PRGsize[0]; i += 0x2000)
if(c == -1 || PRGptr[0][i + (a & 0x1FFF)] == c){
GGlist[j] = i + (a & 0x1FFF) + 0x10;
if(++j > GGLISTSIZE)
return;
sprintf(str, "%06X", i + (a & 0x1FFF) + 0x10);
SendDlgItemMessage(hwndDlg, IDC_LIST_GGADDRESSES, LB_ADDSTRING, 0, (LPARAM)str);
}
}
//A different model for this could be to have everything
//set in the INITDIALOG message based on the internal
//variables, and have this simply call that.
void SetGGConvFocus(int address, int compare)
{
char str[10];
if(!hGGConv)
DoGGConv();
// GGaddr = address;
// GGcomp = compare;
dontupdateGG = 1; //little hack to fix a nasty bug
sprintf(str, "%04X", address);
SetDlgItemText(hGGConv, IDC_GAME_GENIE_ADDR, str);
dontupdateGG = 0;
sprintf(str, "%02X", compare);
SetDlgItemText(hGGConv, IDC_GAME_GENIE_COMP, str);
GetDlgItemText(hGGConv, IDC_GAME_GENIE_VAL, str, 3);
uint8 val = StrToU8(str);
if(val < 0)
SetDlgItemText(hGGConv, IDC_GAME_GENIE_CODE, "");
else {
str[0] = 0;
if (val > 0x7FFF)
EncodeGG(str, address, val, compare);
SetDlgItemText(hGGConv, IDC_GAME_GENIE_CODE, str);
}
SetFocus(GetDlgItem(hGGConv, IDC_GAME_GENIE_VAL));
return;
}
void DoGGConv()
{
if (hGGConv)
{
ShowWindow(hGGConv, SW_SHOWNORMAL);
SetForegroundWindow(hGGConv);
} else
hGGConv = CreateDialog(fceu_hInstance,"GGCONV", hAppWnd, GGConvCallB);
}
inline void GetCheatStr(char* buf, int a, int v, int c)
{
if (a > 0x7FFF)
EncodeGG(buf, a, v, c);
else {
GetCheatCodeStr(buf, a, v, c);
}
}
inline void GetCheatCodeStr(char* buf, int a, int v, int c)
{
if (c == -1)
sprintf(buf, "%04X:%02X", a, v);
else
sprintf(buf, "%04X?%02X:%02X", a, c, v);
}
static void SetCheatToolTip(HWND hwndDlg, UINT id)
{
TOOLINFO info;
memset(&info, 0, sizeof(TOOLINFO));
info.cbSize = sizeof(TOOLINFO);
info.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
info.hwnd = hwndDlg;
info.lpszText = GetCheatToolTipStr(hwndDlg, id);
info.uId = (UINT_PTR)GetDlgItem(hwndDlg, id);
if (hCheatTip)
SendMessage(hCheatTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&info);
else
{
if (hCheatTip = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL, fceu_hInstance, NULL)) {
SendMessage(hCheatTip, TTM_ADDTOOL, 0, (LPARAM)&info);
SendMessage(hCheatTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, 30000);
SendMessage(hCheatTip, TTM_SETMAXTIPWIDTH, 0, 8000);
}
}
}
char* GetCheatToolTipStr(HWND hwndDlg, UINT id)
{
switch (id)
{
case IDC_CHEAT_AUTOLOADSAVE:
switch (disableAutoLSCheats)
{
case 0: return "Automatically load/save cheat file along with the game.";
case 1: return
"Don't add cheat on game load, but prompt for saving on game closes.\r\n"
"You must manually import cht file when it's needed.";
case 2: return
"Don't add cheat on game load, and don't save cheat on game closes.\r\n"
"You must manually import/export cht file by yourself,\nor all your changes to cheat will be lost!";
default:
return "Mysterious undocumented state.";
}
}
return NULL;
}
void GetUICheatInfo(HWND hwndDlg, char* name, uint32* a, uint8* v, int* c)
{
char buf[16];
GetDlgItemText(hwndDlg, IDC_CHEAT_ADDR, buf, 5);
*a = StrToU16(buf);
GetDlgItemText(hwndDlg, IDC_CHEAT_VAL, buf, 3);
*v = StrToU8(buf);
GetDlgItemText(hwndDlg, IDC_CHEAT_COM, buf, 3);
*c = (buf[0] == 0) ? -1 : StrToU8(buf);
if (name)
GetDlgItemText(hwndDlg, IDC_CHEAT_NAME, name, 256);
}
void GetUIGGInfo(HWND hwndDlg, uint32* a, uint8* v, int* c)
{
char buf[16];
GetDlgItemText(hwndDlg, IDC_GAME_GENIE_ADDR, buf, 5);
*a = StrToU16(buf);
GetDlgItemText(hwndDlg, IDC_GAME_GENIE_VAL, buf, 3);
*v = StrToU8(buf);
GetDlgItemText(hwndDlg, IDC_GAME_GENIE_COMP, buf, 3);
*c = (buf[0] == 0 ? -1 : StrToU8(buf));
}
void DisableAllCheats()
{
if(FCEU_DisableAllCheats() && hCheat){
LVITEM lvi;
lvi.mask = LVIF_STATE;
lvi.stateMask = LVIS_STATEIMAGEMASK;
lvi.state = INDEXTOSTATEIMAGEMASK(1);
for (int current = SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LB_GETCOUNT, 0, 0) - 1; current >= 0; --current)
SendDlgItemMessage(hCheat, IDC_LIST_CHEATS, LVM_GETITEMSTATE, current, (LPARAM)&lvi);
UpdateCheatListGroupBoxUI();
}
}
void UpdateCheatRelatedWindow()
{
// hex editor
if (hMemView)
UpdateColorTable(); //if the memory viewer is open then update any blue freeze locations in it as well
// ram search
extern HWND RamSearchHWnd;
if (RamSearchHWnd)
// if ram search is open then update the ram list.
SendDlgItemMessage(RamSearchHWnd, IDC_RAMLIST, LVM_REDRAWITEMS,
SendDlgItemMessage(RamSearchHWnd, IDC_RAMLIST, LVM_GETTOPINDEX, 0, 0),
SendDlgItemMessage(RamSearchHWnd, IDC_RAMLIST, LVM_GETTOPINDEX, 0, 0) +
SendDlgItemMessage(RamSearchHWnd, IDC_RAMLIST, LVM_GETCOUNTPERPAGE, 0, 0) + 1);
// ram watch
extern void UpdateWatchCheats();
UpdateWatchCheats();
extern HWND RamWatchHWnd;
if (RamWatchHWnd)
// if ram watch is open then update the ram list.
SendDlgItemMessage(RamWatchHWnd, IDC_WATCHLIST, LVM_REDRAWITEMS,
SendDlgItemMessage(RamWatchHWnd, IDC_WATCHLIST, LVM_GETTOPINDEX, 0, 0),
SendDlgItemMessage(RamSearchHWnd, IDC_RAMLIST, LVM_GETTOPINDEX, 0, 0) +
SendDlgItemMessage(RamWatchHWnd, IDC_WATCHLIST, LVM_GETCOUNTPERPAGE, 0, 0) + 1);
}
bool ShowCheatFileBox(HWND hwnd, char* buf, bool save)
{
if (!buf)
return false;
char filename[2048] = { 0 };
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hInstance = fceu_hInstance;
ofn.hwndOwner = hwnd;
ofn.lpstrTitle = save ? "Save cheats file" : "Open cheats file";
ofn.lpstrFilter = "Cheat files (*.cht)\0*.cht\0All Files (*.*)\0*.*\0\0";
// I gave up setting the default filename for import cheat dialog, since the filename display contains a bug.
if (save)
{
if (GameInfo)
{
char* _filename;
if ((_filename = strrchr(GameInfo->filename, '\\')) || (_filename = strrchr(GameInfo->filename, '/')))
strcpy(filename, _filename + 1);
else
strcpy(filename, GameInfo->filename);
_filename = strrchr(filename, '.');
if (_filename)
strcpy(_filename, ".cht");
else
strcat(filename, ".cht");
}
}
ofn.lpstrFile = filename;
ofn.nMaxFile = sizeof(filename);
ofn.lpstrDefExt = "cht";
ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST;
ofn.lpstrInitialDir = FCEU_GetPath(FCEUMKF_CHEAT).c_str();
if (save ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn))
{
strcpy(buf, filename);
return true;
}
return false;
}
void AskSaveCheat()
{
if (cheats)
{
HWND hwnd = hCheat ? hCheat : hAppWnd;
if (MessageBox(hwnd, "Save cheats?", "Cheat Console", MB_YESNO | MB_ICONASTERISK) == IDYES)
SaveCheatAs(hwnd, true);
}
}
void SaveCheatAs(HWND hwnd, bool flush)
{
if (cheats)
{
char filename[2048];
if (ShowCheatFileBox(hwnd, filename, true))
{
FILE* file = FCEUD_UTF8fopen(filename, "wb");
if (file)
{
if (flush)
{
savecheats = 1;
FCEU_FlushGameCheats(file, 0);
}
else
FCEU_SaveGameCheats(file);
fclose(file);
}
else
MessageBox(hwnd, "Error saving cheats!", "Cheat Console", MB_OK | MB_ICONERROR);
}
}
}
void SetupCheatFont(HWND hwnd)
{
if (!hCheat && !hGGConv)
{
hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
LOGFONT lf;
GetObject(hFont, sizeof(LOGFONT), &lf);
strcpy(lf.lfFaceName, "Courier New");
hNewFont = CreateFontIndirect(&lf);
}
}
void DeleteCheatFont()
{
if (!hCheat && !hGGConv)
{
DeleteObject(hFont);
DeleteObject(hNewFont);
hFont = NULL;
hNewFont = NULL;
}
}
void CreateCheatMap()
{
if (!CheatMapUsers)
FCEUI_CreateCheatMap();
++CheatMapUsers;
}
void ReleaseCheatMap()
{
--CheatMapUsers;
// printf("CheatMapUsers: %d\n", CheatMapUsers);
if (!CheatMapUsers)
FCEUI_ReleaseCheatMap();
}