c62d2810 |
1 | /* FCE Ultra - NES/Famicom Emulator |
2 | * |
3 | * Copyright notice for this file: |
4 | * Copyright (C) 2002 Ben Parnell |
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> |
24 | |
25 | #include "types.h" |
26 | #include "x6502.h" |
27 | #include "cheat.h" |
28 | #include "fce.h" |
29 | #include "svga.h" |
30 | #include "general.h" |
31 | #include "cart.h" |
32 | #include "memory.h" |
33 | |
34 | static uint8 *CheatRPtrs[64]; |
35 | |
36 | void FCEU_CheatResetRAM(void) |
37 | { |
38 | int x; |
39 | |
40 | for(x=0;x<64;x++) |
41 | CheatRPtrs[x]=0; |
42 | } |
43 | |
44 | void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p) |
45 | { |
46 | uint32 AB=A>>10; |
47 | int x; |
48 | |
49 | for(x=s-1;x>=0;x--) |
50 | CheatRPtrs[AB+x]=p-A; |
51 | } |
52 | |
53 | |
54 | struct CHEATF { |
55 | struct CHEATF *next; |
56 | char *name; |
57 | uint16 addr; |
58 | uint8 val; |
59 | int status; |
60 | }; |
61 | |
62 | struct CHEATF *cheats=0,*cheatsl=0; |
63 | |
64 | |
65 | #define CHEATC_NONE 0x8000 |
66 | #define CHEATC_EXCLUDED 0x4000 |
67 | #define CHEATC_NOSHOW 0xC000 |
68 | |
69 | static uint16 *CheatComp=0; |
70 | static int savecheats; |
71 | |
72 | static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status); |
73 | |
74 | static void CheatMemErr(void) |
75 | { |
76 | FCEUD_PrintError("Error allocating memory for cheat data."); |
77 | } |
78 | |
79 | /* This function doesn't allocate any memory for "name" */ |
80 | static int AddCheatEntry(char *name, uint32 addr, uint8 val, int status) |
81 | { |
82 | struct CHEATF *temp; |
83 | if(!(temp=malloc(sizeof(struct CHEATF)))) |
84 | { |
85 | CheatMemErr(); |
86 | return(0); |
87 | } |
88 | temp->name=name; |
89 | temp->addr=addr; |
90 | temp->val=val; |
91 | temp->status=status; |
92 | |
93 | temp->next=0; |
94 | |
95 | if(cheats) |
96 | { |
97 | cheatsl->next=temp; |
98 | cheatsl=temp; |
99 | } |
100 | else |
101 | cheats=cheatsl=temp; |
102 | |
103 | return(1); |
104 | } |
105 | |
106 | void LoadGameCheats(void) |
107 | { |
108 | FILE *fp; |
109 | char *name=0; |
110 | unsigned int addr; |
111 | unsigned int val; |
112 | unsigned int status; |
113 | int x; |
114 | |
115 | 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 */ |
116 | char namebuf[257]; |
117 | int tc=0; |
118 | |
119 | savecheats=0; |
120 | if(!(fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"rb"))) |
121 | return; |
122 | |
123 | while(fgets(linebuf,256+4+2+2+1+1,fp)>0) |
124 | { |
125 | addr=val=status=0; |
126 | namebuf[0]=0; // If the cheat doesn't have a name... |
127 | if(linebuf[0]==':') |
128 | { |
129 | strncpy(namebuf,&linebuf[1+4+2+2],257); |
130 | if(sscanf(&linebuf[1],"%04x%*[:]%02x",&addr,&val)!=2) |
131 | continue; |
132 | status=0; |
133 | } |
134 | else |
135 | { |
136 | strncpy(namebuf,&linebuf[4+2+2],257); |
137 | if(sscanf(linebuf,"%04x%*[:]%02x",&addr,&val)!=2) continue; |
138 | status=1; |
139 | } |
140 | for(x=0;x<257;x++) |
141 | { |
142 | if(namebuf[x]==10 || namebuf[x]==13) |
143 | { |
144 | namebuf[x]=0; |
145 | break; |
146 | } |
147 | } |
148 | namebuf[256]=0; |
149 | if(!(name=malloc(strlen(namebuf)+1))) |
150 | CheatMemErr(); |
151 | else |
152 | { |
153 | strcpy(name,namebuf); |
154 | AddCheatEntry(name,addr,val,status); |
155 | tc++; |
156 | } |
157 | } |
158 | fclose(fp); |
159 | } |
160 | |
161 | |
162 | void FlushGameCheats(void) |
163 | { |
164 | if(CheatComp) |
165 | { |
166 | free(CheatComp); |
167 | CheatComp=0; |
168 | } |
169 | |
170 | if(!savecheats) |
171 | { |
172 | if(cheats) |
173 | { |
174 | struct CHEATF *next=cheats; |
175 | for(;;) |
176 | { |
177 | next=next->next; |
178 | free(cheats->name); |
179 | free(cheats); |
180 | if(!next) break; |
181 | } |
182 | cheats=cheatsl=0; |
183 | } |
184 | } |
185 | else |
186 | { |
187 | if(cheats) |
188 | { |
189 | struct CHEATF *next=cheats; |
190 | FILE *fp; |
191 | if((fp=fopen(FCEU_MakeFName(FCEUMKF_CHEAT,0,0),"wb"))) |
192 | { |
193 | for(;;) |
194 | { |
195 | struct CHEATF *t; |
196 | if(next->status) |
197 | fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name); |
198 | else |
199 | fprintf(fp,":%04x:%02x:%s\n",next->addr,next->val,next->name); |
200 | free(next->name); |
201 | t=next; |
202 | next=next->next; |
203 | free(t); |
204 | if(!next) break; |
205 | } |
206 | fclose(fp); |
207 | } |
208 | else |
209 | FCEUD_PrintError("Error saving cheats."); |
210 | cheats=cheatsl=0; |
211 | } |
212 | else |
213 | remove(FCEU_MakeFName(FCEUMKF_CHEAT,0,0)); |
214 | } |
215 | } |
216 | |
217 | |
218 | int FCEUI_AddCheat(char *name, uint32 addr, uint8 val) |
219 | { |
220 | char *t; |
221 | |
222 | if(!(t=malloc(strlen(name)+1))) |
223 | { |
224 | CheatMemErr(); |
225 | return(0); |
226 | } |
227 | strcpy(t,name); |
228 | if(!AddCheatEntry(t,addr,val,1)) |
229 | { |
230 | free(t); |
231 | return(0); |
232 | } |
233 | savecheats=1; |
234 | return(1); |
235 | } |
236 | |
237 | int FCEUI_DelCheat(uint32 which) |
238 | { |
239 | struct CHEATF *prev; |
240 | struct CHEATF *cur; |
241 | uint32 x=0; |
242 | |
243 | for(prev=0,cur=cheats;;) |
244 | { |
245 | if(x==which) // Remove this cheat. |
246 | { |
247 | if(prev) // Update pointer to this cheat. |
248 | { |
249 | if(cur->next) // More cheats. |
250 | prev->next=cur->next; |
251 | else // No more. |
252 | { |
253 | prev->next=0; |
254 | cheatsl=prev; // Set the previous cheat as the last cheat. |
255 | } |
256 | } |
257 | else // This is the first cheat. |
258 | { |
259 | if(cur->next) // More cheats |
260 | cheats=cur->next; |
261 | else |
262 | cheats=cheatsl=0; // No (more) cheats. |
263 | } |
264 | free(cur->name); // Now that all references to this cheat are removed, |
265 | free(cur); // free the memory. |
266 | break; |
267 | } // *END REMOVE THIS CHEAT* |
268 | |
269 | |
270 | if(!cur->next) // No more cheats to go through(this shouldn't ever happen...) |
271 | return(0); |
272 | prev=cur; |
273 | cur=prev->next; |
274 | x++; |
275 | } |
276 | |
277 | savecheats=1; |
278 | return(1); |
279 | } |
280 | |
281 | void ApplyPeriodicCheats(void) |
282 | { |
283 | struct CHEATF *cur=cheats; |
284 | if(!cur) return; |
285 | |
286 | for(;;) |
287 | { |
288 | if(cur->status) |
289 | if(CheatRPtrs[cur->addr>>10]) |
290 | CheatRPtrs[cur->addr>>10][cur->addr]=cur->val; |
291 | if(cur->next) |
292 | cur=cur->next; |
293 | else |
294 | break; |
295 | } |
296 | } |
297 | |
298 | |
299 | void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int s)) |
300 | { |
301 | struct CHEATF *next=cheats; |
302 | |
303 | while(next) |
304 | { |
305 | if(!callb(next->name,next->addr,next->val,next->status)) break; |
306 | next=next->next; |
307 | } |
308 | } |
309 | |
310 | int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *s) |
311 | { |
312 | struct CHEATF *next=cheats; |
313 | uint32 x=0; |
314 | |
315 | while(next) |
316 | { |
317 | if(x==which) |
318 | { |
319 | if(name) |
320 | *name=next->name; |
321 | if(a) |
322 | *a=next->addr; |
323 | if(v) |
324 | *v=next->val; |
325 | if(s) |
326 | *s=next->status; |
327 | |
328 | return(1); |
329 | } |
330 | next=next->next; |
331 | x++; |
332 | } |
333 | return(0); |
334 | } |
335 | |
336 | /* name can be NULL if the name isn't going to be changed. */ |
337 | /* same goes for a, v, and s(except the values of each one must be <0) */ |
338 | |
339 | int FCEUI_SetCheat(uint32 which, char *name, int32 a, int32 v, int s) |
340 | { |
341 | struct CHEATF *next=cheats; |
342 | uint32 x=0; |
343 | |
344 | while(next) |
345 | { |
346 | if(x==which) |
347 | { |
348 | if(name) |
349 | { |
350 | char *t; |
351 | |
352 | if((t=realloc(next->name,strlen(name+1)))) |
353 | { |
354 | next->name=t; |
355 | strcpy(next->name,name); |
356 | } |
357 | else |
358 | return(0); |
359 | } |
360 | if(a>=0) |
361 | next->addr=a; |
362 | if(v>=0) |
363 | next->val=v; |
364 | if(s>=0) |
365 | next->status=s; |
366 | savecheats=1; |
367 | return(1); |
368 | } |
369 | next=next->next; |
370 | x++; |
371 | } |
372 | return(0); |
373 | } |
374 | |
375 | |
376 | static int InitCheatComp(void) |
377 | { |
378 | uint32 x; |
379 | |
380 | CheatComp=malloc(65536*sizeof(uint16)); |
381 | if(!CheatComp) |
382 | { |
383 | CheatMemErr(); |
384 | return(0); |
385 | } |
386 | for(x=0;x<65536;x++) |
387 | CheatComp[x]=CHEATC_NONE; |
388 | |
389 | return(1); |
390 | } |
391 | |
392 | void FCEUI_CheatSearchSetCurrentAsOriginal(void) |
393 | { |
394 | uint32 x; |
395 | for(x=0x000;x<0x10000;x++) |
396 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
397 | { |
398 | if(CheatRPtrs[x>>10]) |
399 | CheatComp[x]=CheatRPtrs[x>>10][x]; |
400 | else |
401 | CheatComp[x]|=CHEATC_NONE; |
402 | } |
403 | } |
404 | |
405 | void FCEUI_CheatSearchShowExcluded(void) |
406 | { |
407 | uint32 x; |
408 | |
409 | for(x=0x000;x<0x10000;x++) |
410 | CheatComp[x]&=~CHEATC_EXCLUDED; |
411 | } |
412 | |
413 | |
414 | int32 FCEUI_CheatSearchGetCount(void) |
415 | { |
416 | uint32 x,c=0; |
417 | |
418 | if(CheatComp) |
419 | { |
420 | for(x=0x0000;x<0x10000;x++) |
421 | if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) |
422 | c++; |
423 | } |
424 | |
425 | return c; |
426 | } |
427 | /* This function will give the initial value of the search and the current value at a location. */ |
428 | |
429 | void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current)) |
430 | { |
431 | uint32 x; |
432 | |
433 | if(!CheatComp) |
434 | { |
435 | if(!InitCheatComp()) |
436 | CheatMemErr(); |
437 | return; |
438 | } |
439 | |
440 | for(x=0;x<0x10000;x++) |
441 | if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) |
442 | if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x])) |
443 | break; |
444 | } |
445 | |
446 | void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current)) |
447 | { |
448 | uint32 x; |
449 | uint32 in=0; |
450 | |
451 | if(!CheatComp) |
452 | { |
453 | if(!InitCheatComp()) |
454 | CheatMemErr(); |
455 | return; |
456 | } |
457 | |
458 | for(x=0;x<0x10000;x++) |
459 | if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) |
460 | { |
461 | if(in>=first) |
462 | if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x])) |
463 | break; |
464 | in++; |
465 | if(in>last) return; |
466 | } |
467 | } |
468 | |
469 | void FCEUI_CheatSearchBegin(void) |
470 | { |
471 | uint32 x; |
472 | |
473 | if(!CheatComp) |
474 | { |
475 | if(!InitCheatComp()) |
476 | { |
477 | CheatMemErr(); |
478 | return; |
479 | } |
480 | } |
481 | for(x=0;x<0x10000;x++) |
482 | { |
483 | if(CheatRPtrs[x>>10]) |
484 | CheatComp[x]=CheatRPtrs[x>>10][x]; |
485 | else |
486 | CheatComp[x]=CHEATC_NONE; |
487 | } |
488 | } |
489 | |
490 | |
491 | static int INLINE CAbs(int x) |
492 | { |
493 | if(x<0) |
494 | return(0-x); |
495 | return x; |
496 | } |
497 | |
498 | void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) |
499 | { |
500 | uint32 x; |
501 | |
502 | if(!CheatComp) |
503 | { |
504 | if(!InitCheatComp()) |
505 | { |
506 | CheatMemErr(); |
507 | return; |
508 | } |
509 | } |
510 | |
511 | |
512 | if(!type) // Change to a specific value. |
513 | { |
514 | for(x=0;x<0x10000;x++) |
515 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
516 | { |
517 | if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2) |
518 | { |
519 | |
520 | } |
521 | else |
522 | CheatComp[x]|=CHEATC_EXCLUDED; |
523 | } |
524 | } |
525 | else if(type==1) // Search for relative change(between values). |
526 | { |
527 | for(x=0;x<0x10000;x++) |
528 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
529 | { |
530 | if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2) |
531 | { |
532 | |
533 | } |
534 | else |
535 | CheatComp[x]|=CHEATC_EXCLUDED; |
536 | } |
537 | } |
538 | else if(type==2) // Purely relative change. |
539 | { |
540 | for(x=0x000;x<0x10000;x++) |
541 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
542 | { |
543 | if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2) |
544 | { |
545 | |
546 | } |
547 | else |
548 | CheatComp[x]|=CHEATC_EXCLUDED; |
549 | } |
550 | } |
551 | else if(type==3) // Any change. |
552 | { |
553 | for(x=0x000;x<0x10000;x++) |
554 | if(!(CheatComp[x]&CHEATC_NOSHOW)) |
555 | { |
556 | if(CheatComp[x]!=CheatRPtrs[x>>10][x]) |
557 | { |
558 | |
559 | } |
560 | else |
561 | CheatComp[x]|=CHEATC_EXCLUDED; |
562 | } |
563 | |
564 | } |
565 | } |