1. Trying to find a more efficient way to know which byte has a cheat. Since the cheat map occupies a lot of memory, I decided to make it only exists when necessary.

2. Reorganized some codes.
This commit is contained in:
owomomo 2020-02-01 16:51:33 +08:00
parent c3d0d40aa6
commit a9c4bc9592
8 changed files with 219 additions and 147 deletions

View File

@ -63,7 +63,7 @@ CHEATF_SUBFAST SubCheats[256] = { 0 };
uint32 numsubcheats = 0; uint32 numsubcheats = 0;
int globalCheatDisabled = 0; int globalCheatDisabled = 0;
int disableAutoLSCheats = 0; int disableAutoLSCheats = 0;
static unsigned char cheatMap[0x10000 / 8] = { 0 }; static _8BYTECHEATMAP* cheatMap = NULL;
struct CHEATF *cheats = 0, *cheatsl = 0; struct CHEATF *cheats = 0, *cheatsl = 0;
@ -105,7 +105,8 @@ void RebuildSubCheats(void)
for (x = 0; x < numsubcheats; x++) for (x = 0; x < numsubcheats; x++)
{ {
SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead); SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead);
SetByteCheat(SubCheats[x].addr, false); if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[x].addr, false);
} }
numsubcheats = 0; numsubcheats = 0;
@ -121,7 +122,8 @@ void RebuildSubCheats(void)
SubCheats[numsubcheats].val = c->val; SubCheats[numsubcheats].val = c->val;
SubCheats[numsubcheats].compare = c->compare; SubCheats[numsubcheats].compare = c->compare;
SetReadHandler(c->addr, c->addr, SubCheatsRead); SetReadHandler(c->addr, c->addr, SubCheatsRead);
SetByteCheat(SubCheats[numsubcheats].addr, true); if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[numsubcheats].addr, true);
numsubcheats++; numsubcheats++;
} }
c = c->next; c = c->next;
@ -134,15 +136,17 @@ void RebuildSubCheats(void)
void FCEU_PowerCheats() void FCEU_PowerCheats()
{ {
numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */ numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */
memset(cheatMap, 0, sizeof(cheatMap)); if (cheatMap)
FCEUI_RefreshCheatMap();
RebuildSubCheats(); RebuildSubCheats();
} }
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size) { int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size) {
uint32 count = 0; uint32 count = 0;
if (cheatMap)
for (uint32 i = 0; i < size; ++i) for (uint32 i = 0; i < size; ++i)
if (IsByteCheat(address + i)) if (FCEUI_FindCheatMapByte(address + i))
++count; ++count;
return count; return count;
} }
@ -205,7 +209,8 @@ void FCEU_LoadGameCheats(FILE *override, int override_existing)
if (override_existing) if (override_existing)
{ {
numsubcheats = 0; numsubcheats = 0;
memset(cheatMap, 0, sizeof(cheatMap)); if (cheatMap)
FCEUI_RefreshCheatMap();
} }
if(override) if(override)
@ -896,13 +901,35 @@ int FCEU_DisableAllCheats(){
return count; return count;
} }
int IsByteCheat(uint8 address) inline int FCEUI_FindCheatMapByte(uint16 address)
{ {
return cheatMap[address / 8] >> (address % 8) & 1; return cheatMap[address / 8] >> (address % 8) & 1;
} }
void SetByteCheat(uint8 address, bool cheat) inline void FCEUI_SetCheatMapByte(uint16 address, bool cheat)
{ {
cheat ? cheatMap[address / 8] |= (1 << address % 8) : cheatMap[address / 8] ^= (1 << address % 8); cheat ? cheatMap[address / 8] |= (1 << address % 8) : cheatMap[address / 8] ^= (1 << address % 8);
} }
inline void FCEUI_CreateCheatMap()
{
if (!cheatMap)
cheatMap = (unsigned char*)malloc(CHEATMAP_SIZE);
FCEUI_RefreshCheatMap();
}
inline void FCEUI_RefreshCheatMap()
{
memset(cheatMap, 0, CHEATMAP_SIZE);
for (int i = 0; i < numsubcheats; ++i)
FCEUI_SetCheatMapByte(SubCheats[i].addr, true);
}
inline void FCEUI_ReleaseCheatMap()
{
if (cheatMap)
{
free(cheatMap);
cheatMap = NULL;
}
}

View File

@ -11,6 +11,17 @@ void FCEU_ApplyPeriodicCheats(void);
void FCEU_PowerCheats(void); void FCEU_PowerCheats(void);
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size); int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size);
// Trying to find a more efficient way for determining if an address has a cheat
// each bit of 1 byte represents to 8 bytes in NES
typedef unsigned char _8BYTECHEATMAP;
#define CHEATMAP_SIZE 0x10000 / 8
extern int FCEUI_FindCheatMapByte(uint16 address);
extern void FCEUI_SetCheatMapByte(uint16 address, bool cheat);
extern void FCEUI_CreateCheatMap();
extern void FCEUI_RefreshCheatMap();
extern void FCEUI_ReleaseCheatMap();
int FCEU_CheatGetByte(uint32 A); int FCEU_CheatGetByte(uint32 A);
void FCEU_CheatSetByte(uint32 A, uint8 V); void FCEU_CheatSetByte(uint32 A, uint8 V);
@ -44,11 +55,6 @@ struct SEARCHPOSSIBLE {
bool update; bool update;
}; };
// Trying to find a more efficient way for determining if an address has a cheat
// 1 byte represents to 8 bytes in NES,
int IsByteCheat(uint8 address);
void SetByteCheat(uint8 address, bool cheat);
#define FCEU_SEARCH_SPECIFIC_CHANGE 0 #define FCEU_SEARCH_SPECIFIC_CHANGE 0
#define FCEU_SEARCH_RELATIVE_CHANGE 1 #define FCEU_SEARCH_RELATIVE_CHANGE 1
#define FCEU_SEARCH_PUERLY_RELATIVE_CHANGE 2 #define FCEU_SEARCH_PUERLY_RELATIVE_CHANGE 2

View File

@ -41,6 +41,7 @@ extern bool wasPausedByCheats;
int CheatWindow; int CheatWindow;
int CheatStyle = 1; int CheatStyle = 1;
int CheatMapUsers = 0; // how many windows using cheatmap
#define GGLISTSIZE 128 //hopefully this is enough for all cases #define GGLISTSIZE 128 //hopefully this is enough for all cases
@ -1541,3 +1542,19 @@ void DeleteCheatFont()
hNewFont = NULL; hNewFont = NULL;
} }
} }
void CreateCheatMap()
{
if (!CheatMapUsers)
FCEUI_CreateCheatMap();
++CheatMapUsers;
}
void ReleaseCheatMap()
{
--CheatMapUsers;
printf("CheatMapUsers: %d\n", CheatMapUsers);
if (!CheatMapUsers)
FCEUI_ReleaseCheatMap();
}

View File

@ -40,6 +40,10 @@ void SetupCheatFont(HWND hDlg);
void DeleteCheatFont(); void DeleteCheatFont();
extern POINT CalcSubWindowPos(HWND hDlg, POINT* conf); extern POINT CalcSubWindowPos(HWND hDlg, POINT* conf);
void CreateCheatMap();
void ReleaseCheatMap();
extern int CheatMapUsers;
extern INT_PTR CALLBACK GGConvCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); extern INT_PTR CALLBACK GGConvCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
extern LRESULT APIENTRY FilterEditCtrlProc(HWND hDlg, UINT msg, WPARAM wP, LPARAM lP); extern LRESULT APIENTRY FilterEditCtrlProc(HWND hDlg, UINT msg, WPARAM wP, LPARAM lP);
extern WNDPROC DefaultEditCtrlProc; extern WNDPROC DefaultEditCtrlProc;

View File

@ -669,33 +669,26 @@ void UpdateCaption()
int GetMemViewData(uint32 i) int GetMemViewData(uint32 i)
{ {
if (EditingMode == MODE_NES_MEMORY) switch (EditingMode)
return GetMem(i);
if (EditingMode == MODE_NES_PPU)
{ {
case MODE_NES_MEMORY:
return GetMem(i);
case MODE_NES_PPU:
i &= 0x3FFF; i &= 0x3FFF;
if (i < 0x2000)return VPage[(i) >> 10][(i)]; if (i < 0x2000)return VPage[(i) >> 10][(i)];
//NSF PPU Viewer crash here (UGETAB) (Also disabled by 'MaxSize = 0x2000') //NSF PPU Viewer crash here (UGETAB) (Also disabled by 'MaxSize = 0x2000')
if (GameInfo->type == GIT_NSF) if (GameInfo->type == GIT_NSF)
{
return (0); return (0);
}
else else
{ {
if (i < 0x3F00) if (i < 0x3F00)
return vnapage[(i >> 10) & 0x3][i & 0x3FF]; return vnapage[(i >> 10) & 0x3][i & 0x3FF];
return READPAL_MOTHEROFALL(i & 0x1F); return READPAL_MOTHEROFALL(i & 0x1F);
} }
} break;
case MODE_NES_OAM:
if (EditingMode == MODE_NES_OAM)
{
return SPRAM[i & 0xFF]; return SPRAM[i & 0xFF];
} case MODE_NES_FILE:
if (EditingMode == MODE_NES_FILE)
{
//todo: use getfiledata() here //todo: use getfiledata() here
if (i < 16) return *((unsigned char *)&head + i); if (i < 16) return *((unsigned char *)&head + i);
if (i < 16 + PRGsize[0])return PRGptr[0][i - 16]; if (i < 16 + PRGsize[0])return PRGptr[0][i - 16];
@ -729,12 +722,14 @@ void UpdateColorTable()
TextColorList[hexBookmarks[j].address - CurOffset] = RGB(0,0xCC,0); // Green for Bookmarks TextColorList[hexBookmarks[j].address - CurOffset] = RGB(0,0xCC,0); // Green for Bookmarks
} }
//mbg merge 6/29/06 - added argument switch (EditingMode)
if (EditingMode == MODE_NES_MEMORY)
FCEUI_ListCheats(UpdateCheatColorCallB, 0);
if(EditingMode == MODE_NES_FILE)
{ {
case MODE_NES_MEMORY:
for (uint32 a = CurOffset; a < CurOffset + DataAmount; ++a)
if (FCEUI_FindCheatMapByte(a))
TextColorList[a - CurOffset] = RGB(HexFreezeColorR, HexFreezeColorG, HexFreezeColorB);
break;
case MODE_NES_FILE:
if (cdloggerdataSize) if (cdloggerdataSize)
{ {
for (i = 0; i < DataAmount; i++) for (i = 0; i < DataAmount; i++)
@ -749,11 +744,13 @@ void UpdateColorTable()
{ {
// the byte is both Code and Data - green // the byte is both Code and Data - green
TextColorList[i] = RGB(0, 190, 0); TextColorList[i] = RGB(0, 190, 0);
} else if((cdloggerdata[temp_offset] & 3) == 1) }
else if ((cdloggerdata[temp_offset] & 3) == 1)
{ {
// the byte is Code - dark-yellow // the byte is Code - dark-yellow
TextColorList[i] = RGB(160, 140, 0); TextColorList[i] = RGB(160, 140, 0);
} else if((cdloggerdata[temp_offset] & 3) == 2) }
else if ((cdloggerdata[temp_offset] & 3) == 2)
{ {
// the byte is Data - blue/cyan // the byte is Data - blue/cyan
if (cdloggerdata[temp_offset] & 0x40) if (cdloggerdata[temp_offset] & 0x40)
@ -763,7 +760,8 @@ void UpdateColorTable()
// non-PCM data - blue // non-PCM data - blue
TextColorList[i] = RGB(0, 0, 210); TextColorList[i] = RGB(0, 0, 210);
} }
} else }
else
{ {
temp_offset -= cdloggerdataSize; temp_offset -= cdloggerdataSize;
if (((unsigned int)temp_offset < cdloggerVideoDataSize)) if (((unsigned int)temp_offset < cdloggerVideoDataSize))
@ -773,11 +771,13 @@ void UpdateColorTable()
{ {
// the byte was both rendered and read programmatically - light-green // the byte was both rendered and read programmatically - light-green
TextColorList[i] = RGB(5, 255, 5); TextColorList[i] = RGB(5, 255, 5);
} else if ((cdloggervdata[temp_offset] & 3) == 1) }
else if ((cdloggervdata[temp_offset] & 3) == 1)
{ {
// the byte was rendered - yellow // the byte was rendered - yellow
TextColorList[i] = RGB(210, 190, 0); TextColorList[i] = RGB(210, 190, 0);
} else if ((cdloggervdata[temp_offset] & 3) == 2) }
else if ((cdloggervdata[temp_offset] & 3) == 2)
{ {
// the byte was read programmatically - light-blue // the byte was read programmatically - light-blue
TextColorList[i] = RGB(15, 15, 255); TextColorList[i] = RGB(15, 15, 255);
@ -798,20 +798,12 @@ void UpdateColorTable()
} }
tmp = tmp->last; tmp = tmp->last;
} }
break;
} }
UpdateMemoryView(1); //anytime the colors change, the memory viewer needs to be completely redrawn UpdateMemoryView(1); //anytime the colors change, the memory viewer needs to be completely redrawn
} }
//mbg merge 6/29/06 - added argument
int UpdateCheatColorCallB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data) {
if((a >= (uint32)CurOffset) && (a < (uint32)CurOffset+DataAmount)){
if(s)TextColorList[a-CurOffset] = RGB(HexFreezeColorR,HexFreezeColorG,HexFreezeColorB);
}
return 1;
}
int addrtodelete; // This is a very ugly hackish method of doing this int addrtodelete; // This is a very ugly hackish method of doing this
int cheatwasdeleted; // but it works and that is all that matters here. int cheatwasdeleted; // but it works and that is all that matters here.
int DeleteCheatCallB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data){ //mbg merge 6/29/06 - added arg int DeleteCheatCallB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data){ //mbg merge 6/29/06 - added arg
@ -1001,12 +993,13 @@ void InputData(char *input){
if (addr >= MaxSize) continue; if (addr >= MaxSize) continue;
if (EditingMode == MODE_NES_MEMORY) switch(EditingMode)
{ {
case MODE_NES_MEMORY:
// RAM (system bus) // RAM (system bus)
BWrite[addr](addr, data[i]); BWrite[addr](addr, data[i]);
} else if (EditingMode == MODE_NES_PPU) break;
{ case MODE_NES_PPU:
// PPU // PPU
addr &= 0x3FFF; addr &= 0x3FFF;
if (addr < 0x2000) if (addr < 0x2000)
@ -1015,12 +1008,12 @@ void InputData(char *input){
vnapage[(addr >> 10) & 0x3][addr & 0x3FF] = data[i]; //todo: this causes 0x3000-0x3f00 to mirror 0x2000-0x2f00, is this correct? vnapage[(addr >> 10) & 0x3][addr & 0x3FF] = data[i]; //todo: this causes 0x3000-0x3f00 to mirror 0x2000-0x2f00, is this correct?
if ((addr >= 0x3F00) && (addr < 0x3FFF)) if ((addr >= 0x3F00) && (addr < 0x3FFF))
PalettePoke(addr, data[i]); PalettePoke(addr, data[i]);
} else if (EditingMode == MODE_NES_OAM) break;
{ case MODE_NES_OAM:
addr &= 0xFF; addr &= 0xFF;
SPRAM[addr] = data[i]; SPRAM[addr] = data[i];
} else if (EditingMode == MODE_NES_FILE) break;
{ case MODE_NES_FILE:
// ROM // ROM
ApplyPatch(addr, datasize, data); ApplyPatch(addr, datasize, data);
break; break;
@ -1194,6 +1187,8 @@ void KillMemView()
UnregisterClass("MEMVIEW",fceu_hInstance); UnregisterClass("MEMVIEW",fceu_hInstance);
hMemView = 0; hMemView = 0;
hMemFind = 0; hMemFind = 0;
if (EditingMode == MODE_NES_MEMORY)
ReleaseCheatMap();
return; return;
} }
@ -1252,6 +1247,7 @@ LRESULT CALLBACK MemViewCallB(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
resetHighlightingActivityLog(); resetHighlightingActivityLog();
EditingText = CurOffset = 0; EditingText = CurOffset = 0;
EditingMode = MODE_NES_MEMORY; EditingMode = MODE_NES_MEMORY;
CreateCheatMap();
//set the default table //set the default table
UnloadTableFile(); UnloadTableFile();
@ -1685,8 +1681,10 @@ LRESULT CALLBACK MemViewCallB(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
checkCondition(condition, numWPs); checkCondition(condition, numWPs);
numWPs++; numWPs++;
{ extern int myNumWPs; {
myNumWPs++; } extern int myNumWPs;
myNumWPs++;
}
if (hDebug) if (hDebug)
AddBreakList(); AddBreakList();
else else
@ -2034,24 +2032,34 @@ LRESULT CALLBACK MemViewCallB(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
case MENU_MV_VIEW_PPU: case MENU_MV_VIEW_PPU:
case MENU_MV_VIEW_OAM: case MENU_MV_VIEW_OAM:
case MENU_MV_VIEW_ROM: case MENU_MV_VIEW_ROM:
EditingMode = wParam - MENU_MV_VIEW_RAM; {
int _EditingMode = wParam - MENU_MV_VIEW_RAM;
// Leave NES Memory
if (_EditingMode == MODE_NES_MEMORY && EditingMode != MODE_NES_MEMORY)
CreateCheatMap();
// Enter NES Memory
if (_EditingMode != MODE_NES_MEMORY && EditingMode == MODE_NES_MEMORY)
ReleaseCheatMap();
EditingMode = _EditingMode;
for (i = MODE_NES_MEMORY; i <= MODE_NES_FILE; i++) for (i = MODE_NES_MEMORY; i <= MODE_NES_FILE; i++)
if(EditingMode == i) if(EditingMode == i)
{ {
CheckMenuRadioItem(GetMenu(hMemView), MENU_MV_VIEW_RAM, MENU_MV_VIEW_ROM, MENU_MV_VIEW_RAM + i, MF_BYCOMMAND); CheckMenuRadioItem(GetMenu(hMemView), MENU_MV_VIEW_RAM, MENU_MV_VIEW_ROM, MENU_MV_VIEW_RAM + i, MF_BYCOMMAND);
break; break;
} }
if (EditingMode == MODE_NES_MEMORY)
MaxSize = 0x10000; switch (EditingMode)
if (EditingMode == MODE_NES_PPU)
{ {
if (GameInfo->type==GIT_NSF) {MaxSize = 0x2000;} //Also disabled under GetMemViewData case MODE_NES_MEMORY:
else {MaxSize = 0x4000;} MaxSize = 0x10000; break;
case MODE_NES_PPU:
MaxSize = (GameInfo->type == GIT_NSF ? 0x2000 : 0x4000); break;
case MODE_NES_OAM:
MaxSize = 0x100; break;
case MODE_NES_FILE: //todo: add trainer size
MaxSize = 16 + CHRsize[0] + PRGsize[0]; break;
} }
if (EditingMode == MODE_NES_OAM)
MaxSize = 0x100;
if (EditingMode == MODE_NES_FILE)
MaxSize = 16+CHRsize[0]+PRGsize[0]; //todo: add trainer size
if (CurOffset >= MaxSize - DataAmount) CurOffset = MaxSize - DataAmount; if (CurOffset >= MaxSize - DataAmount) CurOffset = MaxSize - DataAmount;
if (CurOffset < 0) CurOffset = 0; if (CurOffset < 0) CurOffset = 0;
if(CursorEndAddy >= MaxSize) CursorEndAddy = -1; if(CursorEndAddy >= MaxSize) CursorEndAddy = -1;
@ -2070,7 +2078,7 @@ LRESULT CALLBACK MemViewCallB(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
UpdateColorTable(); UpdateColorTable();
UpdateCaption(); UpdateCaption();
return 0; return 0;
}
case ID_HIGHLIGHTING_HIGHLIGHT_ACTIVITY: case ID_HIGHLIGHTING_HIGHLIGHT_ACTIVITY:
{ {
MemView_HighlightActivity ^= 1; MemView_HighlightActivity ^= 1;

View File

@ -318,8 +318,8 @@ void UpdateMemWatch()
if (FrozenAddressCount) if (FrozenAddressCount)
for (unsigned int x = 0; x < FrozenAddressCount; x++) for (unsigned int x = 0; x < FrozenAddressCount; x++)
{ {
extern int IsByteCheat(uint8); extern int FCEUI_FindCheatMapByte(uint16);
if (IsByteCheat(mwrec.addr)) if (FCEUI_FindCheatMapByte(mwrec.addr))
SetTextColor(hdc,GetSysColor(COLOR_HIGHLIGHT)); SetTextColor(hdc,GetSysColor(COLOR_HIGHLIGHT));
} }
@ -812,6 +812,8 @@ static INT_PTR CALLBACK MemWatchCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LP
editlast[x]= 0; editlast[x]= 0;
} }
CreateCheatMap();
RamChangeInitialize = true; RamChangeInitialize = true;
break; break;
@ -830,7 +832,9 @@ static INT_PTR CALLBACK MemWatchCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LP
case WM_QUIT: case WM_QUIT:
CloseMemoryWatch(); CloseMemoryWatch();
break; break;
case WM_DESTROY:
ReleaseCheatMap();
break;
case WM_DROPFILES: case WM_DROPFILES:
{ {
unsigned int len; unsigned int len;

View File

@ -1420,6 +1420,8 @@ INT_PTR CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
CalcSubWindowPos(hDlg, NULL); CalcSubWindowPos(hDlg, NULL);
CreateCheatMap();
switch(rs_o) switch(rs_o)
{ {
case '<': case '<':
@ -2105,6 +2107,7 @@ INT_PTR CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
break; break;
case WM_DESTROY: case WM_DESTROY:
RamSearchHWnd = NULL; RamSearchHWnd = NULL;
ReleaseCheatMap();
// theApp.modelessCheatDialogIsOpen = false; // theApp.modelessCheatDialogIsOpen = false;
break; break;
} }

View File

@ -1059,6 +1059,7 @@ INT_PTR CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
rwrecentmenu=CreateMenu(); rwrecentmenu=CreateMenu();
UpdateRW_RMenu(rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE); UpdateRW_RMenu(rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE);
CreateCheatMap();
const char* names[3] = {"Address","Value","Notes"}; const char* names[3] = {"Address","Value","Notes"};
int widths[3] = {78,64,160}; int widths[3] = {78,64,160};
init_list_box(GetDlgItem(hDlg,IDC_WATCHLIST),names,3,widths); init_list_box(GetDlgItem(hDlg,IDC_WATCHLIST),names,3,widths);
@ -1506,6 +1507,8 @@ INT_PTR CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
// release the hdc related objects // release the hdc related objects
SeparatorCache::DeInit(); SeparatorCache::DeInit();
// release cheatmap
ReleaseCheatMap();
break; break;
case WM_DROPFILES: case WM_DROPFILES: