some warnings fixed, nsf fixed, palettes, more code backported
[fceu.git] / cheat.c
diff --git a/cheat.c b/cheat.c
index d789d74..2fba4f4 100644 (file)
--- a/cheat.c
+++ b/cheat.c
@@ -1,7 +1,7 @@
 /* FCE Ultra - NES/Famicom Emulator
  *
  * Copyright notice for this file:
 /* FCE Ultra - NES/Famicom Emulator
  *
  * Copyright notice for this file:
- *  Copyright (C) 2002 Ben Parnell
+ *  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
  *
  * 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
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+#include <ctype.h>
 
 #include "types.h"
 #include "x6502.h"
 #include "cheat.h"
 #include "fce.h"
 
 #include "types.h"
 #include "x6502.h"
 #include "cheat.h"
 #include "fce.h"
-#include "svga.h"
 #include "general.h"
 #include "cart.h"
 #include "memory.h"
 
 #include "general.h"
 #include "cart.h"
 #include "memory.h"
 
+#include "file.h"
+#include "svga.h"
+
 static uint8 *CheatRPtrs[64];
 
 void FCEU_CheatResetRAM(void)
 {
  int x;
 
 static uint8 *CheatRPtrs[64];
 
 void FCEU_CheatResetRAM(void)
 {
  int x;
 
- for(x=0;x<64;x++) 
+ for(x=0;x<64;x++)
   CheatRPtrs[x]=0;
 }
 
   CheatRPtrs[x]=0;
 }
 
@@ -56,9 +59,21 @@ struct CHEATF {
            char *name;
            uint16 addr;
            uint8 val;
            char *name;
            uint16 addr;
            uint8 val;
+          int compare; /* -1 for no compare. */
+          int type;    /* 0 for replace, 1 for substitute(GG). */
           int status;
 };
 
           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;
 
 
 struct CHEATF *cheats=0,*cheatsl=0;
 
 
@@ -69,18 +84,79 @@ struct CHEATF *cheats=0,*cheatsl=0;
 static uint16 *CheatComp=0;
 static int savecheats;
 
 static uint16 *CheatComp=0;
 static int savecheats;
 
-static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status);
+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 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 status)
+static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type)
 {
  struct CHEATF *temp;
 {
  struct CHEATF *temp;
- if(!(temp=malloc(sizeof(struct CHEATF))))
+ if(!(temp=(struct CHEATF *)malloc(sizeof(struct CHEATF))))
  {
   CheatMemErr();
   return(0);
  {
   CheatMemErr();
   return(0);
@@ -89,7 +165,8 @@ static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status)
  temp->addr=addr;
  temp->val=val;
  temp->status=status;
  temp->addr=addr;
  temp->val=val;
  temp->status=status;
-
+ temp->compare=compare;
+ temp->type=type;
  temp->next=0;
 
  if(cheats)
  temp->next=0;
 
  if(cheats)
@@ -103,80 +180,113 @@ static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status)
  return(1);
 }
 
  return(1);
 }
 
-void LoadGameCheats(void)
+void FCEU_LoadGameCheats(FILE *override)
 {
  FILE *fp;
 {
  FILE *fp;
- char *name=0;
  unsigned int addr;
  unsigned int val;
  unsigned int status;
  unsigned int addr;
  unsigned int val;
  unsigned int status;
+ unsigned int type;
+ unsigned int compare;
  int x;
 
  int x;
 
- char linebuf[256+4+2+2+1+1]; /* 256 for name, 4 for address, 2 for value, 2 for semicolons, 1 for status, 1 for null */
- char namebuf[257];
+ char linebuf[2048];
+ char *namebuf;
  int tc=0;
  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;
+ }
 
 
- savecheats=0;
- if(!(fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"rb")))
-  return;
- while(fgets(linebuf,256+4+2+2+1+1,fp)>0)
- { 
-  addr=val=status=0;
-  namebuf[0]=0; // If the cheat doesn't have a name...
-  if(linebuf[0]==':')  
+ while(fgets(linebuf,2048,fp)>0)
+ {
+  char *tbuf=linebuf;
+  int doc=0;
+
+  addr=val=compare=status=type=0;
+
+  if(tbuf[0]=='S')
   {
   {
-   strncpy(namebuf,&linebuf[1+4+2+2],257);
-   if(sscanf(&linebuf[1],"%04x%*[:]%02x",&addr,&val)!=2)
-    continue;
+   tbuf++;
+   type=1;
+  }
+  else type=0;
+
+  if(tbuf[0]=='C')
+  {
+   tbuf++;
+   doc=1;
+  }
+
+  if(tbuf[0]==':')
+  {
+   tbuf++;
    status=0;
   }
    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
   {
   else
   {
-   strncpy(namebuf,&linebuf[4+2+2],257);
-   if(sscanf(linebuf,"%04x%*[:]%02x",&addr,&val)!=2) continue;
-   status=1;
+   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<257;x++)
+
+  for(x=0;x<strlen(namebuf);x++)
   {
    if(namebuf[x]==10 || namebuf[x]==13)
    {
     namebuf[x]=0;
     break;
    }
   {
    if(namebuf[x]==10 || namebuf[x]==13)
    {
     namebuf[x]=0;
     break;
    }
+   else if(namebuf[x]<0x20) namebuf[x]=' ';
   }
   }
-  namebuf[256]=0;
-  if(!(name=malloc(strlen(namebuf)+1)))
-   CheatMemErr();
-  else
-  {
-   strcpy(name,namebuf);
-   AddCheatEntry(name,addr,val,status);
-   tc++;
-  }
+
+  AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type);
+  tc++;
  }
  }
- fclose(fp);
+ RebuildSubCheats();
+ if(!override)
+  fclose(fp);
 }
 
 }
 
-
-void FlushGameCheats(void)
+void FCEU_FlushGameCheats(FILE *override, int nosave)
 {
  if(CheatComp)
  {
   free(CheatComp);
   CheatComp=0;
  }
 {
  if(CheatComp)
  {
   free(CheatComp);
   CheatComp=0;
  }
-
- if(!savecheats)
+ if((!savecheats || nosave) && !override)      /* Always save cheats if we're being overridden. */
  {
   if(cheats)
   {
    struct CHEATF *next=cheats;
    for(;;)
  {
   if(cheats)
   {
    struct CHEATF *next=cheats;
    for(;;)
-   {  
+   {
+    struct CHEATF *last=next;
     next=next->next;
     next=next->next;
-    free(cheats->name);
-    free(cheats);
+    free(last->name);
+    free(last);
     if(!next) break;
    }
    cheats=cheatsl=0;
     if(!next) break;
    }
    cheats=cheatsl=0;
@@ -184,53 +294,80 @@ void FlushGameCheats(void)
  }
  else
  {
  }
  else
  {
+  char *fn = 0;
+
+  if(!override)
+   fn = FCEU_MakeFName(FCEUMKF_CHEAT,0,0);
+
   if(cheats)
   {
    struct CHEATF *next=cheats;
    FILE *fp;
   if(cheats)
   {
    struct CHEATF *next=cheats;
    FILE *fp;
-   if((fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"wb")))
+
+   if(override)
+    fp = override;
+   else
+    fp=FCEUD_UTF8fopen(fn,"wb");
+
+   if(fp)
    {
     for(;;)
     {
      struct CHEATF *t;
    {
     for(;;)
     {
      struct CHEATF *t;
-     if(next->status)
-      fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name);
+     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
      else
-      fprintf(fp,":%04x:%02x:%s\n",next->addr,next->val,next->name);
+      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;
     }
      free(next->name);
      t=next;
      next=next->next;
      free(t);
      if(!next) break;
     }
-    fclose(fp);
+    if(!override)
+     fclose(fp);
    }
    else
     FCEUD_PrintError("Error saving cheats.");
    cheats=cheatsl=0;
   }
    }
    else
     FCEUD_PrintError("Error saving cheats.");
    cheats=cheatsl=0;
   }
-  else
-   remove(FCEU_MakeFName(FCEUMKF_CHEAT,0,0));
+  else if(!override)
+   remove(fn);
+  if(!override)
+   free(fn);
  }
  }
+
+ RebuildSubCheats();  /* Remove memory handlers. */
+
 }
 
 
 }
 
 
-int FCEUI_AddCheat(char *name, uint32 addr, uint8 val)
+int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
 {
  char *t;
 
 {
  char *t;
 
- if(!(t=malloc(strlen(name)+1)))
+ if(!(t=(char *)malloc(strlen(name)+1)))
  {
   CheatMemErr();
   return(0);
  }
  strcpy(t,name);
  {
   CheatMemErr();
   return(0);
  }
  strcpy(t,name);
- if(!AddCheatEntry(t,addr,val,1))
+ if(!AddCheatEntry(t,addr,val,compare,1,type))
  {
   free(t);
   return(0);
  }
  savecheats=1;
  {
   free(t);
   return(0);
  }
  savecheats=1;
+ RebuildSubCheats();
  return(1);
 }
 
  return(1);
 }
 
@@ -262,7 +399,7 @@ int FCEUI_DelCheat(uint32 which)
      cheats=cheatsl=0;  // No (more) cheats.
    }
    free(cur->name);     // Now that all references to this cheat are removed,
      cheats=cheatsl=0;  // No (more) cheats.
    }
    free(cur->name);     // Now that all references to this cheat are removed,
-   free(cur);           // free the memory.   
+   free(cur);           // free the memory.
    break;
   }                     // *END REMOVE THIS CHEAT*
 
    break;
   }                     // *END REMOVE THIS CHEAT*
 
@@ -275,17 +412,19 @@ int FCEUI_DelCheat(uint32 which)
  }
 
  savecheats=1;
  }
 
  savecheats=1;
+ RebuildSubCheats();
+
  return(1);
 }
 
  return(1);
 }
 
-void ApplyPeriodicCheats(void)
+void FCEU_ApplyPeriodicCheats(void)
 {
  struct CHEATF *cur=cheats;
  if(!cur) return;
 
  for(;;)
  {
 {
  struct CHEATF *cur=cheats;
  if(!cur) return;
 
  for(;;)
  {
-  if(cur->status)
+  if(cur->status && !(cur->type))
    if(CheatRPtrs[cur->addr>>10])
     CheatRPtrs[cur->addr>>10][cur->addr]=cur->val;
   if(cur->next)
    if(CheatRPtrs[cur->addr>>10])
     CheatRPtrs[cur->addr>>10][cur->addr]=cur->val;
   if(cur->next)
@@ -296,18 +435,18 @@ void ApplyPeriodicCheats(void)
 }
 
 
 }
 
 
-void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int s))
+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)
   {
 {
   struct CHEATF *next=cheats;
 
   while(next)
   {
-   if(!callb(next->name,next->addr,next->val,next->status)) break;
+   if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break;
    next=next->next;
   }
 }
 
    next=next->next;
   }
 }
 
-int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s)
+int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
 {
  struct CHEATF *next=cheats;
  uint32 x=0;
 {
  struct CHEATF *next=cheats;
  uint32 x=0;
@@ -319,12 +458,15 @@ int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s)
    if(name)
     *name=next->name;
    if(a)
    if(name)
     *name=next->name;
    if(a)
-    *a=next->addr; 
+    *a=next->addr;
    if(v)
     *v=next->val;
    if(s)
     *s=next->status;
    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;
    return(1);
   }
   next=next->next;
@@ -333,10 +475,116 @@ int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s)
  return(0);
 }
 
  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) */
 
 /* 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, char *name, int32 a, int32 v, int s)
+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;
 {
  struct CHEATF *next=cheats;
  uint32 x=0;
@@ -349,7 +597,7 @@ int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s)
    {
     char *t;
 
    {
     char *t;
 
-    if((t=realloc(next->name,strlen(name+1))))
+    if((t=(char *)realloc(next->name,strlen(name+1))))
     {
      next->name=t;
      strcpy(next->name,name);
     {
      next->name=t;
      strcpy(next->name,name);
@@ -363,7 +611,12 @@ int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s)
     next->val=v;
    if(s>=0)
     next->status=s;
     next->val=v;
    if(s>=0)
     next->status=s;
+   next->compare=compare;
+   next->type=type;
+
    savecheats=1;
    savecheats=1;
+   RebuildSubCheats();
+
    return(1);
   }
   next=next->next;
    return(1);
   }
   next=next->next;
@@ -372,12 +625,33 @@ int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s)
  return(0);
 }
 
  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;
 
 
 static int InitCheatComp(void)
 {
  uint32 x;
 
- CheatComp=malloc(65536*sizeof(uint16));
+ CheatComp=(uint16*)malloc(65536*sizeof(uint16));
  if(!CheatComp)
  {
   CheatMemErr();
  if(!CheatComp)
  {
   CheatMemErr();
@@ -385,7 +659,7 @@ static int InitCheatComp(void)
  }
  for(x=0;x<65536;x++)
   CheatComp[x]=CHEATC_NONE;
  }
  for(x=0;x<65536;x++)
   CheatComp[x]=CHEATC_NONE;
+
  return(1);
 }
 
  return(1);
 }
 
@@ -426,7 +700,7 @@ int32 FCEUI_CheatSearchGetCount(void)
 }
 /* This function will give the initial value of the search and the current value at a location. */
 
 }
 /* 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 FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data),void *data)
 {
   uint32 x;
 
 {
   uint32 x;
 
@@ -439,7 +713,7 @@ void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current))
 
   for(x=0;x<0x10000;x++)
    if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
 
   for(x=0;x<0x10000;x++)
    if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
-    if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
+    if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x],data))
      break;
 }
 
      break;
 }
 
@@ -550,7 +824,7 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
  }
  else if(type==3)                          // Any change.
  {
  }
  else if(type==3)                          // Any change.
  {
-  for(x=0x000;x<0x10000;x++)
+  for(x=0;x<0x10000;x++)
    if(!(CheatComp[x]&CHEATC_NOSHOW))
    {
     if(CheatComp[x]!=CheatRPtrs[x>>10][x])
    if(!(CheatComp[x]&CHEATC_NOSHOW))
    {
     if(CheatComp[x]!=CheatRPtrs[x>>10][x])
@@ -560,6 +834,25 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
     else
      CheatComp[x]|=CHEATC_EXCLUDED;
    }
     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();
 }
 }