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