1 /*********************************************************************
2
3 cheat.c
4
5 This is a massively rewritten version of the cheat engine. There
6 are still quite a few features that are broken or not reimplemented.
7
8 Busted (probably permanently) is the ability to use the UI_CONFIGURE
9 key to pop the menu system on and off while retaining the current
10 menu selection. The sheer number of submenus involved makes this
11 a difficult task to pull off here.
12
13 TODO:
14
15 * comment cheats
16 * memory searches
17 * saving of cheats to a file
18 * inserting/deleting new cheats
19 * cheats as watchpoints
20 * key shortcuts to the search menus
21
22 (Description from Pugsy's cheat.dat)
23
24 ; all fields are separated by a colon (:)
25 ; -Name of the game (short name) [zip file or directory]
26 ; -No of the CPU usually 0, only different in multiple CPU games
27 ; -Address in Hexadecimal (where to poke)
28 ; -Data to put at this address in hexadecimal (what to poke)
29 ; -Special (see below) usually 000
30 ; -000 : the byte is poked every time and the cheat remains in active list.
31 ; -001 : the byte is poked once and the cheat is removed from active list.
32 ; -002 : the byte is poked every one second and the cheat remains in active
33 ; list.
34 ; -003 : the byte is poked every two seconds and the cheat remains in active
35 ; list.
36 ; -004 : the byte is poked every five seconds and the cheat remains in active
37 ; list.
38 ; -005 : the byte is poked one second after the original value has changed
39 ; and the cheat remains in active list.
40 ; -006 : the byte is poked two seconds after the original value has changed
41 ; and the cheat remains in active list.
42 ; -007 : the byte is poked five seconds after the original value has changed
43 ; and the cheat remains in active list.
44 ; -008 : the byte is poked unless the original value in being decremented by
45 ; 1 each frame and the cheat remains in active list.
46 ; -009 : the byte is poked unless the original value in being decremented by
47 ; 2 each frame and the cheat remains in active list.
48 ; -010 : the byte is poked unless the original value in being decremented by
49 ; 3 each frame and the cheat remains in active list.
50 ; -011 : the byte is poked unless the original value in being decremented by
51 ; 4 each frame and the cheat remains in active list.
52 ; -020 : the bits are set every time and the cheat remains in active list.
53 ; -021 : the bits are set once and the cheat is removed from active list.
54 ; -040 : the bits are reset every time and the cheat remains in active list.
55 ; -041 : the bits are reset once and the cheat is removed from active list.
56 ; -060 : the user selects a decimal value from 0 to byte
57 ; (display : 0 to byte) - the value is poked once when it changes and
58 ; the cheat is removed from the active list.
59 ; -061 : the user selects a decimal value from 0 to byte
60 ; (display : 1 to byte+1) - the value is poked once when it changes
61 ; and the cheat is removed from the active list.
62 ; -062 : the user selects a decimal value from 1 to byte
63 ; (display : 1 to byte) - the value is poked once when it changes and
64 ; the cheat is removed from the active list.
65 ; -063 : the user selects a BCD value from 0 to byte
66 ; (display : 0 to byte) - the value is poked once when it changes and
67 ; the cheat is removed from the active list.
68 ; -064 : the user selects a BCD value from 0 to byte
69 ; (display : 1 to byte+1) - the value is poked once when it changes
70 ; and the cheat is removed from the active list.
71 ; -065 : the user selects a decimal value from 1 to byte
72 ; (display : 1 to byte) - the value is poked once when it changes and
73 ; the cheat is removed from the active list.
74 ; -070 : the user selects a decimal value from 0 to byte
75 ; (display : 0 to byte) - the value is poked once and the cheat is
76 ; removed from the active list.
77 ; -071 : the user selects a decimal value from 0 to byte
78 ; (display : 1 to byte+1) - the value is poked once and the cheat is
79 ; removed from the active list.
80 ; -072 : the user selects a decimal value from 1 to byte
81 ; (display : 1 to byte) - the value is poked once and the cheat is
82 ; removed from the active list.
83 ; -073 : the user selects a BCD value from 0 to byte
84 ; (display : 0 to byte) - the value is poked once and the cheat is
85 ; removed from the active list.
86 ; -074 : the user selects a BCD value from 0 to byte
87 ; (display : 1 to byte+1) - the value is poked once and the cheat is
88 ; removed from the active list.
89 ; -075 : the user selects a decimal value from 1 to byte
90 ; (display : 1 to byte) - the value is poked once and the cheat is
91 ; removed from the active list.
92 ; -500 to 575: These cheat types are identical to types 000 to 075 except
93 ; they are used in linked cheats (i.e. of 1/8 type). The first
94 ; cheat in the link list will be the normal type (eg type 000)
95 ; and the remaining cheats (eg 2/8...8/8) will be of this type
96 ; (eg type 500).
97 ; -998 : this is used as a watch cheat, ideal for showing answers in quiz
98 ; games .
99 ; -999 : this is used for comments only, cannot be enabled/selected by the
100 ; user.
101 ; -Name of the cheat
102 ; -Description for the cheat
103
104 *********************************************************************/
105
106 #include "driver.h"
107 #include "ui_text.h"
108
109 #ifndef MESS
110 #ifdef NEOMAME
111 extern struct GameDriver driver_neogeo;
112 #endif
113 #endif
114
115 extern unsigned char *memory_find_base (int cpu, int offset);
116
117 /******************************************
118 *
119 * Cheats
120 *
121 */
122
123 #define MAX_LOADEDCHEATS 200
124 #define CHEAT_FILENAME_MAXLEN 255
125
126
127 #define SUBCHEAT_FLAG_DONE 0x0001
128 #define SUBCHEAT_FLAG_TIMED 0x0002
129
130 struct subcheat_struct
131 {
132 int cpu;
133 offs_t address;
134 data_t data;
135 #ifdef MESS
136 data_t olddata; /* old data for code patch when cheat is turned OFF */
137 #endif
138 data_t backup; /* The original value of the memory location, checked against the current */
139 UINT32 code;
140 UINT16 flags;
141 data_t min;
142 data_t max;
143 UINT32 frames_til_trigger; /* the number of frames until this cheat fires (does not change) */
144 UINT32 frame_count; /* decrementing frame counter to determine if cheat should fire */
145 };
146
147 #define CHEAT_FLAG_ACTIVE 0x01
148 #define CHEAT_FLAG_WATCH 0x02
149 #define CHEAT_FLAG_COMMENT 0x04
150
151 struct cheat_struct
152 {
153 #ifdef MESS
154 unsigned int crc; /* CRC of the game */
155 char patch; /* 'C' : code patch - 'D' : data patch */
156 #endif
157 char *name;
158 char *comment;
159 UINT8 flags; /* bit 0 = active, 1 = watchpoint, 2 = comment */
160 int num_sub; /* number of cheat cpu/address/data/code combos for this one cheat */
161 struct subcheat_struct *subcheat; /* a variable-number of subcheats are attached to each "master" cheat */
162 };
163
164 struct memory_struct
165 {
166 int Enabled;
167 char name[40];
168 mem_write_handler handler;
169 };
170
171 enum
172 {
173 kCheatSpecial_Poke = 0,
174 kCheatSpecial_Poke1 = 2,
175 kCheatSpecial_Poke2 = 3,
176 kCheatSpecial_Poke5 = 4,
177 kCheatSpecial_Delay1 = 5,
178 kCheatSpecial_Delay2 = 6,
179 kCheatSpecial_Delay5 = 7,
180 kCheatSpecial_Backup1 = 8,
181 kCheatSpecial_Backup4 = 11,
182 kCheatSpecial_SetBit1 = 22,
183 kCheatSpecial_SetBit2 = 23,
184 kCheatSpecial_SetBit5 = 24,
185 kCheatSpecial_ResetBit1 = 42,
186 kCheatSpecial_ResetBit2 = 43,
187 kCheatSpecial_ResetBit5 = 44,
188 kCheatSpecial_UserFirst = 60,
189 kCheatSpecial_m0d0c = 60, /* minimum value 0, display range 0 to byte, poke when changed */
190 kCheatSpecial_m0d1c = 61, /* minimum value 0, display range 1 to byte+1, poke when changed */
191 kCheatSpecial_m1d1c = 62, /* minimum value 1, display range 1 to byte, poke when changed */
192 kCheatSpecial_m0d0bcdc = 63, /* BCD, minimum value 0, display range 0 to byte, poke when changed */
193 kCheatSpecial_m0d1bcdc = 64, /* BCD, minimum value 0, display range 1 to byte+1, poke when changed */
194 kCheatSpecial_m1d1bcdc = 65, /* BCD, minimum value 1, display range 1 to byte, poke when changed */
195 kCheatSpecial_m0d0 = 70, /* minimum value 0, display range 0 to byte */
196 kCheatSpecial_m0d1 = 71, /* minimum value 0, display range 1 to byte+1 */
197 kCheatSpecial_m1d1 = 72, /* minimum value 1, display range 1 to byte */
198 kCheatSpecial_m0d0bcd = 73, /* BCD, minimum value 0, display range 0 to byte */
199 kCheatSpecial_m0d1bcd = 74, /* BCD, minimum value 0, display range 1 to byte+1 */
200 kCheatSpecial_m1d1bcd = 75, /* BCD, minimum value 1, display range 1 to byte */
201 kCheatSpecial_UserLast = 75,
202 kCheatSpecial_Last = 99,
203 kCheatSpecial_LinkStart = 500, /* only used when loading the database */
204 kCheatSpecial_LinkEnd = 599, /* only used when loading the database */
205 kCheatSpecial_Watch = 998,
206 kCheatSpecial_Comment = 999,
207 kCheatSpecial_Timed = 1000
208 };
209
210 char *cheatfile = "cheat.dat";
211
212 char database[CHEAT_FILENAME_MAXLEN+1];
213
214 int he_did_cheat;
215
216
217 /******************************************
218 *
219 * Searches
220 *
221 */
222
223 /* Defines */
224 #define MAX_SEARCHES 500
225
226 enum {
227 kSearch_None = 0,
228 kSearch_Value = 1,
229 kSearch_Time,
230 kSearch_Energy,
231 kSearch_Bit,
232 kSearch_Byte
233 };
234
235 enum {
236 kRestore_NoInit = 1,
237 kRestore_NoSave,
238 kRestore_Done,
239 kRestore_OK
240 };
241
242 /* Local variables */
243 static int searchType;
244 static int searchCPU;
245 //static int priorSearchCPU; /* Steph */
246 static int searchValue;
247 static int restoreStatus;
248
249 static int fastsearch = 2; /* ?? */
250
251 static struct ExtMemory StartRam[MAX_EXT_MEMORY];
252 static struct ExtMemory BackupRam[MAX_EXT_MEMORY];
253 static struct ExtMemory FlagTable[MAX_EXT_MEMORY];
254
255 static struct ExtMemory OldBackupRam[MAX_EXT_MEMORY];
256 static struct ExtMemory OldFlagTable[MAX_EXT_MEMORY];
257
258 /* Local prototypes */
259 static void reset_table (struct ExtMemory *table);
260
261 /******************************************
262 *
263 * Watchpoints
264 *
265 */
266
267 #define MAX_WATCHES 20
268
269 struct watch_struct
270 {
271 int cheat_num; /* if this watchpoint is tied to a cheat, this is the index into the cheat array. -1 if none */
272 UINT32 address;
273 INT16 cpu;
274 UINT8 num_bytes; /* number of consecutive bytes to display */
275 UINT8 label_type; /* none, address, text */
276 char label[255]; /* optional text label */
277 UINT16 x, y; /* position of watchpoint on screen */
278 };
279
280 static struct watch_struct watches[MAX_WATCHES];
281 static int is_watch_active; /* true if at least one watchpoint is active */
282 static int is_watch_visible; /* we can toggle the visibility for all on or off */
283
284
285
286 /* in hiscore.c */
287 int computer_readmem_byte(int cpu, int addr);
288 void computer_writemem_byte(int cpu, int addr, int value);
289
290 /* Some macros to simplify the code */
291 #define READ_CHEAT computer_readmem_byte (subcheat->cpu, subcheat->address)
292 #define WRITE_CHEAT computer_writemem_byte (subcheat->cpu, subcheat->address, subcheat->data)
293 #define COMPARE_CHEAT (computer_readmem_byte (subcheat->cpu, subcheat->address) != subcheat->data)
294 #define CPU_AUDIO_OFF(index) ((Machine->drv->cpu[index].cpu_type & CPU_AUDIO_CPU) && (Machine->sample_rate == 0))
295
296 /* Steph */
297 #ifdef MESS
298 #define WRITE_OLD_CHEAT computer_writemem_byte (subcheat->cpu, subcheat->address, subcheat->olddata)
299 #endif
300
301 /* Local prototypes */
302 static INT32 DisplayHelpFile (INT32 selected);
303 static INT32 EditCheatMenu (struct osd_bitmap *bitmap, INT32 selected, UINT8 cheatnum);
304 static INT32 CommentMenu (struct osd_bitmap *bitmap, INT32 selected, int cheat_index);
305 static int SkipBank(int CpuToScan, int *BankToScanTable, mem_write_handler handler); /* Steph */
306
307 /* Local variables */
308 /* static int search_started = 0; */
309
310 static int ActiveCheatTotal; /* number of cheats currently active */
311 static int LoadedCheatTotal; /* total number of cheats */
312 static struct cheat_struct CheatTable[MAX_LOADEDCHEATS+1];
313
314 static int CheatEnabled;
315
316 #ifdef MESS
317 /* Function who tries to find a valid game with a CRC */
MatchCRC(unsigned int crc)318 int MatchCRC(unsigned int crc)
319 {
320 int type, id;
321
322 if (!crc)
323 return 1;
324
325 for (type = 0; type < IO_COUNT; type++)
326 {
327 for( id = 0; id < device_count(type); id++ )
328 {
329 if (crc == device_crc(type,id))
330 return 1;
331 }
332 }
333
334 return 0;
335 }
336 #endif
337
338
339
340 /* Function to test if a value is BCD (returns 1) or not (returns 0) */
IsBCD(int ParamValue)341 int IsBCD(int ParamValue)
342 {
343 return(((ParamValue % 0x10 <= 9) & (ParamValue <= 0x99)) ? 1 : 0);
344 }
345
346 /* return a format specifier for printf based on cpu address range */
FormatAddr(int cpu,int addtext)347 static char *FormatAddr(int cpu, int addtext)
348 {
349 static char bufadr[10];
350 static char buffer[18];
351 // int i;
352
353 memset (buffer, '\0', strlen(buffer));
354 switch (cpunum_address_bits(cpu) >> 2)
355 {
356 case 4:
357 strcpy (bufadr, "%04X");
358 break;
359 case 5:
360 strcpy (bufadr, "%05X");
361 break;
362 case 6:
363 strcpy (bufadr, "%06X");
364 break;
365 case 7:
366 strcpy (bufadr, "%07X");
367 break;
368 case 8:
369 strcpy (bufadr, "%08X");
370 break;
371 default:
372 strcpy (bufadr, "%X");
373 break;
374 }
375 #if 0
376 if (addtext)
377 {
378 strcpy (buffer, "Addr: ");
379 for (i = strlen(bufadr) + 1; i < 8; i ++)
380 strcat (buffer, " ");
381 }
382 #endif
383 strcat (buffer,bufadr);
384 return buffer;
385 }
386
387 /* Function to rename the cheatfile (returns 1 if the file has been renamed else 0)*/
RenameCheatFile(int merge,int DisplayFileName,char * filename)388 int RenameCheatFile(int merge, int DisplayFileName, char *filename)
389 {
390 return 0;
391 }
392
393 /* Function who loads the cheats for a game */
SaveCheat(int NoCheat)394 int SaveCheat(int NoCheat)
395 {
396 return 0;
397 }
398
399 /***************************************************************************
400
401 cheat_set_code
402
403 Given a cheat code, sets the various attribues of the cheat structure.
404 This is to aid in making the cheat engine more flexible in the event that
405 someday the codes are restructured or the case statement in DoCheat is
406 simplified from its current form.
407
408 ***************************************************************************/
cheat_set_code(struct subcheat_struct * subcheat,int code,int cheat_num)409 void cheat_set_code (struct subcheat_struct *subcheat, int code, int cheat_num)
410 {
411 switch (code)
412 {
413 case kCheatSpecial_Poke1:
414 case kCheatSpecial_Delay1:
415 case kCheatSpecial_SetBit1:
416 case kCheatSpecial_ResetBit1:
417 subcheat->frames_til_trigger = 1 * Machine->drv->frames_per_second; /* was 60 */
418 break;
419 case kCheatSpecial_Poke2:
420 case kCheatSpecial_Delay2:
421 case kCheatSpecial_SetBit2:
422 case kCheatSpecial_ResetBit2:
423 subcheat->frames_til_trigger = 2 * Machine->drv->frames_per_second; /* was 60 */
424 break;
425 case kCheatSpecial_Poke5:
426 case kCheatSpecial_Delay5:
427 case kCheatSpecial_SetBit5:
428 case kCheatSpecial_ResetBit5:
429 subcheat->frames_til_trigger = 5 * Machine->drv->frames_per_second; /* was 60 */
430 break;
431 case kCheatSpecial_Comment:
432 subcheat->frames_til_trigger = 0;
433 subcheat->address = 0;
434 subcheat->data = 0;
435 CheatTable[cheat_num].flags |= CHEAT_FLAG_COMMENT;
436 break;
437 case kCheatSpecial_Watch:
438 subcheat->frames_til_trigger = 0;
439 subcheat->data = 0;
440 CheatTable[cheat_num].flags |= CHEAT_FLAG_WATCH;
441 break;
442 default:
443 subcheat->frames_til_trigger = 0;
444 break;
445 }
446
447 /* Set the minimum value */
448 if ((code == kCheatSpecial_m1d1c) ||
449 (code == kCheatSpecial_m1d1bcdc) ||
450 (code == kCheatSpecial_m1d1) ||
451 (code == kCheatSpecial_m1d1bcd))
452 subcheat->min = 1;
453 else
454 subcheat->min = 0;
455
456 /* Set the maximum value */
457 if ((code >= kCheatSpecial_UserFirst) &&
458 (code <= kCheatSpecial_UserLast))
459 {
460 subcheat->max = subcheat->data;
461 subcheat->data = 0;
462 }
463 else
464 subcheat->max = 0xff;
465
466 subcheat->code = code;
467 }
468
469 /***************************************************************************
470
471 cheat_set_status
472
473 Given an index into the cheat table array, make the selected cheat
474 either active or inactive.
475
476 TODO: possibly support converting to a watchpoint in here.
477
478 ***************************************************************************/
cheat_set_status(int cheat_num,int active)479 void cheat_set_status (int cheat_num, int active)
480 {
481 int i;
482
483 if (active) /* enable the cheat */
484 {
485 for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
486 {
487 /* Reset the active variables */
488 CheatTable[cheat_num].subcheat[i].frame_count = 0;
489 CheatTable[cheat_num].subcheat[i].backup = 0;
490 }
491
492 /* only add if there's a cheat active already */
493 if ((CheatTable[cheat_num].flags & CHEAT_FLAG_ACTIVE) == 0)
494 {
495 CheatTable[cheat_num].flags |= CHEAT_FLAG_ACTIVE;
496 ActiveCheatTotal++;
497 }
498
499 /* tell the MAME core that we're cheaters! */
500 he_did_cheat = 1;
501 }
502 else /* disable the cheat (case 0, 2) */
503 {
504 for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
505 {
506 // struct subcheat_struct *subcheat = &CheatTable[cheat_num].subcheat[i]; /* Steph */
507
508 /* Reset the active variables */
509 CheatTable[cheat_num].subcheat[i].frame_count = 0;
510 CheatTable[cheat_num].subcheat[i].backup = 0;
511
512 #ifdef MESS
513 /* Put the original code if it is a code patch */
514 if (CheatTable[cheat_num].patch == 'C')
515 WRITE_OLD_CHEAT;
516 #endif
517
518 }
519
520 /* only add if there's a cheat active already */
521 if (CheatTable[cheat_num].flags & CHEAT_FLAG_ACTIVE)
522 {
523 CheatTable[cheat_num].flags &= ~CHEAT_FLAG_ACTIVE;
524 ActiveCheatTotal--;
525 }
526 }
527 }
528
cheat_insert_new(int cheat_num)529 void cheat_insert_new (int cheat_num)
530 {
531 /* if list is full, bail */
532 if (LoadedCheatTotal == MAX_LOADEDCHEATS) return;
533
534 /* if the index is off the end of the list, fix it */
535 if (cheat_num > LoadedCheatTotal) cheat_num = LoadedCheatTotal;
536
537 /* clear space in the middle of the table if needed */
538 if (cheat_num < LoadedCheatTotal)
539 memmove (&CheatTable[cheat_num+1], &CheatTable[cheat_num], sizeof (struct cheat_struct) * (LoadedCheatTotal - cheat_num));
540
541 /* clear the new entry */
542 memset (&CheatTable[cheat_num], 0, sizeof (struct cheat_struct));
543
544 CheatTable[cheat_num].name = (char*)malloc(strlen (ui_getstring(UI_none)) + 1);
545 strcpy (CheatTable[cheat_num].name, ui_getstring(UI_none));
546
547 CheatTable[cheat_num].subcheat = calloc(1, sizeof (struct subcheat_struct));
548
549 /*add one to the total */
550 LoadedCheatTotal ++;
551 }
552
cheat_delete(int cheat_num)553 void cheat_delete (int cheat_num)
554 {
555 /* if the index is off the end, make it the last one */
556 if (cheat_num >= LoadedCheatTotal) cheat_num = LoadedCheatTotal - 1;
557
558 /* deallocate storage for the cheat */
559 free(CheatTable[cheat_num].name);
560 free(CheatTable[cheat_num].comment);
561 free(CheatTable[cheat_num].subcheat);
562
563 /* If it's active, decrease the count */
564 if (CheatTable[cheat_num].flags & CHEAT_FLAG_ACTIVE)
565 ActiveCheatTotal --;
566
567 /* move all the elements after this one up one slot if there are more than 1 and it's not the last */
568 if ((LoadedCheatTotal > 1) && (cheat_num < LoadedCheatTotal - 1))
569 memmove (&CheatTable[cheat_num], &CheatTable[cheat_num+1], sizeof (struct cheat_struct) * (LoadedCheatTotal - (cheat_num + 1)));
570
571 /* knock one off the total */
572 LoadedCheatTotal --;
573 }
574
subcheat_insert_new(int cheat_num,int subcheat_num)575 void subcheat_insert_new (int cheat_num, int subcheat_num)
576 {
577 /* if the index is off the end of the list, fix it */
578 if (subcheat_num > CheatTable[cheat_num].num_sub) subcheat_num = CheatTable[cheat_num].num_sub + 1;
579
580 /* grow the subcheat table allocation */
581 CheatTable[cheat_num].subcheat = realloc(CheatTable[cheat_num].subcheat, sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub + 2));
582 if (CheatTable[cheat_num].subcheat == NULL) return;
583
584 /* insert space in the middle of the table if needed */
585 if ((subcheat_num < CheatTable[cheat_num].num_sub) || (subcheat_num == 0))
586 memmove (&CheatTable[cheat_num].subcheat[subcheat_num+1], &CheatTable[cheat_num].subcheat[subcheat_num],
587 sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub + 1 - subcheat_num));
588
589 /* clear the new entry */
590 memset (&CheatTable[cheat_num].subcheat[subcheat_num], 0, sizeof (struct subcheat_struct));
591
592 /*add one to the total */
593 CheatTable[cheat_num].num_sub ++;
594 }
595
subcheat_delete(int cheat_num,int subcheat_num)596 void subcheat_delete (int cheat_num, int subcheat_num)
597 {
598 if (CheatTable[cheat_num].num_sub < 1) return;
599 /* if the index is off the end, make it the last one */
600 if (subcheat_num > CheatTable[cheat_num].num_sub) subcheat_num = CheatTable[cheat_num].num_sub;
601
602 /* remove the element in the middle if it's not the last */
603 if (subcheat_num < CheatTable[cheat_num].num_sub)
604 memmove (&CheatTable[cheat_num].subcheat[subcheat_num], &CheatTable[cheat_num].subcheat[subcheat_num+1],
605 sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub - subcheat_num));
606
607 /* shrink the subcheat table allocation */
608 CheatTable[cheat_num].subcheat = realloc(CheatTable[cheat_num].subcheat, sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub));
609 if (CheatTable[cheat_num].subcheat == NULL) return;
610
611 /* knock one off the total */
612 CheatTable[cheat_num].num_sub --;
613 }
614
615 /* Function to load the cheats for a game from a single database */
LoadCheatFile(int merge,char * filename)616 void LoadCheatFile (int merge, char *filename)
617 {
618 void *f = osd_fopen (NULL, filename, OSD_FILETYPE_CHEAT, 0);
619 char curline[2048];
620 int name_length;
621 struct subcheat_struct *subcheat;
622 int sub = 0;
623
624 if (!merge)
625 {
626 ActiveCheatTotal = 0;
627 LoadedCheatTotal = 0;
628 }
629
630 //printf("abro fichero cheats\n");
631 if (!f) return;
632 //printf("OK\n");
633
634 name_length = strlen (Machine->gamedrv->name);
635
636 /* Load the cheats for that game */
637 /* Ex.: pacman:0:4E14:06:000:1UP Unlimited lives:Coded on 1 byte */
638 while ((osd_fgets (curline, 2048, f) != NULL) && (LoadedCheatTotal < MAX_LOADEDCHEATS))
639 {
640 char *ptr;
641 int temp_cpu;
642 #ifdef MESS
643 unsigned int temp_crc;
644 char temp_patch;
645 #endif
646 offs_t temp_address;
647 data_t temp_data;
648 #ifdef MESS
649 data_t temp_olddata;
650 #endif
651 INT32 temp_code;
652
653
654 /* Take a few easy-out cases to speed things up */
655 if (curline[name_length] != ':') continue;
656 if (strncmp (curline, Machine->gamedrv->name, name_length) != 0) continue;
657 if (curline[0] == ';') continue;
658
659 #if 0
660 if (sologame)
661 if ((strstr(str, "2UP") != NULL) || (strstr(str, "PL2") != NULL) ||
662 (strstr(str, "3UP") != NULL) || (strstr(str, "PL3") != NULL) ||
663 (strstr(str, "4UP") != NULL) || (strstr(str, "PL4") != NULL) ||
664 (strstr(str, "2up") != NULL) || (strstr(str, "pl2") != NULL) ||
665 (strstr(str, "3up") != NULL) || (strstr(str, "pl3") != NULL) ||
666 (strstr(str, "4up") != NULL) || (strstr(str, "pl4") != NULL))
667 continue;
668 #endif
669
670 /* Extract the fields from the line */
671 /* Skip the driver name */
672 ptr = strtok(curline, ":");
673 if (!ptr) continue;
674
675 #ifdef MESS
676 /* CRC */
677 ptr = strtok(NULL, ":");
678 if (!ptr) continue;
679 sscanf(ptr,"%x", &temp_crc);
680 if (! MatchCRC(temp_crc))
681 continue;
682
683 /* Patch */
684 ptr = strtok(NULL, ":");
685 if (!ptr) continue;
686 sscanf(ptr,"%c", &temp_patch);
687 if (temp_patch != 'C')
688 temp_patch = 'D';
689
690 #endif
691
692 /* CPU number */
693 ptr = strtok(NULL, ":");
694 if (!ptr) continue;
695 sscanf(ptr,"%d", &temp_cpu);
696 // /* skip if it's a sound cpu and the audio is off */
697 // if (CPU_AUDIO_OFF(temp_cpu)) continue;
698 /* skip if this is a bogus CPU */
699 if (temp_cpu >= cpu_gettotalcpu()) continue;
700
701 /* Address */
702 ptr = strtok(NULL, ":");
703 if (!ptr) continue;
704 sscanf(ptr,"%X", &temp_address);
705 temp_address &= cpunum_address_mask(temp_cpu);
706
707 /* data byte */
708 ptr = strtok(NULL, ":");
709 if (!ptr) continue;
710 sscanf(ptr,"%x", &temp_data);
711 temp_data &= 0xff;
712
713 #ifdef MESS
714 /* old data byte */
715 ptr = strtok(NULL, ":");
716 if (!ptr) continue;
717 sscanf(ptr,"%x", &temp_olddata);
718 temp_olddata &= 0xff;
719 #endif
720
721 /* special code */
722 ptr = strtok(NULL, ":");
723 if (!ptr) continue;
724 sscanf(ptr,"%d", &temp_code);
725
726 /* Is this a subcheat? */
727 if ((temp_code >= kCheatSpecial_LinkStart) &&
728 (temp_code <= kCheatSpecial_LinkEnd))
729 {
730 sub ++;
731
732 /* Adjust the special flag */
733 temp_code -= kCheatSpecial_LinkStart;
734
735 /* point to the last valid main cheat entry */
736 LoadedCheatTotal --;
737 }
738 else
739 {
740 /* no, make this the first cheat in the series */
741 sub = 0;
742 }
743
744 /* Allocate (or resize) storage for the subcheat array */
745 CheatTable[LoadedCheatTotal].subcheat = realloc(CheatTable[LoadedCheatTotal].subcheat, sizeof (struct subcheat_struct) * (sub + 1));
746 if (CheatTable[LoadedCheatTotal].subcheat == NULL) continue;
747
748 /* Store the current number of subcheats embodied by this code */
749 CheatTable[LoadedCheatTotal].num_sub = sub;
750
751 subcheat = &CheatTable[LoadedCheatTotal].subcheat[sub];
752
753 /* Reset the cheat */
754 subcheat->frames_til_trigger = 0;
755 subcheat->frame_count = 0;
756 subcheat->backup = 0;
757 subcheat->flags = 0;
758
759 /* Copy the cheat data */
760 subcheat->cpu = temp_cpu;
761
762 subcheat->address = temp_address;
763 subcheat->data = temp_data;
764 #ifdef MESS
765 subcheat->olddata = temp_olddata;
766 #endif
767 subcheat->code = temp_code;
768
769 cheat_set_code (subcheat, temp_code, LoadedCheatTotal);
770
771 /* don't bother with the names & comments for subcheats */
772 if (sub) goto next;
773
774 #ifdef MESS
775 /* CRC */
776 CheatTable[LoadedCheatTotal].crc = temp_crc;
777 /* Patch */
778 CheatTable[LoadedCheatTotal].patch = temp_patch;
779 #endif
780 /* Disable the cheat */
781 CheatTable[LoadedCheatTotal].flags &= ~CHEAT_FLAG_ACTIVE;
782
783 /* cheat name */
784 CheatTable[LoadedCheatTotal].name = NULL;
785 ptr = strtok(NULL, ":");
786 if (!ptr) continue;
787
788 /* Allocate storage and copy the name */
789 CheatTable[LoadedCheatTotal].name = (char*)malloc(strlen (ptr) + 1);
790 strcpy (CheatTable[LoadedCheatTotal].name,ptr);
791
792 /* Strip line-ending if needed */
793 if (strstr(CheatTable[LoadedCheatTotal].name,"\n") != NULL)
794 CheatTable[LoadedCheatTotal].name[strlen(CheatTable[LoadedCheatTotal].name)-1] = 0;
795
796 /* read the "comment" field if there */
797 ptr = strtok(NULL, ":");
798 if (ptr)
799 {
800 /* Allocate storage and copy the comment */
801 CheatTable[LoadedCheatTotal].comment = (char*)malloc(strlen (ptr) + 1);
802 strcpy(CheatTable[LoadedCheatTotal].comment,ptr);
803
804 /* Strip line-ending if needed */
805 if (strstr(CheatTable[LoadedCheatTotal].comment,"\n") != NULL)
806 CheatTable[LoadedCheatTotal].comment[strlen(CheatTable[LoadedCheatTotal].comment)-1] = 0;
807 }
808 else
809 CheatTable[LoadedCheatTotal].comment = NULL;
810
811 next:
812 LoadedCheatTotal ++;
813 }
814
815 osd_fclose (f);
816 }
817
818 /* Function who loads the cheats for a game from many databases */
LoadCheatFiles(void)819 void LoadCheatFiles (void)
820 {
821 char *ptr;
822 char str[CHEAT_FILENAME_MAXLEN+1];
823 char filename[CHEAT_FILENAME_MAXLEN+1];
824
825 int pos1, pos2;
826
827 ActiveCheatTotal = 0;
828 LoadedCheatTotal = 0;
829
830 /* start off with the default cheat file, cheat.dat */
831 strcpy (str, cheatfile);
832 ptr = strtok (str, ";");
833
834 /* append any additional cheat files */
835 strcpy (database, ptr);
836 strcpy (str, cheatfile);
837 str[strlen (str) + 1] = 0;
838 pos1 = 0;
839 while (str[pos1])
840 {
841 pos2 = pos1;
842 while ((str[pos2]) && (str[pos2] != ';'))
843 pos2++;
844 if (pos1 != pos2)
845 {
846 memset (filename, '\0', sizeof(filename));
847 strncpy (filename, &str[pos1], (pos2 - pos1));
848 LoadCheatFile (1, filename);
849 pos1 = pos2 + 1;
850 }
851 }
852 }
853
854 #if 0
855 void InitMemoryAreas(void)
856 {
857 const struct MemoryWriteAddress *mwa = Machine->drv->cpu[Searchcpu].memory_write;
858 char buffer[40];
859
860 MemoryAreasSelected = 0;
861 MemoryAreasTotal = 0;
862
863 while (mwa->start != -1)
864 {
865 sprintf (buffer, FormatAddr(Searchcpu,0), mwa->start);
866 strcpy (MemToScanTable[MemoryAreasTotal].Name, buffer);
867 strcat (MemToScanTable[MemoryAreasTotal].Name," -> ");
868 sprintf (buffer, FormatAddr(Searchcpu,0), mwa->end);
869 strcat (MemToScanTable[MemoryAreasTotal].Name, buffer);
870 MemToScanTable[MemoryAreasTotal].handler = mwa->handler;
871 MemToScanTable[MemoryAreasTotal].Enabled = 0;
872 MemoryAreasTotal++;
873 mwa++;
874 }
875 }
876 #endif
877
878 /* Init some variables */
InitCheat(void)879 void InitCheat(void)
880 {
881 int i;
882
883 he_did_cheat = 0;
884 CheatEnabled = 1;
885
886 /* set up the search tables */
887 reset_table (StartRam);
888 reset_table (BackupRam);
889 reset_table (FlagTable);
890 reset_table (OldBackupRam);
891 reset_table (OldFlagTable);
892
893 restoreStatus = kRestore_NoInit;
894
895 /* Reset the watchpoints to their defaults */
896 is_watch_active = 0;
897 is_watch_visible = 1;
898
899 for (i = 0;i < MAX_WATCHES;i ++)
900 {
901 /* disable this watchpoint */
902 watches[i].num_bytes = 0;
903
904 watches[i].cpu = 0;
905 watches[i].label[0] = 0x00;
906 watches[i].label_type = 0;
907 watches[i].address = 0;
908
909 /* set the screen position */
910 watches[i].x = 0;
911 watches[i].y = i * Machine->uifontheight;
912 }
913
914 LoadCheatFiles ();
915 /* InitMemoryAreas(); */
916 }
917
918 #ifdef macintosh
919 #pragma mark -
920 #endif
921
EnableDisableCheatMenu(struct osd_bitmap * bitmap,INT32 selected)922 INT32 EnableDisableCheatMenu (struct osd_bitmap *bitmap, INT32 selected)
923 {
924 int sel;
925 static INT8 submenu_choice;
926 const char *menu_item[MAX_LOADEDCHEATS + 2];
927 const char *menu_subitem[MAX_LOADEDCHEATS];
928 char buf[MAX_LOADEDCHEATS][80];
929 char buf2[MAX_LOADEDCHEATS][10];
930 static int tag[MAX_LOADEDCHEATS];
931 int i, total = 0;
932
933
934 sel = selected - 1;
935
936 /* If a submenu has been selected, go there */
937 if (submenu_choice)
938 {
939 submenu_choice = CommentMenu (bitmap, submenu_choice, tag[sel]);
940 if (submenu_choice == -1)
941 {
942 submenu_choice = 0;
943 sel = -2;
944 }
945
946 return sel + 1;
947 }
948
949 /* No submenu active, do the watchpoint menu */
950 for (i = 0; i < LoadedCheatTotal; i ++)
951 {
952 int string_num;
953
954 if (CheatTable[i].comment && (CheatTable[i].comment[0] != 0x00))
955 {
956 sprintf (buf[total], "%s (%s...)", CheatTable[i].name, ui_getstring (UI_moreinfo));
957 }
958 else
959 sprintf (buf[total], "%s", CheatTable[i].name);
960
961 tag[total] = i;
962 menu_item[total] = buf[total];
963
964 /* add submenu options for all cheats that are not comments */
965 if ((CheatTable[i].flags & CHEAT_FLAG_COMMENT) == 0)
966 {
967 if (CheatTable[i].flags & CHEAT_FLAG_ACTIVE)
968 string_num = UI_on;
969 else
970 string_num = UI_off;
971 sprintf (buf2[total], "%s", ui_getstring (string_num));
972 menu_subitem[total] = buf2[total];
973 }
974 else
975 menu_subitem[total] = NULL;
976 total ++;
977 }
978
979 menu_item[total] = ui_getstring (UI_returntoprior);
980 menu_subitem[total++] = NULL;
981 menu_item[total] = 0; /* terminate array */
982
983 ui_displaymenu(bitmap,menu_item,menu_subitem,0,sel,0);
984
985 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
986 sel = (sel + 1) % total;
987
988 if (input_ui_pressed_repeat(IPT_UI_UP,8))
989 sel = (sel + total - 1) % total;
990
991 if ((input_ui_pressed_repeat(IPT_UI_LEFT,8)) || (input_ui_pressed_repeat(IPT_UI_RIGHT,8)))
992 {
993 if ((CheatTable[tag[sel]].flags & CHEAT_FLAG_COMMENT) == 0)
994 {
995 int active = CheatTable[tag[sel]].flags & CHEAT_FLAG_ACTIVE;
996
997 active ^= 0x01;
998
999 cheat_set_status (tag[sel], active);
1000 CheatEnabled = 1;
1001 }
1002 }
1003
1004
1005 if (input_ui_pressed(IPT_UI_SELECT))
1006 {
1007 if (sel == (total - 1))
1008 {
1009 /* return to prior menu */
1010 submenu_choice = 0;
1011 sel = -1;
1012 }
1013 else
1014 {
1015 if (CheatTable[tag[sel]].comment && (CheatTable[tag[sel]].comment[0] != 0x00))
1016 {
1017 submenu_choice = 1;
1018 /* tell updatescreen() to clean after us */
1019 need_to_clear_bitmap = 1;
1020 }
1021 }
1022 }
1023
1024 /* Cancel pops us up a menu level */
1025 if (input_ui_pressed(IPT_UI_CANCEL))
1026 sel = -1;
1027
1028 /* The UI key takes us all the way back out */
1029 if (input_ui_pressed(IPT_UI_CONFIGURE))
1030 sel = -2;
1031
1032 if (sel == -1 || sel == -2)
1033 {
1034 /* tell updatescreen() to clean after us */
1035 need_to_clear_bitmap = 1;
1036 }
1037
1038 return sel + 1;
1039 }
1040
CommentMenu(struct osd_bitmap * bitmap,INT32 selected,int cheat_index)1041 static INT32 CommentMenu (struct osd_bitmap *bitmap, INT32 selected, int cheat_index)
1042 {
1043 char buf[2048];
1044 char buf2[256];
1045 int sel;
1046
1047
1048 sel = selected - 1;
1049
1050 buf[0] = 0;
1051
1052 if (CheatTable[cheat_index].comment[0] == 0x00)
1053 {
1054 sel = -1;
1055 buf[0] = 0;
1056 }
1057 else
1058 {
1059 sprintf (buf2, "\t%s\n\t%s\n\n", ui_getstring (UI_moreinfoheader), CheatTable[cheat_index].name);
1060 strcpy (buf, buf2);
1061 strcat (buf, CheatTable[cheat_index].comment);
1062 }
1063
1064 /* menu system, use the normal menu keys */
1065 strcat(buf,"\n\n\t");
1066 strcat(buf,ui_getstring (UI_lefthilight));
1067 strcat(buf," ");
1068 strcat(buf,ui_getstring (UI_returntoprior));
1069 strcat(buf," ");
1070 strcat(buf,ui_getstring (UI_righthilight));
1071
1072 ui_displaymessagewindow(bitmap, buf);
1073
1074 if (input_ui_pressed(IPT_UI_SELECT))
1075 sel = -1;
1076
1077 if (input_ui_pressed(IPT_UI_CANCEL))
1078 sel = -1;
1079
1080 if (input_ui_pressed(IPT_UI_CONFIGURE))
1081 sel = -2;
1082
1083 if (sel == -1 || sel == -2)
1084 {
1085 /* tell updatescreen() to clean after us */
1086 need_to_clear_bitmap = 1;
1087 }
1088
1089 return sel + 1;
1090 }
1091
AddEditCheatMenu(struct osd_bitmap * bitmap,INT32 selected)1092 INT32 AddEditCheatMenu (struct osd_bitmap *bitmap, INT32 selected)
1093 {
1094 int sel;
1095 static INT8 submenu_choice;
1096 const char *menu_item[MAX_LOADEDCHEATS + 4];
1097 // char buf[MAX_LOADEDCHEATS][80];
1098 // char buf2[MAX_LOADEDCHEATS][10];
1099 int tag[MAX_LOADEDCHEATS];
1100 int i, total = 0;
1101
1102
1103 sel = selected - 1;
1104
1105 /* Set up the "tag" table so we know which cheats belong in the menu */
1106 for (i = 0; i < LoadedCheatTotal; i ++)
1107 {
1108 /* add menu listings for all cheats that are not comments */
1109 if (((CheatTable[i].flags & CHEAT_FLAG_COMMENT) == 0)
1110 #ifdef MESS
1111 /* only data patches can be edited within the cheat engine */
1112 && (CheatTable[i].patch == 'D')
1113 #endif
1114 )
1115 {
1116 tag[total] = i;
1117 menu_item[total++] = CheatTable[i].name;
1118 }
1119 }
1120
1121 /* If a submenu has been selected, go there */
1122 if (submenu_choice)
1123 {
1124 submenu_choice = EditCheatMenu (bitmap, submenu_choice, tag[sel]);
1125 if (submenu_choice == -1)
1126 {
1127 submenu_choice = 0;
1128 sel = -2;
1129 }
1130
1131 return sel + 1;
1132 }
1133
1134 /* No submenu active, do the watchpoint menu */
1135 menu_item[total++] = ui_getstring (UI_returntoprior);
1136 menu_item[total] = NULL; /* TODO: add help string */
1137 menu_item[total+1] = 0; /* terminate array */
1138
1139 ui_displaymenu(bitmap,menu_item,0,0,sel,0);
1140
1141 if (code_pressed_memory_repeat (KEYCODE_INSERT, 8))
1142 {
1143 /* add a new cheat at the current position (or the end) */
1144 if (sel < total - 1)
1145 cheat_insert_new (tag[sel]);
1146 else
1147 cheat_insert_new (LoadedCheatTotal);
1148 }
1149
1150 if (code_pressed_memory_repeat (KEYCODE_DEL, 8))
1151 {
1152 if (LoadedCheatTotal)
1153 {
1154 /* delete the selected cheat (or the last one) */
1155 if (sel < total - 1)
1156 cheat_delete (tag[sel]);
1157 else
1158 {
1159 cheat_delete (LoadedCheatTotal - 1);
1160 sel = total - 2;
1161 }
1162 }
1163 }
1164
1165 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
1166 sel = (sel + 1) % total;
1167
1168 if (input_ui_pressed_repeat(IPT_UI_UP,8))
1169 sel = (sel + total - 1) % total;
1170
1171 if (input_ui_pressed(IPT_UI_SELECT))
1172 {
1173 if (sel == (total - 1))
1174 {
1175 /* return to prior menu */
1176 submenu_choice = 0;
1177 sel = -1;
1178 }
1179 else
1180 {
1181 submenu_choice = 1;
1182 /* tell updatescreen() to clean after us */
1183 need_to_clear_bitmap = 1;
1184 }
1185 }
1186
1187 /* Cancel pops us up a menu level */
1188 if (input_ui_pressed(IPT_UI_CANCEL))
1189 sel = -1;
1190
1191 /* The UI key takes us all the way back out */
1192 if (input_ui_pressed(IPT_UI_CONFIGURE))
1193 sel = -2;
1194
1195 if (sel == -1 || sel == -2)
1196 {
1197 /* tell updatescreen() to clean after us */
1198 need_to_clear_bitmap = 1;
1199 }
1200
1201 return sel + 1;
1202 }
1203
EditCheatMenu(struct osd_bitmap * bitmap,INT32 selected,UINT8 cheat_num)1204 static INT32 EditCheatMenu (struct osd_bitmap *bitmap, INT32 selected, UINT8 cheat_num)
1205 {
1206 int sel;
1207 int total, total2;
1208 struct subcheat_struct *subcheat;
1209 static INT8 submenu_choice;
1210 static UINT8 textedit_active;
1211 const char *menu_item[40];
1212 const char *menu_subitem[40];
1213 char setting[40][30];
1214 char flag[40];
1215 int arrowize;
1216 int subcheat_num;
1217 int i;
1218
1219
1220 sel = selected - 1;
1221
1222 total = 0;
1223 /* No submenu active, display the main cheat menu */
1224 menu_item[total++] = ui_getstring (UI_cheatname);
1225 menu_item[total++] = ui_getstring (UI_cheatdescription);
1226 for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
1227 {
1228 menu_item[total++] = ui_getstring (UI_cpu);
1229 menu_item[total++] = ui_getstring (UI_address);
1230 menu_item[total++] = ui_getstring (UI_value);
1231 menu_item[total++] = ui_getstring (UI_code);
1232 }
1233 menu_item[total++] = ui_getstring (UI_returntoprior);
1234 menu_item[total] = 0;
1235
1236 arrowize = 0;
1237
1238 /* set up the submenu selections */
1239 total2 = 0;
1240 for (i = 0; i < 40; i ++)
1241 flag[i] = 0;
1242
1243 /* if we're editing the label, make it inverse */
1244 if (textedit_active)
1245 flag[sel] = 1;
1246
1247 /* name */
1248 if (CheatTable[cheat_num].name != 0x00)
1249 sprintf (setting[total2], "%s", CheatTable[cheat_num].name);
1250 else
1251 strcpy (setting[total2], ui_getstring (UI_none));
1252 menu_subitem[total2] = setting[total2]; total2++;
1253
1254 /* comment */
1255 if (CheatTable[cheat_num].comment && CheatTable[cheat_num].comment != 0x00)
1256 sprintf (setting[total2], "%s...", ui_getstring (UI_moreinfo));
1257 else
1258 strcpy (setting[total2], ui_getstring (UI_none));
1259 menu_subitem[total2] = setting[total2]; total2++;
1260
1261 /* Subcheats */
1262 for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
1263 {
1264 subcheat = &CheatTable[cheat_num].subcheat[i];
1265
1266 /* cpu number */
1267 sprintf (setting[total2], "%d", subcheat->cpu);
1268 menu_subitem[total2] = setting[total2]; total2++;
1269
1270 /* address */
1271 if (cpunum_address_bits(subcheat->cpu) <= 16)
1272 {
1273 sprintf (setting[total2], "%04X", subcheat->address);
1274 }
1275 else
1276 {
1277 sprintf (setting[total2], "%08X", subcheat->address);
1278 }
1279 menu_subitem[total2] = setting[total2]; total2++;
1280
1281 /* value */
1282 sprintf (setting[total2], "%d", subcheat->data);
1283 menu_subitem[total2] = setting[total2]; total2++;
1284
1285 /* code */
1286 sprintf (setting[total2], "%d", subcheat->code);
1287 menu_subitem[total2] = setting[total2]; total2++;
1288
1289 menu_subitem[total2] = NULL;
1290 }
1291
1292 ui_displaymenu(bitmap,menu_item,menu_subitem,flag,sel,arrowize);
1293
1294 if (code_pressed_memory_repeat (KEYCODE_INSERT, 8))
1295 {
1296 if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub + 1) * 4) + 1))
1297 {
1298 subcheat_num = (sel - 2) % 4;
1299 }
1300 else
1301 {
1302 subcheat_num = CheatTable[cheat_num].num_sub + 1;
1303 }
1304
1305 /* add a new subcheat at the current position (or the end) */
1306 subcheat_insert_new (cheat_num, subcheat_num);
1307 }
1308
1309 if (code_pressed_memory_repeat (KEYCODE_DEL, 8))
1310 {
1311 if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub + 1) * 4) + 1))
1312 {
1313 subcheat_num = (sel - 2) % 4;
1314 }
1315 else
1316 {
1317 subcheat_num = CheatTable[cheat_num].num_sub;
1318 }
1319
1320 if (CheatTable[cheat_num].num_sub != 0)
1321 subcheat_delete (cheat_num, subcheat_num);
1322 }
1323
1324 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
1325 {
1326 textedit_active = 0;
1327 sel = (sel + 1) % total;
1328 }
1329
1330 if (input_ui_pressed_repeat(IPT_UI_UP,8))
1331 {
1332 textedit_active = 0;
1333 sel = (sel + total - 1) % total;
1334 }
1335
1336 if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
1337 {
1338 if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub + 1) * 4) + 1))
1339 {
1340 int newsel;
1341
1342 subcheat = &CheatTable[cheat_num].subcheat[(sel - 2) / 4];
1343 newsel = (sel - 2) % 4;
1344
1345 switch (newsel)
1346 {
1347 case 0: /* CPU */
1348 subcheat->cpu --;
1349 /* skip audio CPUs when the sound is off */
1350 if (CPU_AUDIO_OFF(subcheat->cpu))
1351 subcheat->cpu --;
1352 if (subcheat->cpu < 0)
1353 subcheat->cpu = cpu_gettotalcpu() - 1;
1354 subcheat->address &= cpunum_address_mask(subcheat->cpu);
1355 break;
1356 case 1: /* address */
1357 textedit_active = 0;
1358 subcheat->address --;
1359 subcheat->address &= cpunum_address_mask(subcheat->cpu);
1360 break;
1361 case 2: /* value */
1362 textedit_active = 0;
1363 subcheat->data --;
1364 subcheat->data &= 0xff;
1365 break;
1366 case 3: /* code */
1367 textedit_active = 0;
1368 subcheat->code --;
1369 break;
1370 }
1371 }
1372 }
1373
1374 if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
1375 {
1376 if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub+1) * 4) + 1))
1377 {
1378 int newsel;
1379
1380 subcheat = &CheatTable[cheat_num].subcheat[(sel - 2) / 4];
1381 newsel = (sel - 2) % 4;
1382
1383 switch (newsel)
1384 {
1385 case 0: /* CPU */
1386 subcheat->cpu ++;
1387 /* skip audio CPUs when the sound is off */
1388 if (CPU_AUDIO_OFF(subcheat->cpu))
1389 subcheat->cpu ++;
1390 if (subcheat->cpu >= cpu_gettotalcpu())
1391 subcheat->cpu = 0;
1392 subcheat->address &= cpunum_address_mask(subcheat->cpu);
1393 break;
1394 case 1: /* address */
1395 textedit_active = 0;
1396 subcheat->address ++;
1397 subcheat->address &= cpunum_address_mask(subcheat->cpu);
1398 break;
1399 case 2: /* value */
1400 textedit_active = 0;
1401 subcheat->data ++;
1402 subcheat->data &= 0xff;
1403 break;
1404 case 3: /* code */
1405 textedit_active = 0;
1406 subcheat->code ++;
1407 break;
1408 }
1409 }
1410 }
1411
1412 if (input_ui_pressed(IPT_UI_SELECT))
1413 {
1414 if (sel == ((CheatTable[cheat_num].num_sub+1) * 4) + 2)
1415 {
1416 /* return to main menu */
1417 submenu_choice = 0;
1418 sel = -1;
1419 }
1420 else if (/*(sel == 4) ||*/ (sel == 0))
1421 {
1422 /* wait for key up */
1423 while (input_ui_pressed(IPT_UI_SELECT)) {};
1424
1425 /* flush the text buffer */
1426 osd_readkey_unicode (1);
1427 textedit_active ^= 1;
1428 }
1429 else
1430 {
1431 submenu_choice = 1;
1432 /* tell updatescreen() to clean after us */
1433 need_to_clear_bitmap = 1;
1434 }
1435 }
1436
1437 /* Cancel pops us up a menu level */
1438 if (input_ui_pressed(IPT_UI_CANCEL))
1439 sel = -1;
1440
1441 /* The UI key takes us all the way back out */
1442 if (input_ui_pressed(IPT_UI_CONFIGURE))
1443 sel = -2;
1444
1445 if (sel == -1 || sel == -2)
1446 {
1447 textedit_active = 0;
1448 /* flush the text buffer */
1449 osd_readkey_unicode (1);
1450 /* tell updatescreen() to clean after us */
1451 need_to_clear_bitmap = 1;
1452 }
1453
1454 /* After we've weeded out any control characters, look for text */
1455 if (textedit_active)
1456 {
1457 int code;
1458
1459 #if 0
1460 /* is this the address field? */
1461 if (sel == 1)
1462 {
1463 INT8 hex_val;
1464
1465 /* see if a hex digit was typed */
1466 hex_val = code_read_hex_async();
1467 if (hex_val != -1)
1468 {
1469 /* shift over one digit, add in the new value and clip */
1470 subcheat->address <<= 4;
1471 subcheat->address |= hex_val;
1472 subcheat->address &= cpunum_address_mask(subcheat->cpu);
1473 }
1474 }
1475 else
1476 #endif
1477 if (CheatTable[cheat_num].name)
1478 {
1479 int length = strlen(CheatTable[cheat_num].name);
1480
1481 code = osd_readkey_unicode(0) & 0xff; /* no 16-bit support */
1482
1483 if (code)
1484 {
1485 if (code == 0x08) /* backspace */
1486 {
1487 /* clear the buffer */
1488 CheatTable[cheat_num].name[0] = 0x00;
1489 }
1490 else
1491 {
1492 /* append the character */
1493 CheatTable[cheat_num].name = (char*)realloc(CheatTable[cheat_num].name, length + 2);
1494 if (CheatTable[cheat_num].name != NULL)
1495 {
1496 CheatTable[cheat_num].name[length] = code;
1497 CheatTable[cheat_num].name[length+1] = 0x00;
1498 }
1499 }
1500 }
1501 }
1502 }
1503
1504 return sel + 1;
1505 }
1506
1507
1508 #ifdef macintosh
1509 #pragma mark -
1510 #endif
1511
1512 /* make a copy of a source ram table to a dest. ram table */
copy_ram(struct ExtMemory * dest,struct ExtMemory * src)1513 static void copy_ram (struct ExtMemory *dest, struct ExtMemory *src)
1514 {
1515 struct ExtMemory *ext_dest, *ext_src;
1516
1517 for (ext_src = src, ext_dest = dest; ext_src->data; ext_src++, ext_dest++)
1518 {
1519 memcpy (ext_dest->data, ext_src->data, ext_src->end - ext_src->start + 1);
1520 }
1521 }
1522
1523 /* make a copy of each ram area from search CPU ram to the specified table */
backup_ram(struct ExtMemory * table,int cpu)1524 static void backup_ram (struct ExtMemory *table, int cpu)
1525 {
1526 struct ExtMemory *ext;
1527 unsigned char *gameram;
1528
1529 for (ext = table; ext->data; ext++)
1530 {
1531 int i;
1532 gameram = memory_find_base (cpu, ext->start);
1533 memcpy (ext->data, gameram, ext->end - ext->start + 1);
1534 for (i=0; i <= ext->end - ext->start; i++)
1535 ext->data[i] = computer_readmem_byte(cpu, i+ext->start);
1536 }
1537 }
1538
1539 /* set every byte in specified table to data */
memset_ram(struct ExtMemory * table,unsigned char data)1540 static void memset_ram (struct ExtMemory *table, unsigned char data)
1541 {
1542 struct ExtMemory *ext;
1543
1544 for (ext = table; ext->data; ext++)
1545 memset (ext->data, data, ext->end - ext->start + 1);
1546 }
1547
1548 /* free all the memory and init the table */
reset_table(struct ExtMemory * table)1549 static void reset_table (struct ExtMemory *table)
1550 {
1551 struct ExtMemory *ext;
1552
1553 for (ext = table; ext->data; ext++)
1554 free(ext->data);
1555 memset (table, 0, sizeof (struct ExtMemory) * MAX_EXT_MEMORY);
1556 }
1557
1558 /* create tables for storing copies of all MWA_RAM areas */
build_tables(int cpu)1559 static int build_tables (int cpu)
1560 {
1561 /* const struct MemoryReadAddress *mra = Machine->drv->cpu[SearchCpuNo].memory_read; */
1562 const struct MemoryWriteAddress *mwa = Machine->drv->cpu[cpu].memory_write;
1563
1564 int region = REGION_CPU1+cpu;
1565
1566 struct ExtMemory *ext_sr = StartRam;
1567 struct ExtMemory *ext_br = BackupRam;
1568 struct ExtMemory *ext_ft = FlagTable;
1569
1570 struct ExtMemory *ext_obr = OldBackupRam;
1571 struct ExtMemory *ext_oft = OldFlagTable;
1572
1573 static int bail = 0; /* set to 1 if this routine fails during startup */
1574
1575 int i;
1576
1577 int NoMemArea = 0;
1578
1579 /* Trap memory allocation errors */
1580 int MemoryNeeded = 0;
1581
1582 /* Search speedup : (the games should be dasmed to confirm this) */
1583 /* Games based on Exterminator driver should scan BANK1 */
1584 /* Games based on SmashTV driver should scan BANK2 */
1585 /* NEOGEO games should only scan BANK1 (0x100000 -> 0x01FFFF) */
1586 int CpuToScan = -1;
1587 int BankToScanTable[9]; /* 0 for RAM & 1-8 for Banks 1-8 */
1588
1589 for (i = 0; i < 9;i ++)
1590 BankToScanTable[i] = ( fastsearch != 2 );
1591
1592 #if (HAS_TMS34010)
1593 if ((Machine->drv->cpu[1].cpu_type & ~CPU_FLAGS_MASK) == CPU_TMS34010)
1594 {
1595 /* 2nd CPU is 34010: games based on Exterminator driver */
1596 CpuToScan = 0;
1597 BankToScanTable[1] = 1;
1598 }
1599 else if ((Machine->drv->cpu[0].cpu_type & ~CPU_FLAGS_MASK) == CPU_TMS34010)
1600 {
1601 /* 1st CPU but not 2nd is 34010: games based on SmashTV driver */
1602 CpuToScan = 0;
1603 BankToScanTable[2] = 1;
1604 }
1605 #endif
1606 #ifndef MESS
1607 #ifdef NEOMAME
1608 if (Machine->gamedrv->clone_of == &driver_neogeo)
1609 {
1610 /* games based on NEOGEO driver */
1611 CpuToScan = 0;
1612 BankToScanTable[1] = 1;
1613 }
1614 #endif
1615 #endif
1616
1617 /* No CPU so we scan RAM & BANKn */
1618 if ((CpuToScan == -1) && (fastsearch == 2))
1619 for (i = 0; i < 9;i ++)
1620 BankToScanTable[i] = 1;
1621
1622 /* free memory that was previously allocated if no error occured */
1623 /* it must also be there because mwa varies from one CPU to another */
1624 if (!bail)
1625 {
1626 reset_table (StartRam);
1627 reset_table (BackupRam);
1628 reset_table (FlagTable);
1629
1630 reset_table (OldBackupRam);
1631 reset_table (OldFlagTable);
1632 }
1633
1634 bail = 0;
1635
1636 #if 0
1637 /* Message to show that something is in progress */
1638 cheat_clearbitmap();
1639 yPos = (MachHeight - FontHeight) / 2;
1640 xprintf(0, 0, yPos, "Allocating Memory...");
1641 #endif
1642
1643 NoMemArea = 0;
1644 while (mwa->start != -1)
1645 {
1646 /* int (*handler)(int) = mra->handler; */
1647 mem_write_handler handler = mwa->handler;
1648 int size = (mwa->end - mwa->start) + 1;
1649
1650 if (SkipBank(CpuToScan, BankToScanTable, handler))
1651 {
1652 NoMemArea++;
1653 mwa++;
1654 continue;
1655 }
1656
1657 #if 0
1658 if ((fastsearch == 3) && (!MemToScanTable[NoMemArea].Enabled))
1659 {
1660 NoMemArea++;
1661 mwa++;
1662 continue;
1663 }
1664 #endif
1665
1666 /* time to allocate */
1667 if (!bail)
1668 {
1669 ext_sr->data = (unsigned char*)malloc(size);
1670 ext_br->data = (unsigned char*)malloc(size);
1671 ext_ft->data = (unsigned char*)malloc(size);
1672
1673 ext_obr->data = (unsigned char*)malloc(size);
1674 ext_oft->data = (unsigned char*)malloc(size);
1675
1676 if (ext_sr->data == NULL)
1677 {
1678 bail = 1;
1679 MemoryNeeded += size;
1680 }
1681 if (ext_br->data == NULL)
1682 {
1683 bail = 1;
1684 MemoryNeeded += size;
1685 }
1686 if (ext_ft->data == NULL)
1687 {
1688 bail = 1;
1689 MemoryNeeded += size;
1690 }
1691
1692 if (ext_obr->data == NULL)
1693 {
1694 bail = 1;
1695 MemoryNeeded += size;
1696 }
1697 if (ext_oft->data == NULL)
1698 {
1699 bail = 1;
1700 MemoryNeeded += size;
1701 }
1702
1703 if (!bail)
1704 {
1705 ext_sr->start = ext_br->start = ext_ft->start = mwa->start;
1706 ext_sr->end = ext_br->end = ext_ft->end = mwa->end;
1707 ext_sr->region = ext_br->region = ext_ft->region = region;
1708 ext_sr++, ext_br++, ext_ft++;
1709
1710 ext_obr->start = ext_oft->start = mwa->start;
1711 ext_obr->end = ext_oft->end = mwa->end;
1712 ext_obr->region = ext_oft->region = region;
1713 ext_obr++, ext_oft++;
1714 }
1715 }
1716 else
1717 MemoryNeeded += (5 * size);
1718
1719 NoMemArea++;
1720 mwa++;
1721 }
1722
1723 /* free memory that was previously allocated if an error occured */
1724 if (bail)
1725 {
1726 reset_table (StartRam);
1727 reset_table (BackupRam);
1728 reset_table (FlagTable);
1729
1730 reset_table (OldBackupRam);
1731 reset_table (OldFlagTable);
1732
1733 #if 0
1734 cheat_clearbitmap();
1735 yPos = (MachHeight - 10 * FontHeight) / 2;
1736 xprintf(0, 0, yPos, "Error while allocating memory !");
1737 yPos += (2 * FontHeight);
1738 xprintf(0, 0, yPos, "You need %d more bytes", MemoryNeeded);
1739 yPos += FontHeight;
1740 xprintf(0, 0, yPos, "(0x%X) of free memory", MemoryNeeded);
1741 yPos += (2 * FontHeight);
1742 xprintf(0, 0, yPos, "No search available for CPU %d", currentSearchCPU);
1743 yPos += (4 * FontHeight);
1744 xprintf(0, 0, yPos, "Press A Key To Continue...");
1745 key = keyboard_read_sync();
1746 while (keyboard_pressed(key)) ; /* wait for key release */
1747 cheat_clearbitmap();
1748 #endif
1749 }
1750
1751 // ClearTextLine (1, yPos);
1752
1753 return bail;
1754 }
1755
1756
1757 /* Returns 1 if memory area has to be skipped */
SkipBank(int CpuToScan,int * BankToScanTable,mem_write_handler handler)1758 static int SkipBank(int CpuToScan, int *BankToScanTable, mem_write_handler handler)
1759 {
1760 int res = 0;
1761
1762 if ((fastsearch == 1) || (fastsearch == 2))
1763 {
1764 if (((FPTR)handler)==((FPTR)MWA_RAM))
1765 {
1766 res = !BankToScanTable[0];
1767 }
1768 else if (((FPTR)handler)==((FPTR)MWA_BANK1))
1769 {
1770 res = !BankToScanTable[1];
1771 }
1772 else if (((FPTR)handler)==((FPTR)MWA_BANK2))
1773 {
1774 res = !BankToScanTable[2];
1775 }
1776 else if (((FPTR)handler)==((FPTR)MWA_BANK3))
1777 {
1778 res = !BankToScanTable[3];
1779 }
1780 else if (((FPTR)handler)==((FPTR)MWA_BANK4))
1781 {
1782 res = !BankToScanTable[4];
1783 }
1784 else if (((FPTR)handler)==((FPTR)MWA_BANK5))
1785 {
1786 res = !BankToScanTable[5];
1787 }
1788 else if (((FPTR)handler)==((FPTR)MWA_BANK6))
1789 {
1790 res = !BankToScanTable[6];
1791 }
1792 else if (((FPTR)handler)==((FPTR)MWA_BANK7))
1793 {
1794 res = !BankToScanTable[7];
1795 }
1796 else if (((FPTR)handler)==((FPTR)MWA_BANK8))
1797 {
1798 res = !BankToScanTable[8];
1799 }
1800 else
1801 {
1802 res = 1;
1803 }
1804 }
1805 return(res);
1806 }
1807
PerformSearch(struct osd_bitmap * bitmap,INT32 selected)1808 INT32 PerformSearch (struct osd_bitmap *bitmap, INT32 selected)
1809 {
1810 return -1;
1811 }
1812
1813
1814 /*****************
1815 * Start a cheat search
1816 * If the method 1 is selected, ask the user a number
1817 * In all cases, backup the ram.
1818 *
1819 * Ask the user to select one of the following:
1820 * 1 - Lives or other number (byte) (exact) ask a start value, ask new value
1821 * 2 - Timers (byte) (+ or - X) nothing at start, ask +-X
1822 * 3 - Energy (byte) (less, equal or greater) nothing at start, ask less, equal or greater
1823 * 4 - Status (bit) (true or false) nothing at start, ask same or opposite
1824 * 5 - Slow but sure (Same as start or different) nothing at start, ask same or different
1825 *
1826 * Another method is used in the Pro action Replay the Energy method
1827 * you can tell that the value is now 25%/50%/75%/100% as the start
1828 * the problem is that I probably cannot search for exactly 50%, so
1829 * that do I do? search +/- 10% ?
1830 * If you think of other way to search for codes, let me know.
1831 */
1832
StartSearch(struct osd_bitmap * bitmap,INT32 selected)1833 INT32 StartSearch (struct osd_bitmap *bitmap, INT32 selected)
1834 {
1835 enum
1836 {
1837 Menu_CPU = 0,
1838 Menu_Value,
1839 Menu_Time,
1840 Menu_Energy,
1841 Menu_Bit,
1842 Menu_Byte,
1843 Menu_Speed,
1844 Menu_Return,
1845 Menu_Total
1846 };
1847
1848 const char *menu_item[Menu_Total];
1849 const char *menu_subitem[Menu_Total];
1850 char setting[Menu_Total][30];
1851 INT32 sel;
1852 UINT8 total = 0;
1853 static INT8 submenu_choice;
1854 int i;
1855 // char flag[Menu_Total];
1856
1857 sel = selected - 1;
1858
1859 /* If a submenu has been selected, go there */
1860 if (submenu_choice)
1861 {
1862 switch (sel)
1863 {
1864 case Menu_Value:
1865 searchType = kSearch_Value;
1866 submenu_choice = PerformSearch (bitmap, submenu_choice);
1867 break;
1868 case Menu_Time:
1869 searchType = kSearch_Time;
1870 // submenu_choice = PerformSearch (submenu_choice);
1871 break;
1872 case Menu_Energy:
1873 searchType = kSearch_Energy;
1874 // submenu_choice = PerformSearch (submenu_choice);
1875 break;
1876 case Menu_Bit:
1877 searchType = kSearch_Bit;
1878 // submenu_choice = PerformSearch (submenu_choice);
1879 break;
1880 case Menu_Byte:
1881 searchType = kSearch_Byte;
1882 // submenu_choice = PerformSearch (submenu_choice);
1883 break;
1884 case Menu_Speed:
1885 // submenu_choice = RestoreSearch (submenu_choice);
1886 break;
1887 case Menu_Return:
1888 submenu_choice = 0;
1889 sel = -1;
1890 break;
1891 }
1892
1893 if (submenu_choice == -1)
1894 submenu_choice = 0;
1895
1896 return sel + 1;
1897 }
1898
1899 /* No submenu active, display the main cheat menu */
1900 menu_item[total++] = ui_getstring (UI_cpu);
1901 menu_item[total++] = ui_getstring (UI_search_lives);
1902 menu_item[total++] = ui_getstring (UI_search_timers);
1903 menu_item[total++] = ui_getstring (UI_search_energy);
1904 menu_item[total++] = ui_getstring (UI_search_status);
1905 menu_item[total++] = ui_getstring (UI_search_slow);
1906 menu_item[total++] = ui_getstring (UI_search_speed);
1907 menu_item[total++] = ui_getstring (UI_returntoprior);
1908 menu_item[total] = 0;
1909
1910 /* clear out the subitem menu */
1911 for (i = 0; i < Menu_Total; i ++)
1912 menu_subitem[i] = NULL;
1913
1914 /* cpu number */
1915 sprintf (setting[Menu_CPU], "%d", searchCPU);
1916 menu_subitem[Menu_CPU] = setting[Menu_CPU];
1917
1918 /* lives/byte value */
1919 sprintf (setting[Menu_Value], "%d", searchValue);
1920 menu_subitem[Menu_Value] = setting[Menu_Value];
1921
1922
1923 ui_displaymenu(bitmap,menu_item,menu_subitem,0,sel,0);
1924
1925 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
1926 sel = (sel + 1) % total;
1927
1928 if (input_ui_pressed_repeat(IPT_UI_UP,8))
1929 sel = (sel + total - 1) % total;
1930
1931 if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
1932 {
1933 switch (sel)
1934 {
1935 case Menu_CPU:
1936 searchCPU --;
1937 /* skip audio CPUs when the sound is off */
1938 if (CPU_AUDIO_OFF(searchCPU))
1939 searchCPU --;
1940 if (searchCPU < 0)
1941 searchCPU = cpu_gettotalcpu() - 1;
1942 break;
1943 case Menu_Value:
1944 searchValue --;
1945 if (searchValue < 0)
1946 searchValue = 255;
1947 break;
1948 }
1949 }
1950 if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
1951 {
1952 switch (sel)
1953 {
1954 case Menu_CPU:
1955 searchCPU ++;
1956 /* skip audio CPUs when the sound is off */
1957 if (CPU_AUDIO_OFF(searchCPU))
1958 searchCPU ++;
1959 if (searchCPU >= cpu_gettotalcpu())
1960 searchCPU = 0;
1961 break;
1962 case Menu_Value:
1963 searchValue ++;
1964 if (searchValue > 255)
1965 searchValue = 0;
1966 break;
1967 }
1968 }
1969
1970 if (input_ui_pressed(IPT_UI_SELECT))
1971 {
1972 if (sel == Menu_Return)
1973 {
1974 submenu_choice = 0;
1975 sel = -1;
1976 }
1977 else
1978 {
1979 int count = 0; /* Steph */
1980
1981 /* set up the search tables */
1982 build_tables (searchCPU);
1983
1984 /* backup RAM */
1985 backup_ram (StartRam, searchCPU);
1986 backup_ram (BackupRam, searchCPU);
1987
1988 /* mark all RAM as good */
1989 memset_ram (FlagTable, 0xff);
1990
1991 if (sel == Menu_Value)
1992 {
1993 /* flag locations that match the starting value */
1994 struct ExtMemory *ext;
1995 int j; /* Steph - replaced all instances of 'i' with 'j' */
1996
1997 count = 0;
1998 for (ext = FlagTable; ext->data; ext++)
1999 {
2000 for (j=0; j <= ext->end - ext->start; j++)
2001 if (ext->data[j] != 0)
2002 {
2003 if ((computer_readmem_byte(searchCPU, j+ext->start) != searchValue) &&
2004 ((computer_readmem_byte(searchCPU, j+ext->start) != searchValue-1) /*||
2005 (searchType != kSearch_Value)*/))
2006
2007 ext->data[j] = 0;
2008 else
2009 count ++;
2010 }
2011 }
2012 }
2013
2014 /* Copy the tables */
2015 copy_ram (OldBackupRam, BackupRam);
2016 copy_ram (OldFlagTable, FlagTable);
2017
2018 restoreStatus = kRestore_NoSave;
2019
2020 usrintf_showmessage_secs(4, "%s: %d", ui_getstring(UI_search_matches_found), count);
2021 }
2022 }
2023
2024 /* Cancel pops us up a menu level */
2025 if (input_ui_pressed(IPT_UI_CANCEL))
2026 sel = -1;
2027
2028 /* The UI key takes us all the way back out */
2029 if (input_ui_pressed(IPT_UI_CONFIGURE))
2030 sel = -2;
2031
2032 if (sel == -1 || sel == -2)
2033 {
2034 /* tell updatescreen() to clean after us */
2035 need_to_clear_bitmap = 1;
2036 }
2037
2038 return sel + 1;
2039 }
2040
ContinueSearch(INT32 selected)2041 INT32 ContinueSearch (INT32 selected)
2042 {
2043 return -1;
2044 }
2045
ViewSearchResults(struct osd_bitmap * bitmap,INT32 selected)2046 INT32 ViewSearchResults (struct osd_bitmap *bitmap, INT32 selected)
2047 {
2048 int sel;
2049 static INT8 submenu_choice;
2050 const char *menu_item[MAX_SEARCHES + 2];
2051 char buf[MAX_SEARCHES][20];
2052 int i, total = 0;
2053 struct ExtMemory *ext;
2054 struct ExtMemory *ext_sr;
2055
2056
2057 sel = selected - 1;
2058
2059 /* Set up the menu */
2060 for (ext = FlagTable, ext_sr = StartRam; ext->data /*&& Continue==0*/; ext++, ext_sr++)
2061 {
2062 for (i=0; i <= ext->end - ext->start; i++)
2063 if (ext->data[i] != 0)
2064 {
2065 int TrueAddr, TrueData;
2066 char fmt[40];
2067
2068 strcpy(fmt, FormatAddr(searchCPU,0));
2069 strcat(fmt," = %02X");
2070
2071 TrueAddr = i+ext->start;
2072 TrueData = ext_sr->data[i];
2073 sprintf (buf[total], fmt, TrueAddr, TrueData);
2074
2075 menu_item[total] = buf[total];
2076 total++;
2077 if (total >= MAX_SEARCHES)
2078 {
2079 // Continue = i+ext->start;
2080 break;
2081 }
2082 }
2083 }
2084
2085 menu_item[total++] = ui_getstring (UI_returntoprior);
2086 menu_item[total] = 0; /* terminate array */
2087
2088 ui_displaymenu(bitmap,menu_item,0,0,sel,0);
2089
2090 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
2091 sel = (sel + 1) % total;
2092
2093 if (input_ui_pressed_repeat(IPT_UI_UP,8))
2094 sel = (sel + total - 1) % total;
2095
2096 if (input_ui_pressed(IPT_UI_SELECT))
2097 {
2098 if (sel == total - 1)
2099 {
2100 submenu_choice = 0;
2101 sel = -1;
2102 }
2103 else
2104 {
2105 submenu_choice = 1;
2106 /* tell updatescreen() to clean after us */
2107 need_to_clear_bitmap = 1;
2108 }
2109 }
2110
2111 /* Cancel pops us up a menu level */
2112 if (input_ui_pressed(IPT_UI_CANCEL))
2113 sel = -1;
2114
2115 /* The UI key takes us all the way back out */
2116 if (input_ui_pressed(IPT_UI_CONFIGURE))
2117 sel = -2;
2118
2119 if (sel == -1 || sel == -2)
2120 {
2121 /* tell updatescreen() to clean after us */
2122 need_to_clear_bitmap = 1;
2123 }
2124
2125 return sel + 1;
2126 }
2127
RestoreSearch(void)2128 void RestoreSearch (void)
2129 {
2130 int restoreString = NULL; /* Steph */
2131
2132 switch (restoreStatus)
2133 {
2134 case kRestore_NoInit: restoreString = UI_search_noinit; break;
2135 case kRestore_NoSave: restoreString = UI_search_nosave; break;
2136 case kRestore_Done: restoreString = UI_search_done; break;
2137 case kRestore_OK: restoreString = UI_search_OK; break;
2138 }
2139 usrintf_showmessage_secs(4, "%s", ui_getstring(restoreString));
2140
2141 /* Now restore the tables if possible */
2142 if (restoreStatus == kRestore_OK)
2143 {
2144 copy_ram (BackupRam, OldBackupRam);
2145 copy_ram (FlagTable, OldFlagTable);
2146
2147 /* flag it as restored so we don't do it again */
2148 restoreStatus = kRestore_Done;
2149 }
2150 }
2151
2152 #ifdef macintosh
2153 #pragma mark -
2154 #endif
2155
2156 /*
2157 static int FindFreeWatch (void)
2158 {
2159 int i;
2160 for (i = 0; i < MAX_WATCHES; i ++)
2161 {
2162 if (watches[i].num_bytes == 0)
2163 return i;
2164 }
2165
2166 return -1;
2167 }
2168 */
2169
DisplayWatches(struct osd_bitmap * bitmap)2170 static void DisplayWatches (struct osd_bitmap *bitmap)
2171 {
2172 int i;
2173 char buf[256];
2174
2175 if ((!is_watch_active) || (!is_watch_visible)) return;
2176
2177 for (i = 0; i < MAX_WATCHES; i++)
2178 {
2179 /* Is this watchpoint active? */
2180 if (watches[i].num_bytes != 0)
2181 {
2182 char buf2[80];
2183
2184 /* Display the first byte */
2185 sprintf (buf, "%02x", computer_readmem_byte (watches[i].cpu, watches[i].address));
2186
2187 /* If this is for more than one byte, display the rest */
2188 if (watches[i].num_bytes > 1)
2189 {
2190 int j;
2191
2192 for (j = 1; j < watches[i].num_bytes; j ++)
2193 {
2194 sprintf (buf2, " %02x", computer_readmem_byte (watches[i].cpu, watches[i].address + j));
2195 strcat (buf, buf2);
2196 }
2197 }
2198
2199 /* Handle any labels */
2200 switch (watches[i].label_type)
2201 {
2202 case 0:
2203 default:
2204 break;
2205 case 1:
2206 if (cpunum_address_bits(watches[i].cpu) <= 16)
2207 {
2208 sprintf (buf2, " (%04x)", watches[i].address);
2209 strcat (buf, buf2);
2210 }
2211 else
2212 {
2213 sprintf (buf2, " (%08x)", watches[i].address);
2214 strcat (buf, buf2);
2215 }
2216 break;
2217 case 2:
2218 {
2219 sprintf (buf2, " (%s)", watches[i].label);
2220 strcat (buf, buf2);
2221 }
2222 break;
2223 }
2224
2225 ui_text (bitmap, buf, watches[i].x, watches[i].y);
2226 }
2227 }
2228 }
2229
ConfigureWatch(struct osd_bitmap * bitmap,INT32 selected,UINT8 watchnum)2230 static INT32 ConfigureWatch (struct osd_bitmap *bitmap, INT32 selected, UINT8 watchnum)
2231 {
2232 #ifdef NUM_ENTRIES
2233 #undef NUM_ENTRIES
2234 #endif
2235 #define NUM_ENTRIES 9
2236
2237 int sel;
2238 int total, total2;
2239 static INT8 submenu_choice;
2240 static UINT8 textedit_active;
2241 const char *menu_item[NUM_ENTRIES];
2242 const char *menu_subitem[NUM_ENTRIES];
2243 char setting[NUM_ENTRIES][30];
2244 char flag[NUM_ENTRIES];
2245 int arrowize;
2246 int i;
2247
2248
2249 sel = selected - 1;
2250
2251 total = 0;
2252 /* No submenu active, display the main cheat menu */
2253 menu_item[total++] = ui_getstring (UI_cpu);
2254 menu_item[total++] = ui_getstring (UI_address);
2255 menu_item[total++] = ui_getstring (UI_watchlength);
2256 menu_item[total++] = ui_getstring (UI_watchlabeltype);
2257 menu_item[total++] = ui_getstring (UI_watchlabel);
2258 menu_item[total++] = ui_getstring (UI_watchx);
2259 menu_item[total++] = ui_getstring (UI_watchy);
2260 menu_item[total++] = ui_getstring (UI_returntoprior);
2261 menu_item[total] = 0;
2262
2263 arrowize = 0;
2264
2265 /* set up the submenu selections */
2266 total2 = 0;
2267 for (i = 0; i < NUM_ENTRIES; i ++)
2268 flag[i] = 0;
2269
2270 /* if we're editing the label, make it inverse */
2271 if (textedit_active)
2272 flag[sel] = 1;
2273
2274 /* cpu number */
2275 sprintf (setting[total2], "%d", watches[watchnum].cpu);
2276 menu_subitem[total2] = setting[total2]; total2++;
2277
2278 /* address */
2279 if (cpunum_address_bits(watches[watchnum].cpu) <= 16)
2280 {
2281 sprintf (setting[total2], "%04x", watches[watchnum].address);
2282 }
2283 else
2284 {
2285 sprintf (setting[total2], "%08x", watches[watchnum].address);
2286 }
2287 menu_subitem[total2] = setting[total2]; total2++;
2288
2289 /* length */
2290 sprintf (setting[total2], "%d", watches[watchnum].num_bytes);
2291 menu_subitem[total2] = setting[total2]; total2++;
2292
2293 /* label type */
2294 switch (watches[watchnum].label_type)
2295 {
2296 case 0:
2297 strcpy (setting[total2], ui_getstring (UI_none));
2298 break;
2299 case 1:
2300 strcpy (setting[total2], ui_getstring (UI_address));
2301 break;
2302 case 2:
2303 strcpy (setting[total2], ui_getstring (UI_text));
2304 break;
2305 }
2306 menu_subitem[total2] = setting[total2]; total2++;
2307
2308 /* label */
2309 if (watches[watchnum].label[0] != 0x00)
2310 sprintf (setting[total2], "%s", watches[watchnum].label);
2311 else
2312 strcpy (setting[total2], ui_getstring (UI_none));
2313 menu_subitem[total2] = setting[total2]; total2++;
2314
2315 /* x */
2316 sprintf (setting[total2], "%d", watches[watchnum].x);
2317 menu_subitem[total2] = setting[total2]; total2++;
2318
2319 /* y */
2320 sprintf (setting[total2], "%d", watches[watchnum].y);
2321 menu_subitem[total2] = setting[total2]; total2++;
2322
2323 menu_subitem[total2] = NULL;
2324
2325 ui_displaymenu(bitmap,menu_item,menu_subitem,flag,sel,arrowize);
2326
2327 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
2328 {
2329 textedit_active = 0;
2330 sel = (sel + 1) % total;
2331 }
2332
2333 if (input_ui_pressed_repeat(IPT_UI_UP,8))
2334 {
2335 textedit_active = 0;
2336 sel = (sel + total - 1) % total;
2337 }
2338
2339 if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
2340 {
2341 switch (sel)
2342 {
2343 case 0: /* CPU */
2344 watches[watchnum].cpu --;
2345 /* skip audio CPUs when the sound is off */
2346 if (CPU_AUDIO_OFF(watches[watchnum].cpu))
2347 watches[watchnum].cpu --;
2348 if (watches[watchnum].cpu < 0)
2349 watches[watchnum].cpu = cpu_gettotalcpu() - 1;
2350 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
2351 break;
2352 case 1: /* address */
2353 textedit_active = 0;
2354 watches[watchnum].address --;
2355 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
2356 break;
2357 case 2: /* number of bytes */
2358 watches[watchnum].num_bytes --;
2359 if (watches[watchnum].num_bytes == (UINT8) -1)
2360 watches[watchnum].num_bytes = 16;
2361 break;
2362 case 3: /* label type */
2363 watches[watchnum].label_type --;
2364 if (watches[watchnum].label_type == (UINT8) -1)
2365 watches[watchnum].label_type = 2;
2366 break;
2367 case 4: /* label string */
2368 textedit_active = 0;
2369 break;
2370 case 5: /* x */
2371 watches[watchnum].x --;
2372 if (watches[watchnum].x == (UINT16) -1)
2373 watches[watchnum].x = Machine->uiwidth - 1;
2374 break;
2375 case 6: /* y */
2376 watches[watchnum].y --;
2377 if (watches[watchnum].y == (UINT16) -1)
2378 watches[watchnum].y = Machine->uiheight - 1;
2379 break;
2380 }
2381 }
2382
2383 if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
2384 {
2385 switch (sel)
2386 {
2387 case 0:
2388 watches[watchnum].cpu ++;
2389 /* skip audio CPUs when the sound is off */
2390 if (CPU_AUDIO_OFF(watches[watchnum].cpu))
2391 watches[watchnum].cpu ++;
2392 if (watches[watchnum].cpu >= cpu_gettotalcpu())
2393 watches[watchnum].cpu = 0;
2394 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
2395 break;
2396 case 1:
2397 textedit_active = 0;
2398 watches[watchnum].address ++;
2399 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
2400 break;
2401 case 2:
2402 watches[watchnum].num_bytes ++;
2403 if (watches[watchnum].num_bytes > 16)
2404 watches[watchnum].num_bytes = 0;
2405 break;
2406 case 3:
2407 watches[watchnum].label_type ++;
2408 if (watches[watchnum].label_type > 2)
2409 watches[watchnum].label_type = 0;
2410 break;
2411 case 4:
2412 textedit_active = 0;
2413 break;
2414 case 5:
2415 watches[watchnum].x ++;
2416 if (watches[watchnum].x >= Machine->uiwidth)
2417 watches[watchnum].x = 0;
2418 break;
2419 case 6:
2420 watches[watchnum].y ++;
2421 if (watches[watchnum].y >= Machine->uiheight)
2422 watches[watchnum].y = 0;
2423 break;
2424 }
2425 }
2426
2427 /* see if any watchpoints are active and set the flag if so */
2428 is_watch_active = 0;
2429 for (i = 0; i < MAX_WATCHES; i ++)
2430 {
2431 if (watches[i].num_bytes != 0)
2432 {
2433 is_watch_active = 1;
2434 break;
2435 }
2436 }
2437
2438 if (input_ui_pressed(IPT_UI_SELECT))
2439 {
2440 if (sel == 7)
2441 {
2442 /* return to main menu */
2443 submenu_choice = 0;
2444 sel = -1;
2445 }
2446 else if ((sel == 4) || (sel == 1))
2447 {
2448 /* wait for key up */
2449 while (input_ui_pressed(IPT_UI_SELECT)) {};
2450
2451 /* flush the text buffer */
2452 osd_readkey_unicode (1);
2453 textedit_active ^= 1;
2454 }
2455 else
2456 {
2457 submenu_choice = 1;
2458 /* tell updatescreen() to clean after us */
2459 need_to_clear_bitmap = 1;
2460 }
2461 }
2462
2463 /* Cancel pops us up a menu level */
2464 if (input_ui_pressed(IPT_UI_CANCEL))
2465 sel = -1;
2466
2467 /* The UI key takes us all the way back out */
2468 if (input_ui_pressed(IPT_UI_CONFIGURE))
2469 sel = -2;
2470
2471 if (sel == -1 || sel == -2)
2472 {
2473 textedit_active = 0;
2474 /* flush the text buffer */
2475 osd_readkey_unicode (1);
2476 /* tell updatescreen() to clean after us */
2477 need_to_clear_bitmap = 1;
2478 }
2479
2480 /* After we've weeded out any control characters, look for text */
2481 if (textedit_active)
2482 {
2483 int code;
2484
2485 /* is this the address field? */
2486 if (sel == 1)
2487 {
2488 INT8 hex_val;
2489
2490 /* see if a hex digit was typed */
2491 hex_val = code_read_hex_async();
2492 if (hex_val != -1)
2493 {
2494 /* shift over one digit, add in the new value and clip */
2495 watches[watchnum].address <<= 4;
2496 watches[watchnum].address |= hex_val;
2497 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
2498 }
2499 }
2500 else
2501 {
2502 int length = strlen(watches[watchnum].label);
2503
2504 if (length < 254)
2505 {
2506 code = osd_readkey_unicode(0) & 0xff; /* no 16-bit support */
2507
2508 if (code)
2509 {
2510 if (code == 0x08) /* backspace */
2511 {
2512 /* clear the buffer */
2513 watches[watchnum].label[0] = 0x00;
2514 }
2515 else
2516 {
2517 /* append the character */
2518 watches[watchnum].label[length] = code;
2519 watches[watchnum].label[length+1] = 0x00;
2520 }
2521 }
2522 }
2523 }
2524 }
2525
2526 return sel + 1;
2527 }
2528
ChooseWatch(struct osd_bitmap * bitmap,INT32 selected)2529 static INT32 ChooseWatch (struct osd_bitmap *bitmap, INT32 selected)
2530 {
2531 int sel;
2532 static INT8 submenu_choice;
2533 const char *menu_item[MAX_WATCHES + 2];
2534 char buf[MAX_WATCHES][80];
2535 const char *watchpoint_str = ui_getstring (UI_watchpoint);
2536 const char *disabled_str = ui_getstring (UI_disabled);
2537 int i, total = 0;
2538
2539
2540 sel = selected - 1;
2541
2542 /* If a submenu has been selected, go there */
2543 if (submenu_choice)
2544 {
2545 submenu_choice = ConfigureWatch (bitmap, submenu_choice, sel);
2546
2547 if (submenu_choice == -1)
2548 {
2549 submenu_choice = 0;
2550 sel = -2;
2551 }
2552
2553 return sel + 1;
2554 }
2555
2556 /* No submenu active, do the watchpoint menu */
2557 for (i = 0; i < MAX_WATCHES; i ++)
2558 {
2559 sprintf (buf[i], "%s %d: ", watchpoint_str, i);
2560 /* If the watchpoint is active (1 or more bytes long), show it */
2561 if (watches[i].num_bytes)
2562 {
2563 char buf2[80];
2564
2565 if (cpunum_address_bits(watches[i].cpu) <= 16)
2566 {
2567 sprintf (buf2, "%04x", watches[i].address);
2568 strcat (buf[i], buf2);
2569 }
2570 else
2571 {
2572 sprintf (buf2, "%08x", watches[i].address);
2573 strcat (buf[i], buf2);
2574 }
2575 }
2576 else
2577 strcat (buf[i], disabled_str);
2578
2579 menu_item[total++] = buf[i];
2580 }
2581
2582 menu_item[total++] = ui_getstring (UI_returntoprior);
2583 menu_item[total] = 0; /* terminate array */
2584
2585 ui_displaymenu(bitmap,menu_item,0,0,sel,0);
2586
2587 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
2588 sel = (sel + 1) % total;
2589
2590 if (input_ui_pressed_repeat(IPT_UI_UP,8))
2591 sel = (sel + total - 1) % total;
2592
2593 if (input_ui_pressed(IPT_UI_SELECT))
2594 {
2595 if (sel == MAX_WATCHES)
2596 {
2597 submenu_choice = 0;
2598 sel = -1;
2599 }
2600 else
2601 {
2602 submenu_choice = 1;
2603 /* tell updatescreen() to clean after us */
2604 need_to_clear_bitmap = 1;
2605 }
2606 }
2607
2608 /* Cancel pops us up a menu level */
2609 if (input_ui_pressed(IPT_UI_CANCEL))
2610 sel = -1;
2611
2612 /* The UI key takes us all the way back out */
2613 if (input_ui_pressed(IPT_UI_CONFIGURE))
2614 sel = -2;
2615
2616 if (sel == -1 || sel == -2)
2617 {
2618 /* tell updatescreen() to clean after us */
2619 need_to_clear_bitmap = 1;
2620 }
2621
2622 return sel + 1;
2623 }
2624
2625
2626 #ifdef macintosh
2627 #pragma mark -
2628 #endif
2629
DisplayHelpFile(INT32 selected)2630 static INT32 DisplayHelpFile (INT32 selected)
2631 {
2632 return -1;
2633 }
2634
2635 #ifdef macintosh
2636 #pragma mark -
2637 #endif
2638
cheat_menu(struct osd_bitmap * bitmap,INT32 selected)2639 INT32 cheat_menu(struct osd_bitmap *bitmap, INT32 selected)
2640 {
2641 enum {
2642 Menu_EnableDisable = 0,
2643 Menu_AddEdit,
2644 Menu_StartSearch,
2645 Menu_ContinueSearch,
2646 Menu_ViewResults,
2647 Menu_RestoreSearch,
2648 Menu_ChooseWatch,
2649 Menu_DisplayHelp,
2650 Menu_Return
2651 };
2652
2653 const char *menu_item[10];
2654 INT32 sel;
2655 UINT8 total = 0;
2656 static INT8 submenu_choice;
2657
2658 sel = selected - 1;
2659
2660 /* If a submenu has been selected, go there */
2661 if (submenu_choice)
2662 {
2663 switch (sel)
2664 {
2665 case Menu_EnableDisable:
2666 submenu_choice = EnableDisableCheatMenu (bitmap, submenu_choice);
2667 break;
2668 case Menu_AddEdit:
2669 submenu_choice = AddEditCheatMenu (bitmap, submenu_choice);
2670 break;
2671 case Menu_StartSearch:
2672 submenu_choice = StartSearch (bitmap, submenu_choice);
2673 break;
2674 case Menu_ContinueSearch:
2675 submenu_choice = ContinueSearch (submenu_choice);
2676 break;
2677 case Menu_ViewResults:
2678 submenu_choice = ViewSearchResults (bitmap, submenu_choice);
2679 break;
2680 case Menu_ChooseWatch:
2681 submenu_choice = ChooseWatch (bitmap, submenu_choice);
2682 break;
2683 case Menu_DisplayHelp:
2684 submenu_choice = DisplayHelpFile (submenu_choice);
2685 break;
2686 case Menu_Return:
2687 submenu_choice = 0;
2688 sel = -1;
2689 break;
2690 }
2691
2692 if (submenu_choice == -1)
2693 submenu_choice = 0;
2694
2695 return sel + 1;
2696 }
2697
2698 /* No submenu active, display the main cheat menu */
2699 menu_item[total++] = ui_getstring (UI_enablecheat);
2700 menu_item[total++] = ui_getstring (UI_addeditcheat);
2701 menu_item[total++] = ui_getstring (UI_startcheat);
2702 menu_item[total++] = ui_getstring (UI_continuesearch);
2703 menu_item[total++] = ui_getstring (UI_viewresults);
2704 menu_item[total++] = ui_getstring (UI_restoreresults);
2705 menu_item[total++] = ui_getstring (UI_memorywatch);
2706 menu_item[total++] = ui_getstring (UI_generalhelp);
2707 menu_item[total++] = ui_getstring (UI_returntomain);
2708 menu_item[total] = 0;
2709
2710 ui_displaymenu(bitmap,menu_item,0,0,sel,0);
2711
2712 if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
2713 sel = (sel + 1) % total;
2714
2715 if (input_ui_pressed_repeat(IPT_UI_UP,8))
2716 sel = (sel + total - 1) % total;
2717
2718 if (input_ui_pressed(IPT_UI_SELECT))
2719 {
2720 if (sel == Menu_Return)
2721 {
2722 submenu_choice = 0;
2723 sel = -1;
2724 }
2725 else if (sel == Menu_RestoreSearch)
2726 {
2727 RestoreSearch ();
2728 }
2729 else
2730 {
2731 submenu_choice = 1;
2732 /* tell updatescreen() to clean after us */
2733 need_to_clear_bitmap = 1;
2734 }
2735 }
2736
2737 /* Cancel pops us up a menu level */
2738 if (input_ui_pressed(IPT_UI_CANCEL))
2739 sel = -1;
2740
2741 /* The UI key takes us all the way back out */
2742 if (input_ui_pressed(IPT_UI_CONFIGURE))
2743 sel = -2;
2744
2745 if (sel == -1 || sel == -2)
2746 {
2747 /* tell updatescreen() to clean after us */
2748 need_to_clear_bitmap = 1;
2749 }
2750
2751 return sel + 1;
2752 }
2753
2754 /* Free allocated arrays */
StopCheat(void)2755 void StopCheat(void)
2756 {
2757 int i;
2758
2759 for (i = 0; i < LoadedCheatTotal; i ++)
2760 {
2761 /* free storage for the strings */
2762 if (CheatTable[i].name)
2763 {
2764 free(CheatTable[i].name);
2765 CheatTable[i].name = NULL;
2766 }
2767 if (CheatTable[i].comment)
2768 {
2769 free(CheatTable[i].comment);
2770 CheatTable[i].comment = NULL;
2771 }
2772 }
2773
2774 reset_table (StartRam);
2775 reset_table (BackupRam);
2776 reset_table (FlagTable);
2777
2778 reset_table (OldBackupRam);
2779 reset_table (OldFlagTable);
2780 }
2781
DoCheat(struct osd_bitmap * bitmap)2782 void DoCheat(struct osd_bitmap *bitmap)
2783 {
2784 DisplayWatches (bitmap);
2785
2786 if ((CheatEnabled) && (ActiveCheatTotal))
2787 {
2788 int i, j;
2789
2790 /* At least one cheat is active, handle them */
2791 for (i = 0; i < LoadedCheatTotal; i ++)
2792 {
2793 /* skip if this isn't an active cheat */
2794 if ((CheatTable[i].flags & CHEAT_FLAG_ACTIVE) == 0) continue;
2795
2796 /* loop through all subcheats */
2797 for (j = 0; j <= CheatTable[i].num_sub; j ++)
2798 {
2799 struct subcheat_struct *subcheat = &CheatTable[i].subcheat[j];
2800
2801 if (subcheat->flags & SUBCHEAT_FLAG_DONE) continue;
2802
2803 /* most common case: 0 */
2804 if (subcheat->code == kCheatSpecial_Poke)
2805 {
2806 WRITE_CHEAT;
2807 }
2808 /* Check special function if cheat counter is ready */
2809 else if (subcheat->frame_count == 0)
2810 {
2811 switch (subcheat->code)
2812 {
2813 case 1:
2814 WRITE_CHEAT;
2815 subcheat->flags |= SUBCHEAT_FLAG_DONE;
2816 break;
2817 case 2:
2818 case 3:
2819 case 4:
2820 WRITE_CHEAT;
2821 subcheat->frame_count = subcheat->frames_til_trigger;
2822 break;
2823
2824 /* 5,6,7 check if the value has changed, if yes, start a timer. */
2825 /* When the timer ends, change the location */
2826 case 5:
2827 case 6:
2828 case 7:
2829 if (subcheat->flags & SUBCHEAT_FLAG_TIMED)
2830 {
2831 WRITE_CHEAT;
2832 subcheat->flags &= ~SUBCHEAT_FLAG_TIMED;
2833 }
2834 else if (COMPARE_CHEAT)
2835 {
2836 subcheat->frame_count = subcheat->frames_til_trigger;
2837 subcheat->flags |= SUBCHEAT_FLAG_TIMED;
2838 }
2839 break;
2840
2841 /* 8,9,10,11 do not change the location if the value change by X every frames
2842 This is to try to not change the value of an energy bar
2843 when a bonus is awarded to it at the end of a level
2844 See Kung Fu Master */
2845 case 8:
2846 case 9:
2847 case 10:
2848 case 11:
2849 if (subcheat->flags & SUBCHEAT_FLAG_TIMED)
2850 {
2851 /* Check the value to see if it has increased over the original value by 1 or more */
2852 if (READ_CHEAT != subcheat->backup - (kCheatSpecial_Backup1 - subcheat->code + 1))
2853 WRITE_CHEAT;
2854 subcheat->flags &= ~SUBCHEAT_FLAG_TIMED;
2855 }
2856 else
2857 {
2858 subcheat->backup = READ_CHEAT;
2859 subcheat->frame_count = 1;
2860 subcheat->flags |= SUBCHEAT_FLAG_TIMED;
2861 }
2862 break;
2863
2864 /* 20-24: set bits */
2865 case 20:
2866 computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT | subcheat->data);
2867 break;
2868 case 21:
2869 computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT | subcheat->data);
2870 subcheat->flags |= SUBCHEAT_FLAG_DONE;
2871 break;
2872 case 22:
2873 case 23:
2874 case 24:
2875 computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT | subcheat->data);
2876 subcheat->frame_count = subcheat->frames_til_trigger;
2877 break;
2878
2879 /* 40-44: reset bits */
2880 case 40:
2881 computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT & ~subcheat->data);
2882 break;
2883 case 41:
2884 computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT & ~subcheat->data);
2885 subcheat->flags |= SUBCHEAT_FLAG_DONE;
2886 break;
2887 case 42:
2888 case 43:
2889 case 44:
2890 computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT & ~subcheat->data);
2891 subcheat->frame_count = subcheat->frames_til_trigger;
2892 break;
2893
2894 /* 60-65: user select, poke when changes */
2895 case 60: case 61: case 62: case 63: case 64: case 65:
2896 if (subcheat->flags & SUBCHEAT_FLAG_TIMED)
2897 {
2898 if (READ_CHEAT != subcheat->backup)
2899 {
2900 WRITE_CHEAT;
2901 subcheat->flags |= SUBCHEAT_FLAG_DONE;
2902 }
2903 }
2904 else
2905 {
2906 subcheat->backup = READ_CHEAT;
2907 subcheat->frame_count = 1;
2908 subcheat->flags |= SUBCHEAT_FLAG_TIMED;
2909 }
2910 break;
2911
2912 /* 70-75: user select, poke once */
2913 case 70: case 71: case 72: case 73: case 74: case 75:
2914 WRITE_CHEAT;
2915 subcheat->flags |= SUBCHEAT_FLAG_DONE;
2916 break;
2917 }
2918 }
2919 else
2920 {
2921 subcheat->frame_count--;
2922 }
2923 }
2924 } /* end for */
2925 }
2926
2927 /* IPT_UI_TOGGLE_CHEAT Enable/Disable the active cheats on the fly. Required for some cheats. */
2928 if (input_ui_pressed(IPT_UI_TOGGLE_CHEAT))
2929 {
2930 /* Hold down shift to toggle the watchpoints */
2931 if (code_pressed(KEYCODE_LSHIFT) || code_pressed(KEYCODE_RSHIFT))
2932 {
2933 is_watch_visible ^= 1;
2934 usrintf_showmessage("%s %s", ui_getstring (UI_watchpoints), (is_watch_visible ? ui_getstring (UI_on) : ui_getstring (UI_off)));
2935 }
2936 else if (ActiveCheatTotal)
2937 {
2938 CheatEnabled ^= 1;
2939 usrintf_showmessage("%s %s", ui_getstring (UI_cheats), (CheatEnabled ? ui_getstring (UI_on) : ui_getstring (UI_off)));
2940 }
2941 }
2942
2943 #if 0
2944 /* KEYCODE_END loads the "Continue Search" sub-menu of the cheat engine */
2945 if ( keyboard_pressed_memory( KEYCODE_END ) )
2946 {
2947 osd_sound_enable(0);
2948 osd_pause(1);
2949 ContinueSearch(0, 0);
2950 osd_pause(0);
2951 osd_sound_enable(1);
2952 }
2953 #endif
2954 }
2955