c62d2810 |
1 | /* FCE Ultra - NES/Famicom Emulator |
2 | * |
3 | * Copyright notice for this file: |
92764e62 |
4 | * Copyright (C) 2002 Xodnizel |
c62d2810 |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
20 | |
21 | #include <stdlib.h> |
22 | #include <string.h> |
23 | #include <stdio.h> |
92764e62 |
24 | #include <ctype.h> |
c62d2810 |
25 | |
26 | #include "types.h" |
27 | #include "x6502.h" |
28 | #include "cheat.h" |
29 | #include "fce.h" |
c62d2810 |
30 | #include "general.h" |
31 | #include "cart.h" |
32 | #include "memory.h" |
33 | |
92764e62 |
34 | #include "file.h" |
35 | #include "svga.h" |
36 | |
c62d2810 |
37 | static uint8 *CheatRPtrs[64]; |
38 | |
39 | void FCEU_CheatResetRAM(void) |
40 | { |
41 | int x; |
42 | |
92764e62 |
43 | for(x=0;x<64;x++) |
c62d2810 |
44 | CheatRPtrs[x]=0; |
45 | } |
46 | |
47 | void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p) |
48 | { |
49 | uint32 AB=A>>10; |
50 | int x; |
51 | |
52 | for(x=s-1;x>=0;x--) |
53 | CheatRPtrs[AB+x]=p-A; |
54 | } |
55 | |
56 | |
57 | struct CHEATF { |
58 | struct CHEATF *next; |
59 | char *name; |
60 | uint16 addr; |
61 | uint8 val; |
92764e62 |
62 | int compare; /* -1 for no compare. */ |
63 | int type; /* 0 for replace, 1 for substitute(GG). */ |
c62d2810 |
64 | int status; |
65 | }; |
66 | |
92764e62 |
67 | typedef struct { |
68 | uint16 addr; |
69 | uint8 val; |
70 | int compare; |
71 | readfunc PrevRead; |
72 | } CHEATF_SUBFAST; |
73 | |
74 | |
75 | static CHEATF_SUBFAST SubCheats[256]; |
76 | static int numsubcheats=0; |
c62d2810 |
77 | struct CHEATF *cheats=0,*cheatsl=0; |
78 | |
79 | |
80 | #define CHEATC_NONE 0x8000 |
81 | #define CHEATC_EXCLUDED 0x4000 |
82 | #define CHEATC_NOSHOW 0xC000 |
83 | |
84 | static uint16 *CheatComp=0; |
85 | static int savecheats; |
86 | |
92764e62 |
87 | static DECLFR(SubCheatsRead) |
88 | { |
89 | CHEATF_SUBFAST *s=SubCheats; |
90 | int x=numsubcheats; |
91 | |
92 | do |
93 | { |
94 | if(s->addr==A) |
95 | { |
96 | if(s->compare>=0) |
97 | { |
98 | uint8 pv=s->PrevRead(A); |
99 | |
100 | if(pv==s->compare) |
101 | return(s->val); |
102 | else return(pv); |
103 | } |
104 | else return(s->val); |
105 | } |
106 | s++; |
107 | } while(--x); |
108 | return(0); /* We should never get here. */ |
109 | } |
110 | |
111 | void RebuildSubCheats(void) |
112 | { |
113 | int x; |
114 | struct CHEATF *c=cheats; |
115 | |
116 | for(x=0;x<numsubcheats;x++) |
117 | SetReadHandler(SubCheats[x].addr,SubCheats[x].addr,SubCheats[x].PrevRead); |
118 | |
119 | numsubcheats=0; |
120 | while(c) |
121 | { |
122 | if(c->type==1 && c->status) |
123 | { |
124 | if(GetReadHandler(c->addr)==SubCheatsRead) |
125 | { |
126 | /* Prevent a catastrophe by this check. */ |
127 | //FCEU_DispMessage("oops"); |
128 | } |
129 | else |
130 | { |
131 | SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr); |
132 | SubCheats[numsubcheats].addr=c->addr; |
133 | SubCheats[numsubcheats].val=c->val; |
134 | SubCheats[numsubcheats].compare=c->compare; |
135 | SetReadHandler(c->addr,c->addr,SubCheatsRead); |
136 | numsubcheats++; |
137 | } |
138 | } |
139 | c=c->next; |
140 | } |
141 | } |
c62d2810 |
142 | |
92764e62 |
143 | void FCEU_PowerCheats() |
144 | { |
145 | numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */ |
146 | RebuildSubCheats(); |
147 | } |
148 | |
149 | static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type); |
c62d2810 |
150 | static void CheatMemErr(void) |
151 | { |
152 | FCEUD_PrintError("Error allocating memory for cheat data."); |
153 | } |
154 | |
155 | /* This function doesn't allocate any memory for "name" */ |
92764e62 |
156 | static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type) |
c62d2810 |
157 | { |
158 | struct CHEATF *temp; |
92764e62 |
159 | if(!(temp=(struct CHEATF *)malloc(sizeof(struct CHEATF)))) |
c62d2810 |
160 | { |
161 | CheatMemErr(); |
162 | return(0); |
163 | } |
164 | temp->name=name; |
165 | temp->addr=addr; |
166 | temp->val=val; |
167 | temp->status=status; |
92764e62 |
168 | temp->compare=compare; |
169 | temp->type=type; |
c62d2810 |
170 | temp->next=0; |
171 | |
172 | if(cheats) |
173 | { |
174 | cheatsl->next=temp; |
175 | cheatsl=temp; |
176 | } |
177 | else |
178 | cheats=cheatsl=temp; |
179 | |
180 | return(1); |
181 | } |
182 | |
92764e62 |
183 | void FCEU_LoadGameCheats(FILE *override) |
c62d2810 |
184 | { |
185 | FILE *fp; |
c62d2810 |
186 | unsigned int addr; |
187 | unsigned int val; |
188 | unsigned int status; |
92764e62 |
189 | unsigned int type; |
190 | unsigned int compare; |
c62d2810 |
191 | int x; |
192 | |
92764e62 |
193 | char linebuf[2048]; |
194 | char *namebuf; |
c62d2810 |
195 | int tc=0; |
92764e62 |
196 | char *fn; |
197 | |
198 | numsubcheats=savecheats=0; |
199 | |
200 | if(override) |
201 | fp = override; |
202 | else |
203 | { |
204 | fn=FCEU_MakeFName(FCEUMKF_CHEAT,0,0); |
205 | fp=FCEUD_UTF8fopen(fn,"rb"); |
206 | free(fn); |
207 | if(!fp) return; |
208 | } |
c62d2810 |
209 | |
92764e62 |
210 | while(fgets(linebuf,2048,fp)>0) |
211 | { |
212 | char *tbuf=linebuf; |
213 | int doc=0; |
214 | |
215 | addr=val=compare=status=type=0; |
216 | |
217 | if(tbuf[0]=='S') |
c62d2810 |
218 | { |
92764e62 |
219 | tbuf++; |
220 | type=1; |
221 | } |
222 | else type=0; |
223 | |
224 | if(tbuf[0]=='C') |
225 | { |
226 | tbuf++; |
227 | doc=1; |
228 | } |
229 | |
230 | if(tbuf[0]==':') |
231 | { |
232 | tbuf++; |
c62d2810 |
233 | status=0; |
234 | } |
92764e62 |
235 | else status=1; |
236 | |
237 | if(doc) |
238 | { |
239 | char *neo=&tbuf[4+2+2+1+1+1]; |
240 | if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3) |
241 | continue; |
242 | namebuf=malloc(strlen(neo)+1); |
243 | strcpy(namebuf,neo); |
244 | } |
c62d2810 |
245 | else |
246 | { |
92764e62 |
247 | char *neo=&tbuf[4+2+1+1]; |
248 | if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2) |
249 | continue; |
250 | namebuf=malloc(strlen(neo)+1); |
251 | strcpy(namebuf,neo); |
c62d2810 |
252 | } |
92764e62 |
253 | |
254 | for(x=0;x<strlen(namebuf);x++) |
c62d2810 |
255 | { |
256 | if(namebuf[x]==10 || namebuf[x]==13) |
257 | { |
258 | namebuf[x]=0; |
259 | break; |
260 | } |
92764e62 |
261 | else if(namebuf[x]<0x20) namebuf[x]=' '; |
c62d2810 |
262 | } |
92764e62 |
263 | |
264 | AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type); |
265 | tc++; |
c62d2810 |
266 | } |
92764e62 |
267 | RebuildSubCheats(); |
268 | if(!override) |
269 | fclose(fp); |
c62d2810 |
270 | } |
271 | |
92764e62 |
272 | void FCEU_FlushGameCheats(FILE *override, int nosave) |
c62d2810 |
273 | { |
274 | if(CheatComp) |
275 | { |
276 | free(CheatComp); |
277 | CheatComp=0; |
278 | } |
92764e62 |
279 | if((!savecheats || nosave) && !override) /* Always save cheats if we're being overridden. */ |
c62d2810 |
280 | { |
281 | if(cheats) |
282 | { |
283 | struct CHEATF *next=cheats; |
284 | for(;;) |
92764e62 |
285 | { |
286 | struct CHEATF *last=next; |
c62d2810 |
287 | next=next->next; |
92764e62 |
288 | free(last->name); |
289 | free(last); |
c62d2810 |
290 | if(!next) break; |
291 | } |
292 | cheats=cheatsl=0; |
293 | } |
294 | } |
295 | else |
296 | { |
92764e62 |
297 | char *fn = 0; |
298 | |
299 | if(!override) |
300 | fn = FCEU_MakeFName(FCEUMKF_CHEAT,0,0); |
301 | |
c62d2810 |
302 | if(cheats) |
303 | { |
304 | struct CHEATF *next=cheats; |
305 | FILE *fp; |
92764e62 |
306 | |
307 | if(override) |
308 | fp = override; |
309 | else |
310 | fp=FCEUD_UTF8fopen(fn,"wb"); |
311 | |
312 | if(fp) |
c62d2810 |
313 | { |
314 | for(;;) |
315 | { |
316 | struct CHEATF *t; |
92764e62 |
317 | if(next->type) |
318 | fputc('S',fp); |
319 | if(next->compare>=0) |
320 | fputc('C',fp); |
321 | |
322 | if(!next->status) |
323 | fputc(':',fp); |
324 | |
325 | if(next->compare>=0) |
326 | fprintf(fp,"%04x:%02x:%02x:%s\n",next->addr,next->val,next->compare,next->name); |
c62d2810 |
327 | else |
92764e62 |
328 | fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name); |
329 | |
c62d2810 |
330 | free(next->name); |
331 | t=next; |
332 | next=next->next; |
333 | free(t); |
334 | if(!next) break; |
335 | } |
92764e62 |
336 | if(!override) |
337 | fclose(fp); |
c62d2810 |
338 | } |
339 | else |
340 | FCEUD_PrintError("Error saving cheats."); |
341 | cheats=cheatsl=0; |
342 | } |
92764e62 |
343 | else if(!override) |
344 | remove(fn); |
345 | if(!override) |
346 | free(fn); |
c62d2810 |
347 | } |
92764e62 |
348 | |
349 | RebuildSubCheats(); /* Remove memory handlers. */ |
350 | |
c62d2810 |
351 | } |
352 | |
353 | |
92764e62 |
354 | int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type) |
c62d2810 |
355 | { |
356 | char *t; |
357 | |
92764e62 |
358 | if(!(t=(char *)malloc(strlen(name)+1))) |
c62d2810 |
359 | { |
360 | CheatMemErr(); |
361 | return(0); |
362 | } |
363 | strcpy(t,name); |
92764e62 |
364 | if(!AddCheatEntry(t,addr,val,compare,1,type)) |
c62d2810 |
365 | { |
366 | free(t); |
367 | return(0); |
368 | } |
369 | savecheats=1; |
92764e62 |
370 | RebuildSubCheats(); |
c62d2810 |
371 | return(1); |
372 | } |
373 | |
374 | int FCEUI_DelCheat(uint32 which) |
375 | { |
376 | struct CHEATF *prev; |
377 | struct CHEATF *cur; |
378 | uint32 x=0; |
379 | |
380 | for(prev=0,cur=cheats;;) |
381 | { |
382 | if(x==which) // Remove this cheat. |
383 | { |
384 | if(prev) // Update pointer to this cheat. |
385 | { |
386 | if(cur->next) // More cheats. |
387 | prev->next=cur->next; |
388 | else // No more. |
389 | { |
390 | prev->next=0; |
391 | cheatsl=prev; // Set the previous cheat as the last cheat. |
392 | } |
393 | } |
394 | else // This is the first cheat. |
395 | { |
396 | if(cur->next) // More cheats |
397 | cheats=cur->next; |
398 | else |
399 | cheats=cheatsl=0; // No (more) cheats. |
400 | } |
401 | free(cur->name); // Now that all references to this cheat are removed, |
92764e62 |
402 | free(cur); // free the memory. |
c62d2810 |
403 | break; |
404 | } // *END REMOVE THIS CHEAT* |
405 | |
406 | |
407 | if(!cur->next) // No more cheats to go through(this shouldn't ever happen...) |
408 | return(0); |
409 | prev=cur; |
410 | cur=prev->next; |
411 | x++; |
412 | } |
413 | |
414 | savecheats=1; |
92764e62 |
415 | RebuildSubCheats(); |
416 | |
c62d2810 |
417 | return(1); |
418 | } |
419 | |
92764e62 |
420 | void FCEU_ApplyPeriodicCheats(void) |
c62d2810 |
421 | { |
422 | struct CHEATF *cur=cheats; |
423 | if(!cur) return; |
424 | |
425 | for(;;) |
426 | { |
92764e62 |
427 | if(cur->status && !(cur->type)) |
c62d2810 |
428 | if(CheatRPtrs[cur->addr>>10]) |
429 | CheatRPtrs[cur->addr>>10][cur->addr]=cur->val; |
430 | if(cur->next) |
431 | cur=cur->next; |
432 | else |
433 | break; |
434 | } |
435 | } |
436 | |
437 | |
92764e62 |
438 | void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data) |
c62d2810 |
439 | { |
440 | struct CHEATF *next=cheats; |
441 | |
442 | while(next) |
443 | { |
92764e62 |
444 | if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break; |
c62d2810 |
445 | next=next->next; |
446 | } |
447 | } |
448 | |
92764e62 |
449 | int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type) |
c62d2810 |
450 | { |
451 | struct CHEATF *next=cheats; |
452 | uint32 x=0; |
453 | |
454 | while(next) |
455 | { |
456 | if(x==which) |
457 | { |
458 | if(name) |
459 | *name=next->name; |
460 | if(a) |
92764e62 |
461 | *a=next->addr; |
c62d2810 |
462 | if(v) |
463 | *v=next->val; |
464 | if(s) |
465 | *s=next->status; |
92764e62 |
466 | if(compare) |
467 | *compare=next->compare; |
468 | if(type) |
469 | *type=next->type; |
c62d2810 |
470 | return(1); |
471 | } |
472 | next=next->next; |
473 | x++; |
474 | } |
475 | return(0); |
476 | } |
477 | |
92764e62 |
478 | static int GGtobin(char c) |
479 | { |
480 | static char lets[16]={'A','P','Z','L','G','I','T','Y','E','O','X','U','K','S','V','N'}; |
481 | int x; |
482 | |
483 | for(x=0;x<16;x++) |
484 | if(lets[x] == toupper(c)) return(x); |
485 | return(0); |
486 | } |
487 | |
488 | /* Returns 1 on success, 0 on failure. Sets *a,*v,*c. */ |
489 | int FCEUI_DecodeGG(const char *str, uint16 *a, uint8 *v, int *c) |
490 | { |
491 | uint16 A; |
492 | uint8 V,C; |
493 | uint8 t; |
494 | int s; |
495 | |
496 | A=0x8000; |
497 | V=0; |
498 | C=0; |
499 | |
500 | s=strlen(str); |
501 | if(s!=6 && s!=8) return(0); |
502 | |
503 | t=GGtobin(*str++); |
504 | V|=(t&0x07); |
505 | V|=(t&0x08)<<4; |
506 | |
507 | t=GGtobin(*str++); |
508 | V|=(t&0x07)<<4; |
509 | A|=(t&0x08)<<4; |
510 | |
511 | t=GGtobin(*str++); |
512 | A|=(t&0x07)<<4; |
513 | //if(t&0x08) return(0); /* 8-character code?! */ |
514 | |
515 | t=GGtobin(*str++); |
516 | A|=(t&0x07)<<12; |
517 | A|=(t&0x08); |
518 | |
519 | t=GGtobin(*str++); |
520 | A|=(t&0x07); |
521 | A|=(t&0x08)<<8; |
522 | |
523 | if(s==6) |
524 | { |
525 | t=GGtobin(*str++); |
526 | A|=(t&0x07)<<8; |
527 | V|=(t&0x08); |
528 | |
529 | *a=A; |
530 | *v=V; |
531 | *c=-1; |
532 | return(1); |
533 | } |
534 | else |
535 | { |
536 | t=GGtobin(*str++); |
537 | A|=(t&0x07)<<8; |
538 | C|=(t&0x08); |
539 | |
540 | t=GGtobin(*str++); |
541 | C|=(t&0x07); |
542 | C|=(t&0x08)<<4; |
543 | |
544 | t=GGtobin(*str++); |
545 | C|=(t&0x07)<<4; |
546 | V|=(t&0x08); |
547 | *a=A; |
548 | *v=V; |
549 | *c=C; |
550 | return(1); |
551 | } |
552 | return(0); |
553 | } |
554 | |
555 | int FCEUI_DecodePAR(const char *str, uint16 *a, uint8 *v, int *c, int *type) |
556 | { |
557 | int boo[4]; |
558 | if(strlen(str)!=8) return(0); |
559 | |
560 | sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3); |
561 | |
562 | *c=-1; |
563 | |
564 | if(1) |
565 | { |
566 | *a=(boo[3]<<8)|(boo[2]+0x7F); |
567 | *v=0; |
568 | } |
569 | else |
570 | { |
571 | *v=boo[3]; |
572 | *a=boo[2]|(boo[1]<<8); |
573 | } |
574 | /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so |
575 | we must do the old hacky method of RAM cheats. |
576 | */ |
577 | if(*a<0x0100) |
578 | *type=0; |
579 | else |
580 | *type=1; |
581 | return(1); |
582 | } |
583 | |
c62d2810 |
584 | /* name can be NULL if the name isn't going to be changed. */ |
585 | /* same goes for a, v, and s(except the values of each one must be <0) */ |
586 | |
92764e62 |
587 | int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare,int s, int type) |
c62d2810 |
588 | { |
589 | struct CHEATF *next=cheats; |
590 | uint32 x=0; |
591 | |
592 | while(next) |
593 | { |
594 | if(x==which) |
595 | { |
596 | if(name) |
597 | { |
598 | char *t; |
599 | |
92764e62 |
600 | if((t=(char *)realloc(next->name,strlen(name+1)))) |
c62d2810 |
601 | { |
602 | next->name=t; |
603 | strcpy(next->name,name); |
604 | } |
605 | else |
606 | return(0); |
607 | } |
608 | if(a>=0) |
609 | next->addr=a; |
610 | if(v>=0) |
611 | next->val=v; |
612 | if(s>=0) |
613 | next->status=s; |
92764e62 |
614 | next->compare=compare; |
615 | next->type=type; |
616 | |
c62d2810 |
617 | savecheats=1; |
92764e62 |
618 | RebuildSubCheats(); |
619 | |
c62d2810 |
620 | return(1); |
621 | } |
622 | next=next->next; |
623 | x++; |
624 | } |
625 | return(0); |
626 | } |
627 | |
92764e62 |
628 | /* Convenience function. */ |
629 | int FCEUI_ToggleCheat(uint32 which) |
630 | { |
631 | struct CHEATF *next=cheats; |
632 | uint32 x=0; |
633 | |
634 | while(next) |
635 | { |
636 | if(x==which) |
637 | { |
638 | next->status=!next->status; |
639 | savecheats=1; |
640 | RebuildSubCheats(); |
641 | return(next->status); |
642 | } |
643 | next=next->next; |
644 | x++; |
645 | } |
646 | |
647 | return(-1); |
648 | } |
c62d2810 |
649 | |
650 | static int InitCheatComp(void) |
651 | { |
652 | uint32 x; |
653 | |
92764e62 |
654 | CheatComp=(uint16*)malloc(65536*sizeof(uint16)); |
c62d2810 |
655 | if(!CheatComp) |
656 | { |
657 | CheatMemErr(); |
658 | return(0); |
659 | } |
660 | for(x=0;x<65536;x++) |
661 | CheatComp[x]=CHEATC_NONE; |
92764e62 |
662 | |
c62d2810 |
663 | return(1); |
664 | } |
665 | |
666 | void FCEUI_CheatSearchSetCurrentAsOriginal(void) |
667 | { |
668 | uint32 x; |
669 | for(x=0x000;x<0x10000;x++) |
670 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
671 | { |
672 | if(CheatRPtrs[x>>10]) |
673 | CheatComp[x]=CheatRPtrs[x>>10][x]; |
674 | else |
675 | CheatComp[x]|=CHEATC_NONE; |
676 | } |
677 | } |
678 | |
679 | void FCEUI_CheatSearchShowExcluded(void) |
680 | { |
681 | uint32 x; |
682 | |
683 | for(x=0x000;x<0x10000;x++) |
684 | CheatComp[x]&=~CHEATC_EXCLUDED; |
685 | } |
686 | |
687 | |
688 | int32 FCEUI_CheatSearchGetCount(void) |
689 | { |
690 | uint32 x,c=0; |
691 | |
692 | if(CheatComp) |
693 | { |
694 | for(x=0x0000;x<0x10000;x++) |
695 | if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) |
696 | c++; |
697 | } |
698 | |
699 | return c; |
700 | } |
701 | /* This function will give the initial value of the search and the current value at a location. */ |
702 | |
92764e62 |
703 | void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data),void *data) |
c62d2810 |
704 | { |
705 | uint32 x; |
706 | |
707 | if(!CheatComp) |
708 | { |
709 | if(!InitCheatComp()) |
710 | CheatMemErr(); |
711 | return; |
712 | } |
713 | |
714 | for(x=0;x<0x10000;x++) |
715 | if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) |
92764e62 |
716 | if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x],data)) |
c62d2810 |
717 | break; |
718 | } |
719 | |
720 | void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current)) |
721 | { |
722 | uint32 x; |
723 | uint32 in=0; |
724 | |
725 | if(!CheatComp) |
726 | { |
727 | if(!InitCheatComp()) |
728 | CheatMemErr(); |
729 | return; |
730 | } |
731 | |
732 | for(x=0;x<0x10000;x++) |
733 | if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) |
734 | { |
735 | if(in>=first) |
736 | if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x])) |
737 | break; |
738 | in++; |
739 | if(in>last) return; |
740 | } |
741 | } |
742 | |
743 | void FCEUI_CheatSearchBegin(void) |
744 | { |
745 | uint32 x; |
746 | |
747 | if(!CheatComp) |
748 | { |
749 | if(!InitCheatComp()) |
750 | { |
751 | CheatMemErr(); |
752 | return; |
753 | } |
754 | } |
755 | for(x=0;x<0x10000;x++) |
756 | { |
757 | if(CheatRPtrs[x>>10]) |
758 | CheatComp[x]=CheatRPtrs[x>>10][x]; |
759 | else |
760 | CheatComp[x]=CHEATC_NONE; |
761 | } |
762 | } |
763 | |
764 | |
765 | static int INLINE CAbs(int x) |
766 | { |
767 | if(x<0) |
768 | return(0-x); |
769 | return x; |
770 | } |
771 | |
772 | void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) |
773 | { |
774 | uint32 x; |
775 | |
776 | if(!CheatComp) |
777 | { |
778 | if(!InitCheatComp()) |
779 | { |
780 | CheatMemErr(); |
781 | return; |
782 | } |
783 | } |
784 | |
785 | |
786 | if(!type) // Change to a specific value. |
787 | { |
788 | for(x=0;x<0x10000;x++) |
789 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
790 | { |
791 | if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2) |
792 | { |
793 | |
794 | } |
795 | else |
796 | CheatComp[x]|=CHEATC_EXCLUDED; |
797 | } |
798 | } |
799 | else if(type==1) // Search for relative change(between values). |
800 | { |
801 | for(x=0;x<0x10000;x++) |
802 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
803 | { |
804 | if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2) |
805 | { |
806 | |
807 | } |
808 | else |
809 | CheatComp[x]|=CHEATC_EXCLUDED; |
810 | } |
811 | } |
812 | else if(type==2) // Purely relative change. |
813 | { |
814 | for(x=0x000;x<0x10000;x++) |
815 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
816 | { |
817 | if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2) |
818 | { |
819 | |
820 | } |
821 | else |
822 | CheatComp[x]|=CHEATC_EXCLUDED; |
823 | } |
824 | } |
825 | else if(type==3) // Any change. |
826 | { |
92764e62 |
827 | for(x=0;x<0x10000;x++) |
c62d2810 |
828 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
829 | { |
830 | if(CheatComp[x]!=CheatRPtrs[x>>10][x]) |
831 | { |
832 | |
833 | } |
834 | else |
835 | CheatComp[x]|=CHEATC_EXCLUDED; |
836 | } |
c62d2810 |
837 | } |
92764e62 |
838 | else if(type==4) // Value decreased. |
839 | { |
840 | for(x=0;x<0x10000;x++) |
841 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
842 | { |
843 | if(!(CheatRPtrs[x>>10][x]<CheatComp[x])) |
844 | CheatComp[x]|=CHEATC_EXCLUDED; |
845 | } |
846 | } |
847 | else if(type==5) // Value increased. |
848 | { |
849 | for(x=0;x<0x10000;x++) |
850 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
851 | { |
852 | if(!(CheatRPtrs[x>>10][x]>CheatComp[x])) |
853 | CheatComp[x]|=CHEATC_EXCLUDED; |
854 | } |
855 | } |
856 | if(type>4) |
857 | FCEUI_CheatSearchSetCurrentAsOriginal(); |
c62d2810 |
858 | } |