Initial commit - http://sourceforge.net/p/fceumm/code/160/
This commit is contained in:
727
src/cheat.c
Normal file
727
src/cheat.c
Normal file
@@ -0,0 +1,727 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Xodnizel
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "fceu-types.h"
|
||||
#include "x6502.h"
|
||||
#include "cheat.h"
|
||||
#include "fceu.h"
|
||||
#include "general.h"
|
||||
#include "cart.h"
|
||||
#include "memory.h"
|
||||
|
||||
static uint8 *CheatRPtrs[64];
|
||||
|
||||
void FCEU_CheatResetRAM(void) {
|
||||
int x;
|
||||
|
||||
for (x = 0; x < 64; x++)
|
||||
CheatRPtrs[x] = 0;
|
||||
}
|
||||
|
||||
void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p) {
|
||||
uint32 AB = A >> 10;
|
||||
int x;
|
||||
|
||||
for (x = s - 1; x >= 0; x--)
|
||||
CheatRPtrs[AB + x] = p - A;
|
||||
}
|
||||
|
||||
|
||||
struct CHEATF {
|
||||
struct CHEATF *next;
|
||||
char *name;
|
||||
uint16 addr;
|
||||
uint8 val;
|
||||
int compare; /* -1 for no compare. */
|
||||
int type; /* 0 for replace, 1 for substitute(GG). */
|
||||
int status;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint16 addr;
|
||||
uint8 val;
|
||||
int compare;
|
||||
readfunc PrevRead;
|
||||
} CHEATF_SUBFAST;
|
||||
|
||||
|
||||
static CHEATF_SUBFAST SubCheats[256];
|
||||
static int numsubcheats = 0;
|
||||
struct CHEATF *cheats = 0, *cheatsl = 0;
|
||||
|
||||
|
||||
#define CHEATC_NONE 0x8000
|
||||
#define CHEATC_EXCLUDED 0x4000
|
||||
#define CHEATC_NOSHOW 0xC000
|
||||
|
||||
static uint16 *CheatComp = 0;
|
||||
static int savecheats;
|
||||
|
||||
static DECLFR(SubCheatsRead) {
|
||||
CHEATF_SUBFAST *s = SubCheats;
|
||||
int x = numsubcheats;
|
||||
|
||||
do {
|
||||
if (s->addr == A) {
|
||||
if (s->compare >= 0) {
|
||||
uint8 pv = s->PrevRead(A);
|
||||
|
||||
if (pv == s->compare)
|
||||
return(s->val);
|
||||
else
|
||||
return(pv);
|
||||
} else return(s->val);
|
||||
}
|
||||
s++;
|
||||
} while (--x);
|
||||
return(0); /* We should never get here. */
|
||||
}
|
||||
|
||||
void RebuildSubCheats(void) {
|
||||
int x;
|
||||
struct CHEATF *c = cheats;
|
||||
|
||||
for (x = 0; x < numsubcheats; x++)
|
||||
SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead);
|
||||
|
||||
numsubcheats = 0;
|
||||
while (c) {
|
||||
if (c->type == 1 && c->status) {
|
||||
if (GetReadHandler(c->addr) == SubCheatsRead) {
|
||||
/* Prevent a catastrophe by this check. */
|
||||
//FCEU_DispMessage("oops");
|
||||
} else {
|
||||
SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr);
|
||||
SubCheats[numsubcheats].addr = c->addr;
|
||||
SubCheats[numsubcheats].val = c->val;
|
||||
SubCheats[numsubcheats].compare = c->compare;
|
||||
SetReadHandler(c->addr, c->addr, SubCheatsRead);
|
||||
numsubcheats++;
|
||||
}
|
||||
}
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
|
||||
void FCEU_PowerCheats() {
|
||||
numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */
|
||||
RebuildSubCheats();
|
||||
}
|
||||
|
||||
static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type);
|
||||
static void CheatMemErr(void) {
|
||||
FCEUD_PrintError("Error allocating memory for cheat data.");
|
||||
}
|
||||
|
||||
/* This function doesn't allocate any memory for "name" */
|
||||
static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type) {
|
||||
struct CHEATF *temp;
|
||||
if (!(temp = (struct CHEATF*)malloc(sizeof(struct CHEATF)))) {
|
||||
CheatMemErr();
|
||||
return(0);
|
||||
}
|
||||
temp->name = name;
|
||||
temp->addr = addr;
|
||||
temp->val = val;
|
||||
temp->status = status;
|
||||
temp->compare = compare;
|
||||
temp->type = type;
|
||||
temp->next = 0;
|
||||
|
||||
if (cheats) {
|
||||
cheatsl->next = temp;
|
||||
cheatsl = temp;
|
||||
} else
|
||||
cheats = cheatsl = temp;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void FCEU_LoadGameCheats(FILE *override) {
|
||||
FILE *fp;
|
||||
uint32 addr;
|
||||
uint32 val;
|
||||
uint32 status;
|
||||
uint32 type;
|
||||
uint32 compare;
|
||||
int x;
|
||||
|
||||
char linebuf[2048];
|
||||
char *namebuf;
|
||||
int tc = 0;
|
||||
char *fn;
|
||||
|
||||
numsubcheats = savecheats = 0;
|
||||
|
||||
if (override)
|
||||
fp = override;
|
||||
else {
|
||||
fn = FCEU_MakeFName(FCEUMKF_CHEAT, 0, 0);
|
||||
fp = FCEUD_UTF8fopen(fn, "rb");
|
||||
free(fn);
|
||||
if (!fp) return;
|
||||
}
|
||||
|
||||
while (fgets(linebuf, 2048, fp) > 0) {
|
||||
char *tbuf = linebuf;
|
||||
int doc = 0;
|
||||
|
||||
addr = val = compare = status = type = 0;
|
||||
|
||||
if (tbuf[0] == 'S') {
|
||||
tbuf++;
|
||||
type = 1;
|
||||
} else type = 0;
|
||||
|
||||
if (tbuf[0] == 'C') {
|
||||
tbuf++;
|
||||
doc = 1;
|
||||
}
|
||||
|
||||
if (tbuf[0] == ':') {
|
||||
tbuf++;
|
||||
status = 0;
|
||||
} else status = 1;
|
||||
|
||||
if (doc) {
|
||||
char *neo = &tbuf[4 + 2 + 2 + 1 + 1 + 1];
|
||||
if (sscanf(tbuf, "%04x%*[:]%02x%*[:]%02x", &addr, &val, &compare) != 3)
|
||||
continue;
|
||||
namebuf = malloc(strlen(neo) + 1);
|
||||
strcpy(namebuf, neo);
|
||||
} else {
|
||||
char *neo = &tbuf[4 + 2 + 1 + 1];
|
||||
if (sscanf(tbuf, "%04x%*[:]%02x", &addr, &val) != 2)
|
||||
continue;
|
||||
namebuf = malloc(strlen(neo) + 1);
|
||||
strcpy(namebuf, neo);
|
||||
}
|
||||
|
||||
for (x = 0; x < strlen(namebuf); x++) {
|
||||
if (namebuf[x] == 10 || namebuf[x] == 13) {
|
||||
namebuf[x] = 0;
|
||||
break;
|
||||
} else if (namebuf[x] < 0x20) namebuf[x] = ' ';
|
||||
}
|
||||
|
||||
AddCheatEntry(namebuf, addr, val, doc ? compare : -1, status, type);
|
||||
tc++;
|
||||
}
|
||||
RebuildSubCheats();
|
||||
if (!override)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void FCEU_FlushGameCheats(FILE *override, int nosave) {
|
||||
if (CheatComp) {
|
||||
free(CheatComp);
|
||||
CheatComp = 0;
|
||||
}
|
||||
if ((!savecheats || nosave) && !override) { /* Always save cheats if we're being overridden. */
|
||||
if (cheats) {
|
||||
struct CHEATF *next = cheats;
|
||||
for (;; ) {
|
||||
struct CHEATF *last = next;
|
||||
next = next->next;
|
||||
free(last->name);
|
||||
free(last);
|
||||
if (!next) break;
|
||||
}
|
||||
cheats = cheatsl = 0;
|
||||
}
|
||||
} else {
|
||||
char *fn = 0;
|
||||
|
||||
if (!override)
|
||||
fn = FCEU_MakeFName(FCEUMKF_CHEAT, 0, 0);
|
||||
|
||||
if (cheats) {
|
||||
struct CHEATF *next = cheats;
|
||||
FILE *fp;
|
||||
|
||||
if (override)
|
||||
fp = override;
|
||||
else
|
||||
fp = FCEUD_UTF8fopen(fn, "wb");
|
||||
|
||||
if (fp) {
|
||||
for (;; ) {
|
||||
struct CHEATF *t;
|
||||
if (next->type)
|
||||
fputc('S', fp);
|
||||
if (next->compare >= 0)
|
||||
fputc('C', fp);
|
||||
|
||||
if (!next->status)
|
||||
fputc(':', fp);
|
||||
|
||||
if (next->compare >= 0)
|
||||
fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name);
|
||||
else
|
||||
fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name);
|
||||
|
||||
free(next->name);
|
||||
t = next;
|
||||
next = next->next;
|
||||
free(t);
|
||||
if (!next) break;
|
||||
}
|
||||
if (!override)
|
||||
fclose(fp);
|
||||
} else
|
||||
FCEUD_PrintError("Error saving cheats.");
|
||||
cheats = cheatsl = 0;
|
||||
} else if (!override)
|
||||
remove(fn);
|
||||
if (!override)
|
||||
free(fn);
|
||||
}
|
||||
|
||||
RebuildSubCheats(); /* Remove memory handlers. */
|
||||
}
|
||||
|
||||
|
||||
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type) {
|
||||
char *t;
|
||||
|
||||
if (!(t = (char*)malloc(strlen(name) + 1))) {
|
||||
CheatMemErr();
|
||||
return(0);
|
||||
}
|
||||
strcpy(t, name);
|
||||
if (!AddCheatEntry(t, addr, val, compare, 1, type)) {
|
||||
free(t);
|
||||
return(0);
|
||||
}
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
return(1);
|
||||
}
|
||||
|
||||
int FCEUI_DelCheat(uint32 which) {
|
||||
struct CHEATF *prev;
|
||||
struct CHEATF *cur;
|
||||
uint32 x = 0;
|
||||
|
||||
for (prev = 0, cur = cheats;; ) {
|
||||
if (x == which) { // Remove this cheat.
|
||||
if (prev) { // Update pointer to this cheat.
|
||||
if (cur->next) // More cheats.
|
||||
prev->next = cur->next;
|
||||
else { // No more.
|
||||
prev->next = 0;
|
||||
cheatsl = prev; // Set the previous cheat as the last cheat.
|
||||
}
|
||||
} else {// This is the first cheat.
|
||||
if (cur->next) // More cheats
|
||||
cheats = cur->next;
|
||||
else
|
||||
cheats = cheatsl = 0; // No (more) cheats.
|
||||
}
|
||||
free(cur->name);// Now that all references to this cheat are removed,
|
||||
free(cur); // free the memory.
|
||||
break;
|
||||
} // *END REMOVE THIS CHEAT*
|
||||
|
||||
|
||||
if (!cur->next) // No more cheats to go through(this shouldn't ever happen...)
|
||||
return(0);
|
||||
prev = cur;
|
||||
cur = prev->next;
|
||||
x++;
|
||||
}
|
||||
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void FCEU_ApplyPeriodicCheats(void) {
|
||||
struct CHEATF *cur = cheats;
|
||||
if (!cur) return;
|
||||
|
||||
for (;; ) {
|
||||
if (cur->status && !(cur->type))
|
||||
if (CheatRPtrs[cur->addr >> 10])
|
||||
CheatRPtrs[cur->addr >> 10][cur->addr] = cur->val;
|
||||
if (cur->next)
|
||||
cur = cur->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data) {
|
||||
struct CHEATF *next = cheats;
|
||||
|
||||
while (next) {
|
||||
if (!callb(next->name, next->addr, next->val, next->compare, next->status, next->type, data)) break;
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
|
||||
int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type) {
|
||||
struct CHEATF *next = cheats;
|
||||
uint32 x = 0;
|
||||
|
||||
while (next) {
|
||||
if (x == which) {
|
||||
if (name)
|
||||
*name = next->name;
|
||||
if (a)
|
||||
*a = next->addr;
|
||||
if (v)
|
||||
*v = next->val;
|
||||
if (s)
|
||||
*s = next->status;
|
||||
if (compare)
|
||||
*compare = next->compare;
|
||||
if (type)
|
||||
*type = next->type;
|
||||
return(1);
|
||||
}
|
||||
next = next->next;
|
||||
x++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int GGtobin(char c) {
|
||||
static char lets[16] = { 'A', 'P', 'Z', 'L', 'G', 'I', 'T', 'Y', 'E', 'O', 'X', 'U', 'K', 'S', 'V', 'N' };
|
||||
int x;
|
||||
|
||||
for (x = 0; x < 16; x++)
|
||||
if (lets[x] == toupper(c)) return(x);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Returns 1 on success, 0 on failure. Sets *a,*v,*c. */
|
||||
int FCEUI_DecodeGG(const char *str, uint16 *a, uint8 *v, int *c) {
|
||||
uint16 A;
|
||||
uint8 V, C;
|
||||
uint8 t;
|
||||
int s;
|
||||
|
||||
A = 0x8000;
|
||||
V = 0;
|
||||
C = 0;
|
||||
|
||||
s = strlen(str);
|
||||
if (s != 6 && s != 8) return(0);
|
||||
|
||||
t = GGtobin(*str++);
|
||||
V |= (t & 0x07);
|
||||
V |= (t & 0x08) << 4;
|
||||
|
||||
t = GGtobin(*str++);
|
||||
V |= (t & 0x07) << 4;
|
||||
A |= (t & 0x08) << 4;
|
||||
|
||||
t = GGtobin(*str++);
|
||||
A |= (t & 0x07) << 4;
|
||||
//if(t&0x08) return(0); /* 8-character code?! */
|
||||
|
||||
t = GGtobin(*str++);
|
||||
A |= (t & 0x07) << 12;
|
||||
A |= (t & 0x08);
|
||||
|
||||
t = GGtobin(*str++);
|
||||
A |= (t & 0x07);
|
||||
A |= (t & 0x08) << 8;
|
||||
|
||||
if (s == 6) {
|
||||
t = GGtobin(*str++);
|
||||
A |= (t & 0x07) << 8;
|
||||
V |= (t & 0x08);
|
||||
|
||||
*a = A;
|
||||
*v = V;
|
||||
*c = -1;
|
||||
return(1);
|
||||
} else {
|
||||
t = GGtobin(*str++);
|
||||
A |= (t & 0x07) << 8;
|
||||
C |= (t & 0x08);
|
||||
|
||||
t = GGtobin(*str++);
|
||||
C |= (t & 0x07);
|
||||
C |= (t & 0x08) << 4;
|
||||
|
||||
t = GGtobin(*str++);
|
||||
C |= (t & 0x07) << 4;
|
||||
V |= (t & 0x08);
|
||||
*a = A;
|
||||
*v = V;
|
||||
*c = C;
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int FCEUI_DecodePAR(const char *str, uint16 *a, uint8 *v, int *c, int *type) {
|
||||
int boo[4];
|
||||
if (strlen(str) != 8) return(0);
|
||||
|
||||
sscanf(str, "%02x%02x%02x%02x", boo, boo + 1, boo + 2, boo + 3);
|
||||
|
||||
*c = -1;
|
||||
|
||||
if (1) {
|
||||
*a = (boo[3] << 8) | (boo[2] + 0x7F);
|
||||
*v = 0;
|
||||
} else {
|
||||
*v = boo[3];
|
||||
*a = boo[2] | (boo[1] << 8);
|
||||
}
|
||||
/* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so
|
||||
we must do the old hacky method of RAM cheats.
|
||||
*/
|
||||
if (*a < 0x0100)
|
||||
*type = 0;
|
||||
else
|
||||
*type = 1;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* name can be NULL if the name isn't going to be changed. */
|
||||
/* same goes for a, v, and s(except the values of each one must be <0) */
|
||||
|
||||
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare, int s, int type) {
|
||||
struct CHEATF *next = cheats;
|
||||
uint32 x = 0;
|
||||
|
||||
while (next) {
|
||||
if (x == which) {
|
||||
if (name) {
|
||||
char *t;
|
||||
|
||||
if ((t = (char*)realloc(next->name, strlen(name + 1)))) {
|
||||
next->name = t;
|
||||
strcpy(next->name, name);
|
||||
} else
|
||||
return(0);
|
||||
}
|
||||
if (a >= 0)
|
||||
next->addr = a;
|
||||
if (v >= 0)
|
||||
next->val = v;
|
||||
if (s >= 0)
|
||||
next->status = s;
|
||||
if (compare >= 0)
|
||||
next->compare = compare;
|
||||
next->type = type;
|
||||
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
|
||||
return(1);
|
||||
}
|
||||
next = next->next;
|
||||
x++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Convenience function. */
|
||||
int FCEUI_ToggleCheat(uint32 which) {
|
||||
struct CHEATF *next = cheats;
|
||||
uint32 x = 0;
|
||||
|
||||
while (next) {
|
||||
if (x == which) {
|
||||
next->status = !next->status;
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
return(next->status);
|
||||
}
|
||||
next = next->next;
|
||||
x++;
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int InitCheatComp(void) {
|
||||
uint32 x;
|
||||
|
||||
CheatComp = (uint16*)malloc(65536 * sizeof(uint16));
|
||||
if (!CheatComp) {
|
||||
CheatMemErr();
|
||||
return(0);
|
||||
}
|
||||
for (x = 0; x < 65536; x++)
|
||||
CheatComp[x] = CHEATC_NONE;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void FCEUI_CheatSearchSetCurrentAsOriginal(void) {
|
||||
uint32 x;
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW)) {
|
||||
if (CheatRPtrs[x >> 10])
|
||||
CheatComp[x] = CheatRPtrs[x >> 10][x];
|
||||
else
|
||||
CheatComp[x] |= CHEATC_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void FCEUI_CheatSearchShowExcluded(void) {
|
||||
uint32 x;
|
||||
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
CheatComp[x] &= ~CHEATC_EXCLUDED;
|
||||
}
|
||||
|
||||
|
||||
int32 FCEUI_CheatSearchGetCount(void) {
|
||||
uint32 x, c = 0;
|
||||
|
||||
if (CheatComp) {
|
||||
for (x = 0x0000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
|
||||
c++;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
/* This function will give the initial value of the search and the current value at a location. */
|
||||
|
||||
void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data), void *data) {
|
||||
uint32 x;
|
||||
|
||||
if (!CheatComp) {
|
||||
if (!InitCheatComp())
|
||||
CheatMemErr();
|
||||
return;
|
||||
}
|
||||
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
|
||||
if (!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x], data))
|
||||
break;
|
||||
}
|
||||
|
||||
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current)) {
|
||||
uint32 x;
|
||||
uint32 in = 0;
|
||||
|
||||
if (!CheatComp) {
|
||||
if (!InitCheatComp())
|
||||
CheatMemErr();
|
||||
return;
|
||||
}
|
||||
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10]) {
|
||||
if (in >= first)
|
||||
if (!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x]))
|
||||
break;
|
||||
in++;
|
||||
if (in > last) return;
|
||||
}
|
||||
}
|
||||
|
||||
void FCEUI_CheatSearchBegin(void) {
|
||||
uint32 x;
|
||||
|
||||
if (!CheatComp) {
|
||||
if (!InitCheatComp()) {
|
||||
CheatMemErr();
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (x = 0; x < 0x10000; x++) {
|
||||
if (CheatRPtrs[x >> 10])
|
||||
CheatComp[x] = CheatRPtrs[x >> 10][x];
|
||||
else
|
||||
CheatComp[x] = CHEATC_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int INLINE CAbs(int x) {
|
||||
if (x < 0)
|
||||
return(0 - x);
|
||||
return x;
|
||||
}
|
||||
|
||||
void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) {
|
||||
uint32 x;
|
||||
|
||||
if (!CheatComp) {
|
||||
if (!InitCheatComp()) {
|
||||
CheatMemErr();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!type) {// Change to a specific value.
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW)) {
|
||||
if (CheatComp[x] == v1 && CheatRPtrs[x >> 10][x] == v2) {
|
||||
} else
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
}
|
||||
} else if (type == 1) { // Search for relative change(between values).
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW)) {
|
||||
if (CheatComp[x] == v1 && CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) == v2) {
|
||||
} else
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
}
|
||||
} else if (type == 2) { // Purely relative change.
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW)) {
|
||||
if (CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) == v2) {
|
||||
} else
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
}
|
||||
} else if (type == 3) { // Any change.
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW)) {
|
||||
if (CheatComp[x] != CheatRPtrs[x >> 10][x]) {
|
||||
} else
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
}
|
||||
} else if (type == 4) { // Value decreased.
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW)) {
|
||||
if (!(CheatRPtrs[x >> 10][x] < CheatComp[x]))
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
}
|
||||
} else if (type == 5) { // Value increased.
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW)) {
|
||||
if (!(CheatRPtrs[x >> 10][x] > CheatComp[x]))
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
}
|
||||
}
|
||||
if (type > 4)
|
||||
FCEUI_CheatSearchSetCurrentAsOriginal();
|
||||
}
|
||||
Reference in New Issue
Block a user