Develop and Download Open Source Software

Browse CVS Repository

Contents of /mame32jp/mame32jp/src/cheat.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.6 - (show annotations) (download) (as text)
Tue May 7 00:17:30 2002 UTC (21 years, 11 months ago) by zero
Branch: MAIN
CVS Tags: ver_0_60_1, ver0_60_2, ver0_60_3, ver0_60_4, ver0_60_5, HEAD
Changes since 1.5: +8181 -4971 lines
File MIME type: text/x-csrc
*** empty log message ***

1 /******************************************************************************
2 *
3 * cheat.c
4 * by Ian Patterson [ianpatt at pacbell dot net]
5 *
6 * The cheat engine for MAME. Allows you to search for locations in memory
7 * where gameplay-related values are stored, and change them. In other words,
8 * it lets you cheat.
9 *
10 * TODO:
11 * - conflict checking
12 * - look in to adding auto-fire
13 * - bounds checks for relative address cheats
14 *
15 *****************************************************************************/
16
17 /****** Cheat File Specification **********************************************
18
19 Type Field:
20
21 MSB LSB
22 33222222 22221111 11111100 00000000
23 10987654 32109876 54321098 76543210
24
25 [ type ]
26 -------- -------- -------- -------x one-shot cheat
27 -------- -------- -------- -----xx- type
28 00 = normal/delay
29 01 = wait for modification
30 10 = ignore if decrementing
31 11 = watch
32 -------- -------- -------- ---xx--- operation (combined with operation
33 extend bit)
34 [extend = 0]
35 00 = write with mask
36 01 = add/subtract
37 10 = force range
38 11 = set/clear bits (for
39 relative address mode)
40 [extend = 1]
41 00 = unused
42 01 = unused
43 10 = unused
44 11 = nothing
45 -------- -------- -------- xxx----- parameter
46 type == 00 delay in seconds
47 between operations
48 type == 01 delay after
49 modification before
50 operation in seconds
51 type == 10 decrement ignore value
52 type == 11 none
53 [ user-selected value ]
54 -------- -------- -------x -------- enable
55 -------- -------- ------x- -------- minimum displayed value
56 0 = 0
57 1 = 1
58 -------- -------- -----x-- -------- minimum value
59 0 = 0
60 1 = 1
61 -------- -------- ----x--- -------- BCD
62 [ prefill ]
63 -------- -------- --xx---- -------- value/enable
64 00 = disable
65 01 = prefill with 0xFF
66 10 = prefill with 0x00
67 11 = prefill with 0x01
68 [ link / options ]
69 -------- -------- -x------ -------- don't add to list (used for commands)
70 -------- -------x -------- -------- enable
71 -------- ------x- -------- -------- copy previous value
72 -------- -----x-- -------- -------- operation parameter
73 operation == 001 add/subtract
74 0 = add
75 1 = subtract
76 operation == 011 set/clear
77 0 = set
78 1 = clear
79 -------- ----x--- -------- -------- operation extend bit
80 -------- --xx---- -------- -------- bytes used
81 00 = 1
82 01 = 2
83 10 = 3
84 11 = 4
85 -------- -x------ -------- -------- endianness
86 locations associated with a
87 processor
88 0 = same endianness as
89 target processor
90 1 = different endianness
91 generic locations
92 0 = big endian
93 1 = little endian
94 -------- x------- -------- -------- restore previous value on disable
95 [ location / effective address ]
96 ---xxxxx -------- -------- -------- parameter
97 type == 000 CPU index
98 type == 001 region offset
99 (REGION_xxx)
100 type == 010 CPU index
101 type == 011 custom cheat type
102 00000 comment
103 00001 EEPROM
104 00010 select
105 00011 assign activation key
106 00100 enable
107 00101 overclock
108 ... others?
109 type == 100 address size, CPU
110 ---00 8 bit
111 ---01 16 bit
112 ---10 24 bit
113 ---11 32 bit
114 xxx-- cpu
115 xxx----- -------- -------- -------- type
116 000 = standard memory write
117 001 = memory region
118 010 = write handler mapped memory
119 011 = custom
120 100 = relative address (CPU)
121 101 = unused
122 110 = unused
123 111 = unused
124
125 -------- -------- x------- -------- currently unused
126
127 Conversion Table:
128
129 MSB LSB
130 33222222 22221111 11111100 0000 0000
131 10987654 32109876 54321098 7654 3210
132 000xxxxx 00000000 00000000 0000 0000 000
133 000xxxxx 00000000 00000000 0000 0001 001
134 000xxxxx 00000000 00000000 0010 0000 002
135 000xxxxx 00000000 00000000 0100 0000 003
136 000xxxxx 00000000 00000000 1010 0000 004
137 000xxxxx 00000000 00000000 0010 0010 005
138 000xxxxx 00000000 00000000 0100 0010 006
139 000xxxxx 00000000 00000000 1010 0010 007
140 000xxxxx 00000000 00000000 0010 0100 008
141 000xxxxx 00000000 00000000 0100 0100 009
142 000xxxxx 00000000 00000000 0110 0100 010
143 000xxxxx 00000000 00000000 1000 0100 011
144 000xxxxx 00000000 00000000 0010 0011 015
145 000xxxxx 00000000 00000000 0100 0011 016
146 000xxxxx 00000000 00000000 1010 0011 017
147 000xxxxx 00000000 00000000 0000 0000 020 (mask used)
148 000xxxxx 00000000 00000000 0000 0001 021 (mask used)
149 000xxxxx 00000000 00000000 0010 0000 022 (mask used)
150 000xxxxx 00000000 00000000 0100 0000 023 (mask used)
151 000xxxxx 00000000 00000000 1010 0000 024 (mask used)
152 000xxxxx 00000000 00000000 0000 0000 040 (mask used)
153 000xxxxx 00000000 00000000 0000 0001 041 (mask used)
154 000xxxxx 00000000 00000000 0010 0000 042 (mask used)
155 000xxxxx 00000000 00000000 0100 0000 043 (mask used)
156 000xxxxx 00000000 00000000 1010 0000 044 (mask used)
157 000xxxxx 00000000 00000001 0000 0011 060
158 000xxxxx 00000000 00000011 0000 0011 061
159 000xxxxx 00000000 00000111 0000 0011 062
160 000xxxxx 00000000 00001001 0000 0011 063
161 000xxxxx 00000000 00001011 0000 0011 064
162 000xxxxx 00000000 00001111 0000 0011 065
163 000xxxxx 00000000 00000001 0000 0001 070
164 000xxxxx 00000000 00000011 0000 0001 071
165 000xxxxx 00000000 00000111 0000 0001 072
166 000xxxxx 00000000 00001001 0000 0001 073
167 000xxxxx 00000000 00001011 0000 0001 074
168 000xxxxx 00000000 00001111 0000 0001 075
169 001xxxxx 10000000 00000000 0000 0000 100
170 001xxxxx 10000000 00000000 0000 0001 101
171 001xxxxx 10000000 00000000 0000 0000 102
172 001xxxxx 10000000 00000000 0000 0001 103
173 010xxxxx 10000000 00000000 0000 0000 110
174 010xxxxx 10000000 00000000 0000 0001 111
175 010xxxxx 10000000 00000000 0000 0000 112
176 010xxxxx 10000000 00000000 0000 0001 113
177 00000000 00000001 00000000 0000 0000 5xx
178 000xxxxx 00000000 00000000 0000 0110 998
179 01100000 00000000 00000000 0000 0000 999
180
181 Cheat Format:
182
183 :[ drivername ]:[ type ]:[ address ]:[ data ]:[ extended data ]:[ name ]:[ description ]
184
185 (for MESS)
186
187 :[ drivername ]:[ CRC ]:[ type ]:[ address ]:[ data ]:[ extended data ]:[ name ]:[ description ]
188
189 drivername string maximum 8 chars
190 type hex 32 bits
191 CRC hex 32 bits
192 address hex 32 bits
193 data hex 32 bits
194 extended data hex 32 bits
195 name string maximum 255 chars
196 description string maximum 255 chars
197
198 Extended Data Field:
199
200 [ force range ]
201
202 0xAABB
203
204 AA = minimum value accepted
205 BB = maximum value accepted
206
207 [ add/subtract ]
208
209 The field will store either the minimum or maximum boundary for modification,
210 depending on the operation parameter.
211
212 [ write with mask ]
213
214 The field will store a mask containing which bits are modified by the
215 operation. For normal operation, set the mask to 0xFFFFFFFF.
216 Example code: data = (data & ~mask) | (input & mask);
217
218 Copy Previous Value:
219
220 If this field is true, the value for this cheat is determined by taking the
221 value read from the previous cheat and adding the value stored in the data
222 field.
223
224 Relative Address:
225
226 The extend data field will store the the signed offset to be applied to the
227 address read. Because of this, any operation using the extend data field may
228 have interesting results. Use the special set/clear bits operations instead of
229 a masked write.
230
231 Select Cheat Type: (01100010 -------0 -------- --------) 0x62000000
232
233 May be used only as the first cheat of a linked cheat. In the "Enable/Disable
234 Cheat" menu, instead of simple listing On/Off or Set as the menu option, the
235 engine will list the name fields of each of the subcheats. If the current
236 selected subcheat is a one-shot cheat, pressing Enter will activate the
237 currently subcheat. If the subcheat is an on/off cheat, the currently selected
238 subcheat (and only that subcheat) will be activated.
239
240 Assign Activation Key: (01100011 -------- -1------ --------) 0x63004000
241
242 Assigns an activation key to a cheat. Put the index of the cheat you want to
243 modify in the address field, then put the key index in the data field.
244
245 Example: to set the second cheat in the cheat list to activate when "Q" is
246 pressed, add this cheat to the file.
247
248 :gamename:63004000:00000001:00000010:00000000:
249
250 Key Index List:
251
252 A 00 Q 10 6 20 F3 30 [ 40 [/] 50 CAPSLK 60
253 B 01 R 11 7 21 F4 31 ] 41 [*] 51 LWIN 61
254 C 02 S 12 8 22 F5 32 ENTER 42 [-] 52 RWIN 62
255 D 03 T 13 9 23 F6 33 : 43 [+] 53 MENU 63
256 E 04 U 14 [0] 24 F7 34 ' 44 [DEL] 54
257 F 05 V 15 [1] 25 F8 35 \ 45 [ENT] 55
258 G 06 W 16 [2] 26 F9 36 \ 46 PRTSCR 56
259 H 07 X 17 [3] 27 F10 37 , 47 PAUSE 57
260 I 08 Y 18 [4] 28 F11 38 HOME 48 LSHIFT 58
261 J 09 Z 19 [5] 29 F12 39 END 49 RSHIFT 59
262 K 0A 0 1A [6] 2A ESC 3A PGUP 4A LCTRL 5A
263 L 0B 1 1B [7] 2B ~ 3B PGDN 4B RCTRL 5B
264 M 0C 2 1C [8] 2C - 3C LEFT 4C LALT 5C
265 N 0D 3 1D [9] 2D = 3D RIGHT 4D RALT 5D
266 O 0E 4 1E F1 2E BACKSP 3E UP 4E SCRLLK 5E
267 P 0F 5 1F F2 2F TAB 3F DOWN 4F NUMLK 5F
268
269 Pre-Enable: (01100100 -------- -1------ --------) 0x64004000
270
271 Enables a cheat on startup. Put the index of the cheat you want to enable in
272 the address field.
273
274 Example: to activate the eleventh cheat in the cheat list, add this cheat to
275 the file:
276
277 :gamename:64004000:0000000A:00000000:00000000:
278
279 Overclock: (01100101 -------- -1------ --------) 0x65004000
280
281 Overclocks a CPU. Put the CPU index you want in the address field, and the
282 overclocking amount in the data field. Use 16.16 fixed point notation for
283 the overclocking amount.
284
285 Example 1: overclocking CPU #0 by 200%
286
287 :gamename:65004000:00000000:00020000:00000000:
288
289 Example 2: overclocking CPU #3 by 125%
290
291 :gamename:65004000:00000003:00014000:00000000:
292
293 To convert a percent to 16.16 fixed point notation, take the percentage as a
294 decimal value (eg. 65% = .65) and multiply it by 65536. Then, convert the value
295 to hex.
296
297 Cheat Engine Commands:
298
299 These special cheat lines are used to set global preferences for the cheat engine. They follow
300 this format:
301
302 :_command:[ data ]
303
304 The lower byte of the data field stores the command, and the remaining bytes store data
305 for the command. Here is a list of the commands:
306
307 0x00 disable help boxes (once I add them)
308 0x01 use old-style cheat search box (now redundant)
309 0x02 use new-style cheat search box
310 0x03 don't print labels in new-style search menu
311 0x04 auto-save cheats on exit
312
313 So, if you wanted to use the old-style cheat box, you would add this line to your cheat.dat:
314
315 :_command:00000001
316
317 Watches:
318
319 You can specify options for watches using the data field. Specify fields like this:
320
321 MSB LSB
322 33222222 22221111 11111100 00000000
323 10987654 32109876 54321098 76543210
324 -------- -------- -------- xxxxxxxx number of elements - 1
325 -------- -------- xxxxxxxx -------- bytes to skip after each element
326 -------- xxxxxxxx -------- -------- elements per line
327 0 = all on one line
328
329 So, to make a watch on CPU1 address 0064407F with six elements, skipping three bytes after each element,
330 showing two elements per line, you would do this:
331
332 :gamename:00000006:0064407F:00020305:00000000:
333
334 Notes:
335
336 - if you want to have a list of many on/off subcheats, include a "None" option,
337 or there will be no way to disable the cheat
338 - the engine will display "Press Enter to Activate Cheat" if a one-shot cheat
339 is selected
340
341 *******************************************************************************/
342
343 #include "driver.h"
344 #include "ui_text.h"
345 #include "machine/eeprom.h"
346 #include <ctype.h>
347
348 #define OSD_READKEY_KLUDGE 1
349
350 /**** Macros *****************************************************************/
351
352 // easy bitfield extraction and setting
353 // uses *_Shift, *_ShiftedMask, and *_Mask enums
354 #define EXTRACT_FIELD(data, name) (((data) >> k##name##_Shift) & k##name##_ShiftedMask)
355 #define SET_FIELD(data, name, in) (data = (data & ~(k##name##_ShiftedMask << k##name##_Shift)) | (((in) & k##name##_ShiftedMask) << k##name##_Shift))
356 #define TEST_FIELD(data, name) ((data) & k##name##_Mask)
357 #define SET_MASK_FIELD(data, name) ((data) |= k##name##_Mask)
358 #define CLEAR_MASK_FIELD(data, name) ((data) &= ~(k##name##_Mask))
359 #define TOGGLE_MASK_FIELD(data, name) ((data) ^= k##name##_Mask)
360
361 #define DEFINE_BITFIELD_ENUM(name, end, start) k##name##_Shift = (int)(end), \
362 k##name##_ShiftedMask = (int)(0xFFFFFFFF >> (32 - (start - end + 1))), \
363 k##name##_Mask = (int)(k##name##_ShiftedMask << k##name##_Shift)
364
365 #define CHEAT_FILENAME_MAX_LEN 255
366
367 #ifndef LSB_FIRST
368 #define LSB_FIRST 0
369 #endif
370
371 #define kRegionListLength (REGION_MAX - REGION_INVALID)
372
373 /**** Enums ******************************************************************/
374
375 enum
376 {
377 DEFINE_BITFIELD_ENUM(OneShot, 0, 0),
378 DEFINE_BITFIELD_ENUM(Type, 1, 2),
379 DEFINE_BITFIELD_ENUM(Operation, 3, 4),
380 DEFINE_BITFIELD_ENUM(TypeParameter, 5, 7),
381 DEFINE_BITFIELD_ENUM(UserSelectEnable, 8, 8),
382 DEFINE_BITFIELD_ENUM(UserSelectMinimumDisplay, 9, 9),
383 DEFINE_BITFIELD_ENUM(UserSelectMinimum, 10, 10),
384 DEFINE_BITFIELD_ENUM(UserSelectBCD, 11, 11),
385 DEFINE_BITFIELD_ENUM(Prefill, 12, 13),
386 DEFINE_BITFIELD_ENUM(RemoveFromList, 14, 14),
387 DEFINE_BITFIELD_ENUM(LinkEnable, 16, 16),
388 DEFINE_BITFIELD_ENUM(LinkCopyPreviousValue, 17, 17),
389 DEFINE_BITFIELD_ENUM(OperationParameter, 18, 18),
390 DEFINE_BITFIELD_ENUM(OperationExtend, 19, 19),
391 DEFINE_BITFIELD_ENUM(BytesUsed, 20, 21),
392 DEFINE_BITFIELD_ENUM(Endianness, 22, 22),
393 DEFINE_BITFIELD_ENUM(RestorePreviousValue, 23, 23),
394 DEFINE_BITFIELD_ENUM(LocationParameter, 24, 28),
395 DEFINE_BITFIELD_ENUM(LocationType, 29, 31)
396 };
397
398 enum
399 {
400 kType_NormalOrDelay = 0,
401 kType_WaitForModification,
402 kType_IgnoreIfDecrementing,
403 kType_Watch
404 };
405
406 enum
407 {
408 kOperation_WriteMask = 0,
409 kOperation_AddSubtract,
410 kOperation_ForceRange,
411 kOperation_SetOrClearBits,
412 // kOperation_Unused4,
413 // kOperation_Unused5,
414 // kOperation_Unused6,
415 kOperation_None = 7
416 };
417
418 enum
419 {
420 kPrefill_Disable = 0,
421 kPrefill_UseFF,
422 kPrefill_Use00,
423 kPrefill_Use01
424 };
425
426 enum
427 {
428 kLocation_Standard = 0,
429 kLocation_MemoryRegion,
430 kLocation_HandlerMemory,
431 kLocation_Custom,
432 kLocation_IndirectIndexed
433 };
434
435 enum
436 {
437 kCustomLocation_Comment = 0,
438 kCustomLocation_EEPROM,
439 kCustomLocation_Select,
440 kCustomLocation_AssignActivationKey,
441 kCustomLocation_Enable,
442 kCustomLocation_Overclock
443 };
444
445 enum
446 {
447 // set for wait for modification or ignore if decrementing cheats when
448 // the targeted value has changed
449 // cleared after the operation is performed
450 kActionFlag_WasModified = 1 << 0,
451
452 // set for one shot cheats after the operation is performed
453 kActionFlag_OperationDone = 1 << 1,
454
455 // set if the extendData field is being used by something other than a mask value
456 kActionFlag_IgnoreMask = 1 << 2,
457
458 // set if the lastValue field contains valid data and can be restored if needed
459 kActionFlag_LastValueGood = 1 << 3,
460
461 kActionFlag_StateMask = kActionFlag_OperationDone |
462 kActionFlag_LastValueGood,
463 kActionFlag_InfoMask = kActionFlag_WasModified |
464 kActionFlag_IgnoreMask
465 };
466
467 enum
468 {
469 // true when the cheat is active
470 kCheatFlag_Active = 1 << 0,
471
472 // true if the cheat is entirely one shot
473 kCheatFlag_OneShot = 1 << 1,
474
475 // true if the cheat is entirely null (ex. a comment)
476 kCheatFlag_Null = 1 << 2,
477
478 // true if the cheat contains a user-select element
479 kCheatFlag_UserSelect = 1 << 3,
480
481 // true if the cheat is a select cheat
482 kCheatFlag_Select = 1 << 4,
483
484 // true if the activation key is being pressed
485 kCheatFlag_ActivationKeyPressed = 1 << 5,
486
487 // true if the cheat has been assigned an activation key
488 kCheatFlag_HasActivationKey = 1 << 6,
489
490 // true if the cheat has been edited or is a new cheat
491 kCheatFlag_Dirty = 1 << 7,
492
493 // masks
494 kCheatFlag_StateMask = kCheatFlag_Active,
495 kCheatFlag_InfoMask = kCheatFlag_OneShot |
496 kCheatFlag_Null |
497 kCheatFlag_UserSelect |
498 kCheatFlag_Select |
499 kCheatFlag_ActivationKeyPressed |
500 kCheatFlag_HasActivationKey,
501 kCheatFlag_PersistantMask = kCheatFlag_Active |
502 kCheatFlag_HasActivationKey |
503 kCheatFlag_ActivationKeyPressed |
504 kCheatFlag_Dirty
505 };
506
507 enum
508 {
509 kWatchLabel_None = 0,
510 kWatchLabel_Address,
511 kWatchLabel_String,
512
513 kWatchLabel_MaxPlusOne
514 };
515
516 enum
517 {
518 kWatchDisplayType_Hex = 0,
519 kWatchDisplayType_Decimal,
520 kWatchDisplayType_Binary,
521
522 kWatchDisplayType_MaxPlusOne
523 };
524
525 enum
526 {
527 kVerticalKeyRepeatRate = 8,
528 kHorizontalFastKeyRepeatRate = 5,
529 kHorizontalSlowKeyRepeatRate = 8
530 };
531
532 enum
533 {
534 // true if enabled for search
535 kRegionFlag_Enabled = 1 << 0,
536
537 // true if the memory region has no mapped memory
538 // and uses a memory handler
539 kRegionFlag_UsesHandler = 1 << 1
540 };
541
542 enum
543 {
544 kRegionType_CPU = 0,
545 kRegionType_Memory
546 };
547
548 enum
549 {
550 kSearchSpeed_Fast = 0, // RAM + some banks
551 kSearchSpeed_Medium, // RAM + BANKx
552 kSearchSpeed_Slow, // all memory areas except ROM, NOP, and custom handlers
553 kSearchSpeed_VerySlow, // all memory areas except ROM and NOP
554 kSearchSpeed_AllMemory, // entire CPU address space
555
556 kSearchSpeed_Max = kSearchSpeed_AllMemory
557 };
558
559 enum
560 {
561 kSearchOperand_Current = 0,
562 kSearchOperand_Previous,
563 kSearchOperand_First,
564 kSearchOperand_Value,
565
566 kSearchOperand_Max = kSearchOperand_Value
567 };
568
569 enum
570 {
571 kSearchSize_8Bit = 0,
572 kSearchSize_16Bit,
573 kSearchSize_32Bit,
574 kSearchSize_1Bit,
575
576 kSearchSize_Max = kSearchSize_1Bit
577 };
578
579 enum
580 {
581 kSearchComparison_LessThan = 0,
582 kSearchComparison_GreaterThan,
583 kSearchComparison_EqualTo,
584 kSearchComparison_LessThanOrEqualTo,
585 kSearchComparison_GreaterThanOrEqualTo,
586 kSearchComparison_NotEqual,
587 kSearchComparison_IncreasedBy,
588 kSearchComparison_NearTo,
589
590 kSearchComparison_Max = kSearchComparison_NearTo
591 };
592
593 enum
594 {
595 kEnergy_Equals = 0,
596 kEnergy_Less,
597 kEnergy_Greater,
598 kEnergy_LessOrEquals,
599 kEnergy_GreaterOrEquals,
600 kEnergy_NotEquals,
601
602 kEnergy_Max = kEnergy_NotEquals
603 };
604
605 /**** Structs ****************************************************************/
606
607 struct CheatAction
608 {
609 UINT32 type;
610 UINT32 address;
611 UINT32 data;
612 UINT32 extendData;
613 UINT32 originalDataField;
614
615 INT32 frameTimer;
616 UINT32 lastValue;
617
618 UINT32 flags;
619
620 UINT8 ** cachedPointer;
621 UINT32 cachedOffset;
622
623 char * optionalName;
624 };
625
626 typedef struct CheatAction CheatAction;
627
628 struct CheatEntry
629 {
630 char * name;
631 char * comment;
632
633 INT32 actionListLength;
634 CheatAction * actionList;
635
636 int activationKey;
637
638 UINT32 flags;
639 int selection;
640 };
641
642 typedef struct CheatEntry CheatEntry;
643
644 struct WatchInfo
645 {
646 UINT32 address;
647 UINT8 cpu;
648 UINT8 numElements;
649 UINT8 elementBytes;
650 UINT8 labelType;
651 UINT8 displayType;
652 UINT8 skip;
653 UINT8 elementsPerLine;
654
655 UINT16 x, y;
656
657 CheatEntry * linkedCheat;
658
659 char label[256];
660 };
661
662 typedef struct WatchInfo WatchInfo;
663
664 struct SearchRegion
665 {
666 UINT32 address;
667 UINT32 length;
668
669 UINT8 targetType;
670 UINT8 targetIdx;
671
672 UINT8 flags;
673
674 UINT8 * cachedPointer;
675 const struct Memory_WriteAddress
676 * writeHandler;
677
678 UINT8 * first;
679 UINT8 * last;
680
681 UINT8 * status;
682
683 UINT8 * backupLast;
684 UINT8 * backupStatus;
685
686 // 12345678 - 12345678 BANK31
687 char name[32];
688
689 UINT32 numResults;
690 UINT32 oldNumResults;
691 };
692
693 typedef struct SearchRegion SearchRegion;
694
695 struct OldSearchOptions
696 {
697 UINT8 energy;
698 UINT8 status;
699 UINT8 slow;
700 UINT32 value;
701 UINT32 delta;
702 };
703
704 typedef struct OldSearchOptions OldSearchOptions;
705
706 struct SearchInfo
707 {
708 INT32 regionListLength;
709 SearchRegion * regionList;
710
711 char * name;
712
713 INT8 bytes; // 0 = 1, 1 = 2, 2 = 4, 3 = bit
714 UINT8 swap;
715 UINT8 sign;
716 INT8 lhs;
717 INT8 rhs;
718 INT8 comparison;
719
720 UINT8 targetType; // cpu/region
721 UINT8 targetIdx; // cpu or region index
722
723 UINT32 value;
724
725 UINT8 searchSpeed;
726
727 UINT32 numResults;
728 UINT32 oldNumResults;
729
730 INT32 currentRegionIdx;
731 INT32 currentResultsPage;
732
733 UINT8 backupValid;
734
735 OldSearchOptions oldOptions;
736 };
737
738 typedef struct SearchInfo SearchInfo;
739
740 struct CPUInfo
741 {
742 UINT8 type;
743 UINT8 dataBits;
744 UINT8 addressBits;
745 UINT8 addressCharsNeeded;
746 UINT32 addressMask;
747 UINT8 endianness;
748 };
749
750 typedef struct CPUInfo CPUInfo;
751
752 struct MenuStringList
753 {
754 const char ** mainList; // editable menu item lists
755 const char ** subList;
756 char * flagList;
757
758 char ** mainStrings; // lists of usable strings
759 char ** subStrings;
760
761 char * buf; // string storage
762
763 UINT32 length; // number of menu items supported
764 UINT32 numStrings; // number of strings supported
765 UINT32 mainStringLength; // max length of main string
766 UINT32 subStringLength; // max length of sub string
767 };
768
769 typedef struct MenuStringList MenuStringList;
770
771 struct MenuItemInfoStruct
772 {
773 UINT32 subcheat;
774 UINT32 fieldType;
775 UINT32 extraData;
776 };
777
778 typedef struct MenuItemInfoStruct MenuItemInfoStruct;
779
780 /**** Exported Globals *******************************************************/
781
782 int he_did_cheat = 0;
783 char * cheatfile = NULL;
784
785 /**** Local Globals **********************************************************/
786
787 static CheatEntry * cheatList = NULL;
788 static INT32 cheatListLength = 0;
789
790 static WatchInfo * watchList = NULL;
791 static INT32 watchListLength = 0;
792
793 static SearchInfo * searchList = NULL;
794 static INT32 searchListLength = 0;
795 static INT32 currentSearchIdx = 0;
796
797 static CPUInfo cpuInfoList[MAX_CPU];
798 static CPUInfo regionInfoList[kRegionListLength];
799
800 static int cheatEngineWasActive = 0;
801 static int foundCheatDatabase = 0;
802 static int cheatsDisabled = 0;
803 static int watchesDisabled = 0;
804
805 static int fullMenuPageHeight = 0;
806
807 static char mainDatabaseName[CHEAT_FILENAME_MAX_LEN + 1];
808
809 static MenuStringList menuStrings;
810
811 static MenuItemInfoStruct * menuItemInfo;
812 static INT32 menuItemInfoLength = 0;
813
814 static int useClassicSearchBox = 1;
815 static int dontPrintNewLabels = 0;
816 static int autoSaveEnabled = 0;
817
818 #ifdef MESS
819 static UINT32 * deviceCRCList = NULL;
820 static INT32 deviceCRCListLength = 0;
821
822 static UINT32 thisGameCRC = 0;
823 #endif
824
825 static const char * kCheatNameTemplates[] =
826 {
827 "Infinite Lives",
828 "Infinite Lives PL1",
829 "Infinite Lives PL2",
830 "Infinite Time",
831 "Infinite Time PL1",
832 "Infinite Time PL2",
833 "Invincibility",
834 "Invincibility PL1",
835 "Invincibility PL2",
836 "Infinite Energy",
837 "Infinite Energy PL1",
838 "Infinite Energy PL2",
839 "Select next level",
840 "Select current level",
841 "Infinite Ammo",
842 "Infinite Ammo PL1",
843 "Infinite Ammo PL2",
844 "Infinite Bombs",
845 "Infinite Bombs PL1",
846 "Infinite Bombs PL2",
847 "Infinite Smart Bombs",
848 "Infinite Smart Bombs PL1",
849 "Infinite Smart Bombs PL2",
850 "Select Score PL1",
851 "Select Score PL2",
852 "Drain all Energy Now! PL1",
853 "Drain all Energy Now! PL2",
854 "Watch me for good answer",
855 "Infinite",
856 "Always have",
857 "Get",
858 "Lose",
859 "Finish this",
860 "---> <ENTER> To Edit <---",
861 "\0"
862 };
863
864 static CPUInfo rawCPUInfo =
865 {
866 0, // type
867 8, // dataBits
868 8, // addressBits
869 1, // addressCharsNeeded
870 CPU_IS_BE // endianness
871 };
872
873 static const int kSearchByteIncrementTable[] =
874 {
875 1,
876 2,
877 4,
878 1
879 };
880
881 static const char * kSearchByteNameTable[] =
882 {
883 "1",
884 "2",
885 "4",
886 "Bit"
887 };
888
889 static const int kSearchByteDigitsTable[] =
890 {
891 2,
892 4,
893 8,
894 1
895 };
896
897 static const int kSearchByteDecDigitsTable[] =
898 {
899 3,
900 5,
901 10,
902 1
903 };
904
905 static const UINT32 kSearchByteMaskTable[] =
906 {
907 0x000000FF,
908 0x0000FFFF,
909 0xFFFFFFFF,
910 0x00000001
911 };
912
913 static const UINT32 kSearchByteSignBitTable[] =
914 {
915 0x00000080,
916 0x00008000,
917 0x80000000,
918 0x00000000
919 };
920
921 static const UINT32 kSearchByteUnsignedMaskTable[] =
922 {
923 0x0000007F,
924 0x00007FFF,
925 0x7FFFFFFF,
926 0x00000001
927 };
928
929 static const UINT32 kCheatSizeMaskTable[] =
930 {
931 0x000000FF,
932 0x0000FFFF,
933 0x00FFFFFF,
934 0xFFFFFFFF
935 };
936
937 static const UINT32 kCheatSizeDigitsTable[] =
938 {
939 2,
940 4,
941 6,
942 8
943 };
944
945 static const char * kOperandNameTable[] =
946 {
947 "Current Data",
948 "Previous Data",
949 "First Data",
950 "Value"
951 };
952
953 static const char * kComparisonNameTable[] =
954 {
955 "Less",
956 "Greater",
957 "Equal",
958 "Less Or Equal",
959 "Greater Or Equal",
960 "Not Equal",
961 "Increased By Value",
962 "Near To"
963 };
964
965 static const int kByteConversionTable[] =
966 {
967 kSearchSize_8Bit,
968 kSearchSize_16Bit,
969 kSearchSize_32Bit,
970 kSearchSize_32Bit
971 };
972
973 static const int kWatchSizeConversionTable[] =
974 {
975 kSearchSize_8Bit,
976 kSearchSize_16Bit,
977 kSearchSize_32Bit,
978 kSearchSize_8Bit
979 };
980
981 static const int kSearchOperandNeedsInit[] =
982 {
983 0,
984 1,
985 1,
986 0
987 };
988
989 static const int kOldEnergyComparisonTable[] =
990 {
991 kSearchComparison_EqualTo,
992 kSearchComparison_LessThan,
993 kSearchComparison_GreaterThan,
994 kSearchComparison_LessThanOrEqualTo,
995 kSearchComparison_GreaterThanOrEqualTo,
996 kSearchComparison_NotEqual
997 };
998
999 static const int kOldStatusComparisonTable[] =
1000 {
1001 kSearchComparison_EqualTo,
1002 kSearchComparison_NotEqual
1003 };
1004
1005 /**** Function Prototypes ****************************************************/
1006
1007 static int ShiftKeyPressed(void);
1008 static int ControlKeyPressed(void);
1009 static int AltKeyPressed(void);
1010
1011 static int UIPressedRepeatThrottle(int code, int baseSpeed);
1012 static int ReadHexInput(void);
1013
1014 static char * DoDynamicEditTextField(char * buf);
1015 static void DoStaticEditTextField(char * buf, int size);
1016 static UINT32 DoEditHexField(UINT32 data);
1017 static INT32 DoEditDecField(INT32 data, INT32 min, INT32 max);
1018
1019 static UINT32 BCDToDecimal(UINT32 value);
1020 static UINT32 DecimalToBCD(UINT32 value);
1021
1022 static void RebuildStringTables(void);
1023 static void RequestStrings(UINT32 length, UINT32 numStrings, UINT32 mainStringLength, UINT32 subStringLength);
1024 static void InitStringTable(void);
1025 static void FreeStringTable(void);
1026
1027 static INT32 UserSelectValueMenu(struct mame_bitmap * bitmap, int selection, CheatEntry * entry);
1028 static int EnableDisableCheatMenu(struct mame_bitmap * bitmap, int selection, int firstTime);
1029 static int EditCheatMenu(struct mame_bitmap * bitmap, CheatEntry * entry, int selection);
1030 static int DoSearchMenuClassic(struct mame_bitmap * bitmap, int selection, int startNew);
1031 static int DoSearchMenu(struct mame_bitmap * bitmap, int selection, int startNew);
1032 static int AddEditCheatMenu(struct mame_bitmap * bitmap, int selection);
1033 static int ViewSearchResults(struct mame_bitmap * bitmap, int selection, int firstTime);
1034 static int ChooseWatch(struct mame_bitmap * bitmap, int selection);
1035 static int EditWatch(struct mame_bitmap * bitmap, WatchInfo * entry, int selection);
1036 static INT32 DisplayHelp(struct mame_bitmap * bitmap, int selection);
1037 static int SelectOptions(struct mame_bitmap * bitmap, int selection);
1038 static int SelectSearchRegions(struct mame_bitmap * bitmap, int selection, SearchInfo * search);
1039 static int SelectSearch(struct mame_bitmap * bitmap, int selection);
1040
1041 static char * CreateStringCopy(char * buf);
1042
1043 static void ResizeCheatList(UINT32 newLength);
1044 static void ResizeCheatListNoDispose(UINT32 newLength);
1045 static void AddCheatBefore(UINT32 idx);
1046 static void DeleteCheatAt(UINT32 idx);
1047 static void DisposeCheat(CheatEntry * entry);
1048 static CheatEntry * GetNewCheat(void);
1049
1050 static void ResizeCheatActionList(CheatEntry * entry, UINT32 newLength);
1051 static void ResizeCheatActionListNoDispose(CheatEntry * entry, UINT32 newLength);
1052 static void AddActionBefore(CheatEntry * entry, UINT32 idx);
1053 static void DeleteActionAt(CheatEntry * entry, UINT32 idx);
1054 static void DisposeAction(CheatAction * action);
1055
1056 static void InitWatch(WatchInfo * info, UINT32 idx);
1057 static void ResizeWatchList(UINT32 newLength);
1058 static void ResizeWatchListNoDispose(UINT32 newLength);
1059 static void AddWatchBefore(UINT32 idx);
1060 static void DeleteWatchAt(UINT32 idx);
1061 static void DisposeWatch(WatchInfo * watch);
1062 static WatchInfo * GetUnusedWatch(void);
1063 static void AddCheatFromWatch(WatchInfo * watch);
1064 static void SetupCheatFromWatchAsWatch(CheatEntry * entry, WatchInfo * watch);
1065
1066 static void ResizeSearchList(UINT32 newLength);
1067 static void ResizeSearchListNoDispose(UINT32 newLength);
1068 static void AddSearchBefore(UINT32 idx);
1069 static void DeleteSearchAt(UINT32 idx);
1070 static void DisposeSearchRegions(SearchInfo * info);
1071 static void DisposeSearch(UINT32 idx);
1072 static SearchInfo * GetCurrentSearch(void);
1073
1074 static void FillBufferFromRegion(SearchRegion * region, UINT8 * buf);
1075 static UINT32 ReadRegionData(SearchRegion * region, UINT32 offset, UINT8 size, UINT8 swap);
1076 static void BackupSearch(SearchInfo * info);
1077 static void RestoreSearchBackup(SearchInfo * info);
1078 static void BackupRegion(SearchRegion * region);
1079 static void RestoreRegionBackup(SearchRegion * region);
1080 static void SetSearchRegionDefaultName(SearchRegion * region);
1081 static void AllocateSearchRegions(SearchInfo * info);
1082 static void BuildSearchRegions(SearchInfo * info);
1083
1084 static int ConvertOldCode(int code, int cpu, int * data, int * extendData);
1085 static int MatchCommandCheatLine(char * buf);
1086 static void HandleLocalCommandCheat(UINT32 type, UINT32 address, UINT32 data, UINT32 extendData, char * name, char * description);
1087
1088 static void LoadCheatFile(char * fileName);
1089 static void LoadCheatDatabase(void);
1090 static void DisposeCheatDatabase(void);
1091
1092 static void SaveCheat(CheatEntry * entry);
1093 static void DoAutoSaveCheats(void);
1094 static void AddCheatFromResult(SearchInfo * search, SearchRegion * region, UINT32 address);
1095 static void AddCheatFromFirstResult(SearchInfo * search);
1096 static void AddWatchFromResult(SearchInfo * search, SearchRegion * region, UINT32 address);
1097
1098 static UINT32 SearchSignExtend(SearchInfo * search, UINT32 value);
1099 static UINT32 ReadSearchOperand(UINT8 type, SearchInfo * search, SearchRegion * region, UINT32 address);
1100 static UINT32 ReadSearchOperandBit(UINT8 type, SearchInfo * search, SearchRegion * region, UINT32 address);
1101 static UINT8 DoSearchComparison(SearchInfo * search, UINT32 lhs, UINT32 rhs);
1102 static UINT32 DoSearchComparisonBit(SearchInfo * search, UINT32 lhs, UINT32 rhs);
1103 //static UINT8 IsRegionOffsetValid(SearchInfo * search, SearchRegion * region, UINT32 offset);
1104
1105 #define IsRegionOffsetValid IsRegionOffsetValidBit
1106
1107 static UINT8 IsRegionOffsetValidBit(SearchInfo * search, SearchRegion * region, UINT32 offset);
1108 static void InvalidateRegionOffset(SearchInfo * search, SearchRegion * region, UINT32 offset);
1109 static void InvalidateRegionOffsetBit(SearchInfo * search, SearchRegion * region, UINT32 offset, UINT32 invalidate);
1110 static void InvalidateEntireRegion(SearchInfo * search, SearchRegion * region);
1111
1112 static void InitializeNewSearch(SearchInfo * search);
1113 static void UpdateSearch(SearchInfo * search);
1114
1115 static void DoSearch(SearchInfo * search);
1116
1117 static UINT8 ** LookupHandlerMemory(UINT8 cpu, UINT32 address, UINT32 * outRelativeAddress);
1118
1119 static UINT32 DoCPURead(UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap);
1120 static UINT32 DoMemoryRead(UINT8 * buf, UINT32 address, UINT8 bytes, UINT8 swap, CPUInfo * info);
1121 static void DoCPUWrite(UINT32 data, UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap);
1122 static void DoMemoryWrite(UINT32 data, UINT8 * buf, UINT32 address, UINT8 bytes, UINT8 swap, CPUInfo * info);
1123
1124 static UINT8 CPUNeedsSwap(UINT8 cpu);
1125 static UINT8 RegionNeedsSwap(UINT8 region);
1126
1127 static CPUInfo * GetCPUInfo(UINT8 cpu);
1128 static CPUInfo * GetRegionCPUInfo(UINT8 region);
1129
1130 static UINT32 SwapAddress(UINT32 address, UINT8 dataSize, CPUInfo * info);
1131
1132 static UINT32 ReadData(CheatAction * action);
1133 static void WriteData(CheatAction * action, UINT32 data);
1134
1135 static void WatchCheatEntry(CheatEntry * entry, UINT8 associate);
1136 static void AddActionWatch(CheatAction * action, CheatEntry * entry);
1137
1138 static void ResetAction(CheatAction * action);
1139 static void ActivateCheat(CheatEntry * entry);
1140 static void DeactivateCheat(CheatEntry * entry);
1141 static void TempDeactivateCheat(CheatEntry * entry);
1142
1143 static void DoCheatOperation(CheatAction * action);
1144 static void DoCheatAction(CheatAction * action);
1145 static void DoCheatEntry(CheatEntry * entry);
1146
1147 static void UpdateAllCheatInfo(void);
1148 static void UpdateCheatInfo(CheatEntry * entry, UINT8 isLoadTime);
1149
1150 static int IsAddressInRange(CheatAction * action, UINT32 length);
1151
1152 static void BuildCPUInfoList(void);
1153
1154 #ifdef MESS
1155 static void BuildCRCTable(void);
1156
1157 static int MatchesCRCTable(UINT32 crc);
1158 #endif
1159
1160 /**** Imports ****************************************************************/
1161
1162 /**** Code *******************************************************************/
1163
1164 static int ShiftKeyPressed(void)
1165 {
1166 return (code_pressed(KEYCODE_LSHIFT) || code_pressed(KEYCODE_RSHIFT));
1167 }
1168
1169 static int ControlKeyPressed(void)
1170 {
1171 return (code_pressed(KEYCODE_LCONTROL) || code_pressed(KEYCODE_RCONTROL));
1172 }
1173
1174 static int AltKeyPressed(void)
1175 {
1176 return (code_pressed(KEYCODE_LALT) || code_pressed(KEYCODE_RALT));
1177 }
1178
1179 #if 1
1180
1181 #if OSD_READKEY_KLUDGE
1182
1183 /* dirty hack until osd_readkey_unicode is supported in MAMEW
1184 re-implementation of osd_readkey_unicode */
1185 static int ReadKeyAsync(int flush)
1186 {
1187 int code;
1188
1189 if(flush)
1190 {
1191 while(code_read_async() != CODE_NONE) ;
1192
1193 return 0;
1194 }
1195
1196 while(1)
1197 {
1198 code = code_read_async();
1199
1200 if(code == CODE_NONE)
1201 {
1202 return 0;
1203 }
1204 else if((code >= KEYCODE_A) && (code <= KEYCODE_Z))
1205 {
1206 if(ShiftKeyPressed())
1207 {
1208 return 'A' + (code - KEYCODE_A);
1209 }
1210 else
1211 {
1212 return 'a' + (code - KEYCODE_A);
1213 }
1214 }
1215 else if((code >= KEYCODE_0) && (code <= KEYCODE_9))
1216 {
1217 if(ShiftKeyPressed())
1218 {
1219 return ")!@#$%^&*("[code - KEYCODE_0];
1220 }
1221 else
1222 {
1223 return '0' + (code - KEYCODE_0);
1224 }
1225 }
1226 else if((code >= KEYCODE_0_PAD) && (code <= KEYCODE_0_PAD))
1227 {
1228 return '0' + (code - KEYCODE_0_PAD);
1229 }
1230 else if(code == KEYCODE_TILDE)
1231 {
1232 if(ShiftKeyPressed())
1233 {
1234 return '~';
1235 }
1236 else
1237 {
1238 return '`';
1239 }
1240 }
1241 else if(code == KEYCODE_MINUS)
1242 {
1243 if(ShiftKeyPressed())
1244 {
1245 return '_';
1246 }
1247 else
1248 {
1249 return '-';
1250 }
1251 }
1252 else if(code == KEYCODE_EQUALS)
1253 {
1254 if(ShiftKeyPressed())
1255 {
1256 return '+';
1257 }
1258 else
1259 {
1260 return '=';
1261 }
1262 }
1263 else if(code == KEYCODE_BACKSPACE)
1264 {
1265 return 0x08;
1266 }
1267 else if(code == KEYCODE_OPENBRACE)
1268 {
1269 if(ShiftKeyPressed())
1270 {
1271 return '{';
1272 }
1273 else
1274 {
1275 return '[';
1276 }
1277 }
1278 else if(code == KEYCODE_CLOSEBRACE)
1279 {
1280 if(ShiftKeyPressed())
1281 {
1282 return '}';
1283 }
1284 else
1285 {
1286 return ']';
1287 }
1288 }
1289 else if(code == KEYCODE_COLON)
1290 {
1291 if(ShiftKeyPressed())
1292 {
1293 return ':';
1294 }
1295 else
1296 {
1297 return ';';
1298 }
1299 }
1300 else if(code == KEYCODE_QUOTE)
1301 {
1302 if(ShiftKeyPressed())
1303 {
1304 return '\"';
1305 }
1306 else
1307 {
1308 return '\'';
1309 }
1310 }
1311 else if(code == KEYCODE_BACKSLASH)
1312 {
1313 if(ShiftKeyPressed())
1314 {
1315 return '|';
1316 }
1317 else
1318 {
1319 return '\\';
1320 }
1321 }
1322 else if(code == KEYCODE_COMMA)
1323 {
1324 if(ShiftKeyPressed())
1325 {
1326 return '<';
1327 }
1328 else
1329 {
1330 return ',';
1331 }
1332 }
1333 else if(code == KEYCODE_STOP)
1334 {
1335 if(ShiftKeyPressed())
1336 {
1337 return '>';
1338 }
1339 else
1340 {
1341 return '.';
1342 }
1343 }
1344 else if(code == KEYCODE_SLASH)
1345 {
1346 if(ShiftKeyPressed())
1347 {
1348 return '?';
1349 }
1350 else
1351 {
1352 return '/';
1353 }
1354 }
1355 else if(code == KEYCODE_SLASH_PAD)
1356 {
1357 return '/';
1358 }
1359 else if(code == KEYCODE_ASTERISK)
1360 {
1361 return '*';
1362 }
1363 else if(code == KEYCODE_MINUS_PAD)
1364 {
1365 return '-';
1366 }
1367 else if(code == KEYCODE_PLUS_PAD)
1368 {
1369 return '+';
1370 }
1371 else if(code == KEYCODE_SPACE)
1372 {
1373 return ' ';
1374 }
1375 }
1376 }
1377
1378 #define osd_readkey_unicode ReadKeyAsync
1379
1380 #endif
1381
1382 #endif
1383
1384 static int UIPressedRepeatThrottle(int code, int baseSpeed)
1385 {
1386 static int lastCode = -1;
1387 static int lastSpeed = -1;
1388 static int incrementTimer = 0;
1389 int pressed = 0;
1390
1391 const int kDelayRampTimer = 10;
1392
1393 if(seq_pressed(input_port_type_seq(code)))
1394 {
1395 if(lastCode != code)
1396 {
1397 lastCode = code;
1398 lastSpeed = baseSpeed;
1399 incrementTimer = kDelayRampTimer * lastSpeed;
1400 }
1401 else
1402 {
1403 incrementTimer--;
1404
1405 if(incrementTimer <= 0)
1406 {
1407 incrementTimer = kDelayRampTimer * lastSpeed;
1408
1409 lastSpeed /= 2;
1410 if(lastSpeed < 1)
1411 lastSpeed = 1;
1412
1413 pressed = 1;
1414 }
1415 }
1416 }
1417 else
1418 {
1419 if(lastCode == code)
1420 {
1421 lastCode = -1;
1422 }
1423 }
1424
1425 return input_ui_pressed_repeat(code, lastSpeed);
1426 }
1427
1428 static int ReadHexInput(void)
1429 {
1430 int i;
1431
1432 for(i = 0; i < 10; i++)
1433 {
1434 if(code_pressed_memory(KEYCODE_0 + i))
1435 {
1436 return i;
1437 }
1438 }
1439
1440 for(i = 0; i < 10; i++)
1441 {
1442 if(code_pressed_memory(KEYCODE_0_PAD + i))
1443 {
1444 return i;
1445 }
1446 }
1447
1448 for(i = 0; i < 6; i++)
1449 {
1450 if(code_pressed_memory(KEYCODE_A + i))
1451 {
1452 return i + 10;
1453 }
1454 }
1455
1456 return -1;
1457 }
1458
1459 static char * DoDynamicEditTextField(char * buf)
1460 {
1461 char code = osd_readkey_unicode(0) & 0xFF;
1462
1463 if(code == 0x08)
1464 {
1465 if(buf)
1466 {
1467 UINT32 length = strlen(buf);
1468
1469 if(length > 0)
1470 {
1471 buf[length - 1] = 0;
1472
1473 if(length > 1)
1474 {
1475 buf = realloc(buf, length);
1476 }
1477 else
1478 {
1479 free(buf);
1480
1481 buf = NULL;
1482 }
1483 }
1484 }
1485 }
1486 else if(isprint(code))
1487 {
1488 if(buf)
1489 {
1490 UINT32 length = strlen(buf);
1491
1492 buf = realloc(buf, length + 2);
1493
1494 buf[length] = code;
1495 buf[length + 1] = 0;
1496 }
1497 else
1498 {
1499 buf = malloc(2);
1500
1501 buf[0] = code;
1502 buf[1] = 0;
1503 }
1504 }
1505
1506 return buf;
1507 }
1508
1509 static void DoStaticEditTextField(char * buf, int size)
1510 {
1511 char code = osd_readkey_unicode(0) & 0xFF;
1512 UINT32 length;
1513
1514 if(!buf)
1515 return;
1516
1517 length = strlen(buf);
1518
1519 if(code == 0x08)
1520 {
1521 if(length > 0)
1522 {
1523 buf[length - 1] = 0;
1524 }
1525 }
1526 else if(isprint(code))
1527 {
1528 if(length + 1 < size)
1529 {
1530 buf[length] = code;
1531 buf[length + 1] = 0;
1532 }
1533 }
1534 }
1535
1536 static UINT32 DoEditHexField(UINT32 data)
1537 {
1538 INT8 key;
1539
1540 key = ReadHexInput();
1541
1542 if(key != -1)
1543 {
1544 data <<= 4;
1545 data |= key;
1546 }
1547
1548 return data;
1549 }
1550
1551 static INT32 DoEditDecField(INT32 data, INT32 min, INT32 max)
1552 {
1553 char code = osd_readkey_unicode(0) & 0xFF;
1554
1555 if((code >= '0') && (code <= '9'))
1556 {
1557 data *= 10;
1558 data += (code - '0');
1559 }
1560 else if(code == '-')
1561 {
1562 data = -data;
1563 }
1564 else if(code == 0x08)
1565 {
1566 data /= 10;
1567 }
1568
1569 if(data < min)
1570 data = min;
1571 if(data > max)
1572 data = max;
1573
1574 return data;
1575 }
1576
1577 void InitCheat(void)
1578 {
1579 //logerror("InitCheat: OSD_READKEY_KLUDGE = %d LSB_FIRST = %d\n", OSD_READKEY_KLUDGE, LSB_FIRST);
1580
1581 he_did_cheat = 0;
1582
1583 cheatList = NULL;
1584 cheatListLength = 0;
1585
1586 watchList = NULL;
1587 watchListLength = 0;
1588
1589 searchList = NULL;
1590 searchListLength = 0;
1591
1592 #ifdef MESS
1593 deviceCRCList = NULL;
1594 deviceCRCListLength = 0;
1595 thisGameCRC = 0;
1596
1597 BuildCRCTable();
1598 #endif
1599
1600 currentSearchIdx = 0;
1601 foundCheatDatabase = 0;
1602 cheatsDisabled = 0;
1603 watchesDisabled = 0;
1604
1605 useClassicSearchBox = 1;
1606 dontPrintNewLabels = 0;
1607 autoSaveEnabled = 0;
1608
1609 fullMenuPageHeight = Machine->uiheight / (3 * Machine->uifontheight / 2) - 1;
1610
1611 BuildCPUInfoList();
1612
1613 LoadCheatDatabase();
1614
1615 ResizeSearchList(1);
1616 ResizeWatchList(20);
1617
1618 BuildSearchRegions(GetCurrentSearch());
1619 AllocateSearchRegions(GetCurrentSearch());
1620
1621 InitStringTable();
1622 }
1623
1624 void StopCheat(void)
1625 {
1626 int i;
1627
1628 if(autoSaveEnabled)
1629 {
1630 DoAutoSaveCheats();
1631 }
1632
1633 DisposeCheatDatabase();
1634
1635 if(watchList)
1636 {
1637 for(i = 0; i < watchListLength; i++)
1638 {
1639 DisposeWatch(&watchList[i]);
1640 }
1641
1642 free(watchList);
1643
1644 watchList = NULL;
1645 }
1646
1647 if(searchList)
1648 {
1649 for(i = 0; i < searchListLength; i++)
1650 {
1651 DisposeSearch(i);
1652 }
1653
1654 free(searchList);
1655
1656 searchList = NULL;
1657 }
1658
1659 FreeStringTable();
1660
1661 free(menuItemInfo);
1662 menuItemInfo = NULL;
1663
1664 #ifdef MESS
1665 free(deviceCRCList);
1666 deviceCRCList = NULL;
1667
1668 deviceCRCListLength = 0;
1669 thisGameCRC = 0;
1670 #endif
1671
1672 cheatListLength = 0;
1673 watchListLength = 0;
1674 searchListLength = 0;
1675 currentSearchIdx = 0;
1676 cheatEngineWasActive = 0;
1677 foundCheatDatabase = 0;
1678 cheatsDisabled = 0;
1679 watchesDisabled = 0;
1680 mainDatabaseName[0] = 0;
1681 menuItemInfoLength = 0;
1682 useClassicSearchBox = 1;
1683 dontPrintNewLabels = 0;
1684 autoSaveEnabled = 0;
1685 }
1686
1687 int cheat_menu(struct mame_bitmap * bitmap, int selection)
1688 {
1689 enum
1690 {
1691 kMenu_EnableDisable = 0,
1692 kMenu_AddEdit,
1693 kMenu_StartSearch,
1694 kMenu_ContinueSearch,
1695 kMenu_ViewResults,
1696 kMenu_RestoreSearch,
1697 kMenu_ChooseWatch,
1698 kMenu_DisplayHelp,
1699 kMenu_Options,
1700 kMenu_Return,
1701
1702 kMenu_Max
1703 };
1704
1705 const char * menu_item[kMenu_Max + 1];
1706 INT32 sel;
1707 UINT8 total;
1708 static INT32 submenu_choice = 0;
1709 static int firstEntry = 0;
1710
1711 cheatEngineWasActive = 1;
1712
1713 total = 0;
1714 sel = selection - 1;
1715
1716 if(submenu_choice)
1717 {
1718 switch(sel)
1719 {
1720 case kMenu_EnableDisable:
1721 submenu_choice = EnableDisableCheatMenu(bitmap, submenu_choice, firstEntry);
1722 break;
1723
1724 case kMenu_AddEdit:
1725 submenu_choice = AddEditCheatMenu(bitmap, submenu_choice);
1726 break;
1727
1728 case kMenu_StartSearch:
1729 if(useClassicSearchBox)
1730 submenu_choice = DoSearchMenuClassic(bitmap, submenu_choice, 1);
1731 else
1732 submenu_choice = DoSearchMenu(bitmap, submenu_choice, 1);
1733 break;
1734
1735 case kMenu_ContinueSearch:
1736 if(useClassicSearchBox)
1737 submenu_choice = DoSearchMenuClassic(bitmap, submenu_choice, 0);
1738 else
1739 submenu_choice = DoSearchMenu(bitmap, submenu_choice, 0);
1740 break;
1741
1742 case kMenu_ViewResults:
1743 submenu_choice = ViewSearchResults(bitmap, submenu_choice, firstEntry);
1744 break;
1745
1746 case kMenu_ChooseWatch:
1747 submenu_choice = ChooseWatch(bitmap, submenu_choice);
1748 break;
1749
1750 case kMenu_DisplayHelp:
1751 submenu_choice = DisplayHelp(bitmap, submenu_choice);
1752 break;
1753
1754 case kMenu_Options:
1755 submenu_choice = SelectOptions(bitmap, submenu_choice);
1756 break;
1757
1758 case kMenu_Return:
1759 submenu_choice = 0;
1760 sel = -1;
1761 break;
1762 }
1763
1764 firstEntry = 0;
1765
1766 if(submenu_choice == -1)
1767 submenu_choice = 0;
1768
1769 return sel + 1;
1770 }
1771
1772 menu_item[total++] = ui_getstring(UI_enablecheat);
1773 menu_item[total++] = ui_getstring(UI_addeditcheat);
1774 menu_item[total++] = ui_getstring(UI_startcheat);
1775 menu_item[total++] = ui_getstring(UI_continuesearch);
1776 menu_item[total++] = ui_getstring(UI_viewresults);
1777 menu_item[total++] = ui_getstring(UI_restoreresults);
1778 menu_item[total++] = ui_getstring(UI_memorywatch);
1779 menu_item[total++] = ui_getstring(UI_generalhelp);
1780 menu_item[total++] = ui_getstring(UI_options);
1781 menu_item[total++] = ui_getstring(UI_returntomain);
1782 menu_item[total] = 0;
1783
1784 ui_displaymenu(bitmap, menu_item, 0, 0, sel, 0);
1785
1786 if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
1787 {
1788 if(sel < (total - 1))
1789 sel++;
1790 else
1791 sel = 0;
1792 }
1793
1794 if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
1795 {
1796 if(sel > 0)
1797 sel--;
1798 else
1799 sel = total - 1;
1800 }
1801
1802 if(input_ui_pressed(IPT_UI_SELECT))
1803 {
1804 switch(sel)
1805 {
1806 case kMenu_Return:
1807 submenu_choice = 0;
1808 sel = -1;
1809 break;
1810
1811 case kMenu_RestoreSearch:
1812 {
1813 SearchInfo * search = GetCurrentSearch();
1814
1815 if(search && search->backupValid)
1816 {
1817 RestoreSearchBackup(search);
1818
1819 usrintf_showmessage_secs(1, "values restored");
1820 }
1821 else
1822 {
1823 usrintf_showmessage_secs(1, "there are no old values");
1824 }
1825 }
1826 break;
1827
1828 default:
1829 firstEntry = 1;
1830 submenu_choice = 1;
1831 schedule_full_refresh();
1832 break;
1833 }
1834 }
1835
1836 if(input_ui_pressed(IPT_UI_CANCEL))
1837 sel = -1;
1838 if(input_ui_pressed(IPT_UI_CONFIGURE))
1839 sel = -2;
1840
1841 if((sel == -1) || (sel == -2))
1842 {
1843 schedule_full_refresh();
1844 }
1845
1846 return sel + 1;
1847 }
1848
1849 static UINT32 BCDToDecimal(UINT32 value)
1850 {
1851 UINT32 accumulator = 0;
1852 UINT32 multiplier = 1;
1853 int i;
1854
1855 for(i = 0; i < 8; i++)
1856 {
1857 accumulator += (value & 0xF) * multiplier;
1858
1859 multiplier *= 10;
1860 value >>= 4;
1861 }
1862
1863 return accumulator;
1864 }
1865
1866 static UINT32 DecimalToBCD(UINT32 value)
1867 {
1868 UINT32 accumulator = 0;
1869 UINT32 divisor = 10;
1870 int i;
1871
1872 for(i = 0; i < 8; i++)
1873 {
1874 UINT32 temp;
1875
1876 temp = value % divisor;
1877 value -= temp;
1878 temp /= divisor / 10;
1879
1880 accumulator += temp << (i * 4);
1881
1882 divisor *= 10;
1883 }
1884
1885 return accumulator;
1886 }
1887
1888 static void RebuildStringTables(void)
1889 {
1890 UINT32 storageNeeded, i;
1891 char * traverse;
1892
1893 storageNeeded = (menuStrings.mainStringLength + menuStrings.subStringLength) * menuStrings.numStrings;
1894
1895 menuStrings.mainList = (const char **) realloc((char *) menuStrings.mainList, sizeof(char *) * menuStrings.length);
1896 menuStrings.subList = (const char **) realloc((char *) menuStrings.subList, sizeof(char *) * menuStrings.length);
1897 menuStrings.flagList = realloc( menuStrings.flagList, sizeof(char) * menuStrings.length);
1898 menuStrings.mainStrings = realloc( menuStrings.mainStrings, sizeof(char *) * menuStrings.numStrings);
1899 menuStrings.subStrings = realloc( menuStrings.subStrings, sizeof(char *) * menuStrings.numStrings);
1900 menuStrings.buf = realloc( menuStrings.buf, sizeof(char) * storageNeeded);
1901
1902 if( (!menuStrings.mainList && menuStrings.length) ||
1903 (!menuStrings.subList && menuStrings.length) ||
1904 (!menuStrings.flagList && menuStrings.length) ||
1905 (!menuStrings.mainStrings && menuStrings.numStrings) ||
1906 (!menuStrings.subStrings && menuStrings.numStrings) ||
1907 (!menuStrings.buf && storageNeeded))
1908 {
1909 // memory allocation error
1910
1911 logerror( "cheat: memory allocation error\n"
1912 " length = %.8X\n"
1913 " numStrings = %.8X\n"
1914 " mainStringLength = %.8X\n"
1915 " subStringLength = %.8X\n"
1916 "%.8X %.8X %.8X %.8X %.8X %.8X\n",
1917 menuStrings.length,
1918 menuStrings.numStrings,
1919 menuStrings.mainStringLength,
1920 menuStrings.subStringLength,
1921
1922 menuStrings.mainList,
1923 menuStrings.subList,
1924 menuStrings.flagList,
1925 menuStrings.mainStrings,
1926 menuStrings.subStrings,
1927 menuStrings.buf);
1928
1929 exit(1);
1930 }
1931
1932 traverse = menuStrings.buf;
1933
1934 for(i = 0; i < menuStrings.numStrings; i++)
1935 {
1936 menuStrings.mainStrings[i] = traverse;
1937 traverse += menuStrings.mainStringLength;
1938
1939 menuStrings.subStrings[i] = traverse;
1940 traverse += menuStrings.subStringLength;
1941 }
1942 }
1943
1944 static void RequestStrings(UINT32 length, UINT32 numStrings, UINT32 mainStringLength, UINT32 subStringLength)
1945 {
1946 UINT8 changed = 0;
1947
1948 if(menuStrings.length < length)
1949 {
1950 menuStrings.length = length;
1951
1952 changed = 1;
1953 }
1954
1955 if(menuStrings.numStrings < numStrings)
1956 {
1957 menuStrings.numStrings = numStrings;
1958
1959 changed = 1;
1960 }
1961
1962 if(menuStrings.mainStringLength < mainStringLength)
1963 {
1964 menuStrings.mainStringLength = mainStringLength;
1965
1966 changed = 1;
1967 }
1968
1969 if(menuStrings.subStringLength < subStringLength)
1970 {
1971 menuStrings.subStringLength = subStringLength;
1972
1973 changed = 1;
1974 }
1975
1976 if(changed)
1977 {
1978 RebuildStringTables();
1979 }
1980 }
1981
1982 static void InitStringTable(void)
1983 {
1984 memset(&menuStrings, 0, sizeof(MenuStringList));
1985 }
1986
1987 static void FreeStringTable(void)
1988 {
1989 free((char *)menuStrings.mainList);
1990 free((char *)menuStrings.subList);
1991 free(menuStrings.flagList);
1992 free(menuStrings.mainStrings);
1993 free(menuStrings.subStrings);
1994 free(menuStrings.buf);
1995
1996 memset(&menuStrings, 0, sizeof(MenuStringList));
1997 }
1998
1999 static INT32 UserSelectValueMenu(struct mame_bitmap * bitmap, int selection, CheatEntry * entry)
2000 {
2001 char buf[2048];
2002 int sel;
2003 CheatAction * action;
2004 static INT32 value = -1;
2005 static int firstTime = 1;
2006 int delta = 0;
2007 int displayValue;
2008 int keyValue;
2009 int forceUpdate = 0;
2010
2011 sel = selection - 1;
2012
2013 action = &entry->actionList[0];
2014
2015 // if we're just entering, save the value
2016 if(firstTime)
2017 {
2018 value = action->data;
2019
2020 // and check for valid BCD values
2021 if(TEST_FIELD(action->type, UserSelectBCD))
2022 {
2023 UINT32 min = EXTRACT_FIELD(action->type, UserSelectMinimum);
2024 UINT32 max = action->originalDataField + min;
2025
2026 value = BCDToDecimal(value);
2027 value = DecimalToBCD(value);
2028
2029 if(value < min)
2030 value = max;
2031 if(value > max)
2032 value = min;
2033 }
2034
2035 firstTime = 0;
2036 }
2037
2038 displayValue = value;
2039
2040 // if the minimum display value is one, add one to the display value
2041 if(TEST_FIELD(action->type, UserSelectMinimumDisplay))
2042 {
2043 // bcd -> dec
2044 if(TEST_FIELD(action->type, UserSelectBCD))
2045 {
2046 displayValue = BCDToDecimal(displayValue);
2047 }
2048
2049 displayValue++;
2050
2051 // dec -> bcd
2052 if(TEST_FIELD(action->type, UserSelectBCD))
2053 {
2054 displayValue = DecimalToBCD(displayValue);
2055 }
2056 }
2057
2058 // print it
2059 if(TEST_FIELD(action->type, UserSelectBCD))
2060 {
2061 sprintf(buf, "\t%s\n\t%.2X\n", ui_getstring(UI_search_select_value), displayValue);
2062 }
2063 else
2064 {
2065 sprintf(buf, "\t%s\n\t%.2X (%d)\n", ui_getstring(UI_search_select_value), displayValue, displayValue);
2066 }
2067
2068 // create fake menu strings
2069 strcat(buf, "\t");
2070 strcat(buf, ui_getstring(UI_lefthilight));
2071 strcat(buf, " ");
2072 strcat(buf, ui_getstring(UI_OK));
2073 strcat(buf, " ");
2074 strcat(buf, ui_getstring(UI_righthilight));
2075
2076 // print fake menu
2077 ui_displaymessagewindow(bitmap, buf);
2078
2079 // get user input
2080 if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalFastKeyRepeatRate))
2081 {
2082 delta = -1;
2083 }
2084 if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalFastKeyRepeatRate))
2085 {
2086 delta = 1;
2087 }
2088
2089 // done?
2090 if(input_ui_pressed(IPT_UI_SELECT))
2091 {
2092 // ### redundant?? probably can be removed
2093 if(!firstTime)
2094 {
2095 int i;
2096
2097 // copy data field to all user select cheats
2098 for(i = 0; i < entry->actionListLength; i++)
2099 {
2100 CheatAction * traverse = &entry->actionList[0];
2101
2102 if(TEST_FIELD(traverse->type, UserSelectEnable))
2103 {
2104 traverse->data = value;
2105 }
2106 }
2107
2108 // and activate the cheat
2109 ActivateCheat(entry);
2110 }
2111
2112 // reset and return
2113 firstTime = 1;
2114 sel = -1;
2115 }
2116
2117 if(input_ui_pressed(IPT_UI_CANCEL))
2118 {
2119 firstTime = 1;
2120 sel = -1;
2121 }
2122
2123 if(input_ui_pressed(IPT_UI_CONFIGURE))
2124 {
2125 firstTime = 1;
2126 sel = -2;
2127 }
2128
2129 // get a key
2130 keyValue = ReadHexInput();
2131
2132 // if we got a key
2133 if(keyValue != -1)
2134 {
2135 // add it
2136 if(TEST_FIELD(action->type, UserSelectBCD))
2137 {
2138 if(value < 10)
2139 {
2140 value *= 10;
2141 value &= 0xFF;
2142 value += keyValue;
2143 }
2144 }
2145 else
2146 {
2147 value <<= 4;
2148 value &= 0xF0;
2149 value |= keyValue & 0x0F;
2150 }
2151
2152 delta = 0;
2153 forceUpdate = 1;
2154 }
2155
2156 // wrap-around with BCD stuff
2157 // ### this is a really bad way to do this
2158 if(delta || forceUpdate)
2159 {
2160 INT32 min = EXTRACT_FIELD(action->type, UserSelectMinimum);
2161 INT32 max = action->originalDataField + min;
2162
2163 if(TEST_FIELD(action->type, UserSelectBCD))
2164 {
2165 value = BCDToDecimal(value);
2166 }
2167
2168 value += delta;
2169
2170 if(TEST_FIELD(action->type, UserSelectBCD))
2171 {
2172 value = DecimalToBCD(value);
2173 }
2174
2175 if(value < min)
2176 value = max;
2177 if(value > max)
2178 value = min;
2179 }
2180
2181 if (sel == -1 || sel == -2)
2182 {
2183 schedule_full_refresh();
2184 }
2185
2186 return sel + 1;
2187 }
2188
2189 static INT32 CommentMenu(struct mame_bitmap * bitmap, int selection, CheatEntry * entry)
2190 {
2191 char buf[2048];
2192 int sel;
2193 char * comment;
2194
2195 if(!entry)
2196 return 0;
2197
2198 sel = selection - 1;
2199
2200 // create fake menu strings
2201 if(entry->comment && entry->comment[0])
2202 comment = entry->comment;
2203 else
2204 comment = "(none)";
2205
2206 sprintf(buf, "%s\n\t%s %s %s", comment, ui_getstring(UI_lefthilight), ui_getstring(UI_OK), ui_getstring(UI_righthilight));
2207
2208 // print fake menu
2209 ui_displaymessagewindow(bitmap, buf);
2210
2211 // done?
2212 if(input_ui_pressed(IPT_UI_SELECT))
2213 {
2214 sel = -1;
2215 }
2216
2217 if(input_ui_pressed(IPT_UI_CANCEL))
2218 {
2219 sel = -1;
2220 }
2221
2222 if(input_ui_pressed(IPT_UI_CONFIGURE))
2223 {
2224 sel = -2;
2225 }
2226
2227 if (sel == -1 || sel == -2)
2228 {
2229 schedule_full_refresh();
2230 }
2231
2232 return sel + 1;
2233 }
2234
2235 static int EnableDisableCheatMenu(struct mame_bitmap * bitmap, int selection, int firstTime)
2236 {
2237 INT32 sel;
2238 static INT32 submenu_choice = 0;
2239 static INT32 submenu_id = 0;
2240 const char ** menu_item;
2241 const char ** menu_subitem;
2242 char * flagBuf;
2243 INT32 i;
2244 INT32 total = 0;
2245 CheatEntry * entry;
2246
2247 RequestStrings(cheatListLength + 5, 0, 0, 0);
2248
2249 menu_item = menuStrings.mainList;
2250 menu_subitem = menuStrings.subList;
2251 flagBuf = menuStrings.flagList;
2252
2253 sel = selection - 1;
2254
2255 /* If a submenu has been selected, go there */
2256 if(submenu_choice)
2257 {
2258 switch(submenu_id)
2259 {
2260 case 1:
2261 submenu_choice = CommentMenu(bitmap, submenu_choice, &cheatList[sel]);
2262 break;
2263
2264 case 2:
2265 submenu_choice = UserSelectValueMenu(bitmap, submenu_choice, &cheatList[sel]);
2266 break;
2267
2268 case 3:
2269 submenu_choice = EditCheatMenu(bitmap, &cheatList[sel], submenu_choice);
2270 break;
2271
2272 default:
2273 submenu_choice = 0;
2274 }
2275
2276 if(submenu_choice == -1)
2277 {
2278 submenu_choice = 0;
2279 sel = -2;
2280 }
2281
2282 return sel + 1;
2283 }
2284
2285 /* No submenu active, do the watchpoint menu */
2286 for(i = 0; i < cheatListLength; i++)
2287 {
2288 CheatEntry * traverse = &cheatList[i];
2289
2290 if(traverse->name)
2291 {
2292 menu_item[total] = traverse->name;
2293 }
2294 else
2295 {
2296 menu_item[total] = "null name";
2297 }
2298
2299 menu_subitem[total] = NULL;
2300
2301 if(traverse->flags & kCheatFlag_Select)
2302 {
2303 if((traverse->flags & kCheatFlag_OneShot) && !traverse->selection)
2304 {
2305 traverse->selection = 1;
2306 }
2307
2308 if(traverse->selection && (traverse->selection < traverse->actionListLength))
2309 {
2310 menu_subitem[total] = traverse->actionList[traverse->selection].optionalName;
2311 }
2312 else
2313 {
2314 menu_subitem[total] = ui_getstring(UI_off);
2315 }
2316 }
2317 else
2318 {
2319 // add submenu options for all cheats that are not comments
2320 if(!(traverse->flags & kCheatFlag_Null))
2321 {
2322 if(traverse->flags & kCheatFlag_OneShot)
2323 {
2324 menu_subitem[total] = ui_getstring(UI_set);
2325 }
2326 else
2327 {
2328 if(traverse->flags & kCheatFlag_Active)
2329 {
2330 menu_subitem[total] = ui_getstring(UI_on);
2331 }
2332 else
2333 {
2334 menu_subitem[total] = ui_getstring(UI_off);
2335 }
2336 }
2337 }
2338 }
2339
2340 if(traverse->comment && traverse->comment[0])
2341 flagBuf[total] = 1;
2342 else
2343 flagBuf[total] = 0;
2344
2345 total++;
2346 }
2347
2348 if(cheatListLength == 0)
2349 {
2350 if(foundCheatDatabase)
2351 {
2352 menu_item[total] = "there are no cheats for this game";
2353 menu_subitem[total] = NULL;
2354 flagBuf[total] = 0;
2355 total++;
2356 }
2357 else
2358 {
2359 menu_item[total] = "cheat database not found";
2360 menu_subitem[total] = NULL;
2361 flagBuf[total] = 0;
2362 total++;
2363
2364 menu_item[total] = "unzip it and place it in the MAME directory";
2365 menu_subitem[total] = NULL;
2366 flagBuf[total] = 0;
2367 total++;
2368 }
2369 }
2370
2371 menu_item[total] = ui_getstring(UI_returntoprior);
2372 menu_subitem[total] = NULL;
2373 flagBuf[total] = 0;
2374 total++;
2375
2376 menu_item[total] = 0; /* terminate array */
2377 menu_subitem[total] = 0;
2378 flagBuf[total] = 0;
2379
2380 if(sel < 0)
2381 sel = 0;
2382 if(sel > (total - 1))
2383 sel = total - 1;
2384
2385 if(cheatListLength && firstTime)
2386 {
2387 while( (sel < total - 1) &&
2388 (cheatList[sel].flags & kCheatFlag_Null))
2389 sel++;
2390 }
2391
2392 ui_displaymenu(bitmap, menu_item, menu_subitem, flagBuf, sel, 0);
2393
2394 if(UIPressedRepeatThrottle(IPT_UI_DOWN, kVerticalKeyRepeatRate))
2395 {
2396 sel++;
2397
2398 if(sel >= total)
2399 sel = 0;
2400
2401 if(cheatListLength)
2402 {
2403 for(i = 0; (i < fullMenuPageHeight / 2) &&
2404 (sel < total - 1) &&
2405 (cheatList[sel].flags & kCheatFlag_Null); i++)
2406 sel++;
2407 }
2408 }
2409
2410 if(UIPressedRepeatThrottle(IPT_UI_UP, kVerticalKeyRepeatRate))
2411 {
2412 sel--;
2413
2414 if(sel < 0)
2415 {
2416 sel = total - 1;
2417 }
2418 else
2419 {
2420 if(cheatListLength)
2421 {
2422 for(i = 0; (i < fullMenuPageHeight / 2) &&
2423 (sel != total - 1) &&
2424 (cheatList[sel].flags & kCheatFlag_Null); i++)
2425 {
2426 sel--;
2427
2428 if(sel < 0)
2429 sel = total - 1;
2430 }
2431 }
2432 }
2433 }
2434
2435 if(UIPressedRepeatThrottle(IPT_UI_PAN_UP, kVerticalKeyRepeatRate))
2436 {
2437 sel -= fullMenuPageHeight;
2438
2439 if(sel < 0)
2440 {
2441 sel = 0;
2442 }
2443 }
2444
2445 if(UIPressedRepeatThrottle(IPT_UI_PAN_DOWN, kVerticalKeyRepeatRate))
2446 {
2447 sel += fullMenuPageHeight;
2448
2449 if(sel >= total)
2450 {
2451 sel = total - 1;
2452 }
2453 }
2454
2455 if( (sel >= 0) &&
2456 (sel < cheatListLength))
2457 entry = &cheatList[sel];
2458 else
2459 entry = NULL;
2460
2461 if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate))
2462 {
2463 if((sel < (total - 1)) && entry)
2464 {
2465 if(entry->flags & kCheatFlag_Select)
2466 {
2467 entry->selection--;
2468
2469 if(entry->flags & kCheatFlag_OneShot)
2470 {
2471 if(entry->selection <= 0)
2472 entry->selection = entry->actionListLength - 1;
2473 }
2474 else
2475 {
2476 if(entry->selection < 0)
2477 entry->selection = entry->actionListLength - 1;
2478
2479 if(entry->selection == 0)
2480 {
2481 DeactivateCheat(entry);
2482 }
2483 else
2484 {
2485 ActivateCheat(entry);
2486 }
2487 }
2488 }
2489 else
2490 {
2491 if( !(entry->flags & kCheatFlag_Null) &&
2492 !(entry->flags & kCheatFlag_OneShot))
2493 {
2494 int active = entry->flags & kCheatFlag_Active;
2495
2496 active ^= 0x01;
2497
2498 /* get the user's selected value if needed */
2499 if((entry->flags & kCheatFlag_UserSelect) && active)
2500 {
2501 submenu_id = 2;
2502 submenu_choice = 1;
2503 schedule_full_refresh();
2504 }
2505 else
2506 {
2507 if(active)
2508 ActivateCheat(entry);
2509 else
2510 DeactivateCheat(entry);
2511 }
2512 }
2513 }
2514 }
2515 }
2516
2517 if(UIPressedRepeatThrottle(IPT_UI_RIGHT, kHorizontalSlowKeyRepeatRate))
2518 {
2519 if((sel < (total - 1)) && entry)
2520 {
2521 if(entry->flags & kCheatFlag_Select)
2522 {
2523 entry->selection++;
2524
2525 if(entry->flags & kCheatFlag_OneShot)
2526 {
2527 if(entry->selection >= entry->actionListLength)
2528 {
2529 entry->selection = 1;
2530
2531 if(entry->selection >= entry->actionListLength)
2532 entry->selection = 0;
2533 }
2534 }
2535 else
2536 {
2537 if(entry->selection >= entry->actionListLength)
2538 {
2539 entry->selection = 0;
2540
2541 DeactivateCheat(entry);
2542 }
2543 else
2544 {
2545 ActivateCheat(entry);
2546 }
2547 }
2548 }
2549 else
2550 {
2551 if( !(entry->flags & kCheatFlag_Null) &&
2552 !(entry->flags & kCheatFlag_OneShot))
2553 {
2554 int active = entry->flags & kCheatFlag_Active;
2555
2556 active ^= 0x01;
2557
2558 /* get the user's selected value if needed */
2559 if((entry->flags & kCheatFlag_UserSelect) && active)
2560 {
2561 submenu_id = 2;
2562 submenu_choice = 1;
2563 schedule_full_refresh();
2564 }
2565 else
2566 {
2567 if(active)
2568 ActivateCheat(entry);
2569 else
2570 DeactivateCheat(entry);
2571 }
2572 }
2573 }
2574 }
2575 }
2576
2577 if(input_ui_pressed(IPT_UI_SELECT))
2578 {
2579 if(sel == (total - 1))
2580 {
2581 /* return to prior menu */
2582 submenu_choice = 0;
2583 sel = -1;
2584 }
2585 else if((sel < (total - 1)) && entry)
2586 {
2587 if(ShiftKeyPressed())
2588 {
2589 if(cheatList[sel].comment && cheatList[sel].comment[0])
2590 {
2591 submenu_id = 1;
2592 submenu_choice = 1;
2593 schedule_full_refresh();
2594 }
2595 else
2596 {
2597 ActivateCheat(&cheatList[sel]);
2598
2599 if(cheatList[sel].flags & kCheatFlag_OneShot)
2600 usrintf_showmessage_secs(1, "%s activated", cheatList[sel].name);
2601 }
2602 }
2603 else
2604 {
2605 if(entry->flags & kCheatFlag_UserSelect)
2606 {
2607 submenu_id = 2;
2608 submenu_choice = 1;
2609 schedule_full_refresh();
2610 }
2611 else
2612 {
2613 ActivateCheat(&cheatList[sel]);
2614
2615 if(cheatList[sel].flags & kCheatFlag_OneShot)
2616 usrintf_showmessage_secs(1, "%s activated", cheatList[sel].name);
2617 }
2618 }
2619 }
2620 }
2621
2622 if(input_ui_pressed(IPT_UI_WATCH_VALUE))
2623 {
2624 WatchCheatEntry(entry, 0);
2625 }
2626
2627 if(ShiftKeyPressed())
2628 {
2629 if(input_ui_pressed(IPT_UI_SAVE_CHEAT))
2630 {
2631 for(i = 0; i < cheatListLength; i++)
2632 SaveCheat(&cheatList[i]);
2633
2634 usrintf_showmessage_secs(1, "%d cheats saved", cheatListLength);
2635 }
2636
2637 if(input_ui_pressed(IPT_UI_ADD_CHEAT))
2638 {
2639 AddCheatBefore(sel);
2640 }
2641
2642 if(input_ui_pressed(IPT_UI_DELETE_CHEAT))
2643 {
2644 DeleteCheatAt(sel);
2645 }
2646
2647 if(input_ui_pressed(IPT_UI_EDIT_CHEAT))
2648 {
2649 if(entry)
2650 {
2651 submenu_id = 3;
2652 submenu_choice = 1;
2653 schedule_full_refresh();
2654 }
2655 }
2656 }
2657 else
2658 {
2659 if(input_ui_pressed(IPT_UI_SAVE_CHEAT))
2660 {
2661 SaveCheat(entry);
2662 }
2663 }
2664
2665 /* Cancel pops us up a menu level */
2666 if(input_ui_pressed(IPT_UI_CANCEL))
2667 sel = -1;
2668
2669 /* The UI key takes us all the way back out */
2670 if(input_ui_pressed(IPT_UI_CONFIGURE))
2671 sel = -2;
2672
2673 if(sel == -1 || sel == -2)
2674 {
2675 schedule_full_refresh();
2676 }
2677
2678 return sel + 1;
2679 }
2680
2681 static int EditCheatMenu(struct mame_bitmap * bitmap, CheatEntry * entry, int selection)
2682 {
2683 const char * kTypeNames[] =
2684 {
2685 "Normal/Delay",
2686 "Wait",
2687 "Ignore Decrement",
2688 "Watch",
2689 "Comment",
2690 "Select"
2691 };
2692
2693 const char * kNumbersTable[] =
2694 {
2695 "0", "1", "2", "3", "4", "5", "6", "7",
2696 "8", "9", "10", "11", "12", "13", "14", "15",
2697 "16", "17", "18", "19", "20", "21", "22", "23",
2698 "24", "25", "26", "27", "28", "29", "30", "31"
2699 };
2700
2701 const char * kOperationNames[] =
2702 {
2703 "Write",
2704 "Add/Subtract",
2705 "Force Range",
2706 "Set/Clear Bits",
2707 "Unused (4)",
2708 "Unused (5)",
2709 "Unused (6)",
2710 "Null"
2711 };
2712
2713 const char * kAddSubtractNames[] =
2714 {
2715 "Add",
2716 "Subtract"
2717 };
2718
2719 const char * kSetClearNames[] =
2720 {
2721 "Set",
2722 "Clear"
2723 };
2724
2725 const char * kPrefillNames[] =
2726 {
2727 "None",
2728 "FF",
2729 "00",
2730 "01"
2731 };
2732
2733 const char * kEndiannessNames[] =
2734 {
2735 "Normal",
2736 "Swap"
2737 };
2738
2739 const char * kRegionNames[] =
2740 {
2741 "CPU1", "CPU2", "CPU3", "CPU4", "CPU5", "CPU6", "CPU7", "CPU8",
2742 "GFX1", "GFX2", "GFX3", "GFX4", "GFX5", "GFX6", "GFX7", "GFX8",
2743 "PROMS",
2744 "SOUND1", "SOUND2", "SOUND3", "SOUND4", "SOUND5", "SOUND6", "SOUND7", "SOUND8",
2745 "USER1", "USER2", "USER3", "USER4", "USER5", "USER6", "USER7", "USER8"
2746 };
2747
2748 const char * kLocationNames[] =
2749 {
2750 "Normal",
2751 "Region",
2752 "Mapped Memory",
2753 "Custom",
2754 "Relative Address",
2755 "Unused (5)",
2756 "Unused (6)",
2757 "Unused (7)"
2758 };
2759
2760 const char * kCustomLocationNames[] =
2761 {
2762 "Comment",
2763 "EEPROM",
2764 "Select",
2765 "Unused (3)", "Unused (4)", "Unused (5)", "Unused (6)", "Unused (7)",
2766 "Unused (8)", "Unused (9)", "Unused (10)", "Unused (11)", "Unused (12)",
2767 "Unused (13)", "Unused (14)", "Unused (15)", "Unused (16)", "Unused (17)",
2768 "Unused (18)", "Unused (19)", "Unused (20)", "Unused (21)", "Unused (22)",
2769 "Unused (23)", "Unused (24)", "Unused (25)", "Unused (26)", "Unused (27)",
2770 "Unused (28)", "Unused (29)", "Unused (30)", "Unused (31)"
2771 };
2772
2773 const char * kKeycodeNames[] =
2774 {
2775 "A", "B", "C", "D", "E", "F",
2776 "G", "H", "I", "J", "K", "L",
2777 "M", "N", "O", "P", "Q", "R",
2778 "S", "T", "U", "V", "W", "X",
2779 "Y", "Z", "0", "1", "2", "3",
2780 "4", "5", "6", "7", "8", "9",
2781 "[0]", "[1]", "[2]", "[3]", "[4]",
2782 "[5]", "[6]", "[7]", "[8]", "[9]",
2783 "F1", "F2", "F3", "F4", "F5",
2784 "F6", "F7", "F8", "F9", "F10",
2785 "F11", "F12",
2786 "ESC", "~", "-", "=", "BACKSPACE",
2787 "TAB", "[", "]", "ENTER", ":",
2788 "\'", "\\", "\\", ",", ".",
2789 "/", "SPACE", "INS", "DEL",
2790 "HOME", "END", "PGUP", "PGDN", "LEFT",
2791 "RIGHT", "UP", "DOWN",
2792 "[/]", "[*]", "[-]", "[+]",
2793 "[DEL]", "[ENT]", "PTSCR", "PAUSE",
2794 "LSHIFT", "RSHIFT", "LCONTROL", "RCONTROL",
2795 "LALT", "RALT", "SCRLLK", "NUMLK", "CAPSLK",
2796 "LWIN", "RWIN", "MENU"
2797 };
2798
2799 const char * kSizeNames[] =
2800 {
2801 "8 Bit",
2802 "16 Bit",
2803 "24 Bit",
2804 "32 Bit"
2805 };
2806
2807 enum
2808 {
2809 kType_Name = 0, // text name
2810 // NOTE: read from base cheat (for idx == 0)
2811 kType_ExtendName, // text extraName
2812 // NOTE: read from subcheat for (idx > 0) && (cheat[0].type == Select)
2813 kType_Comment, // text comment
2814 // NOTE: read from base cheat (for idx == 0)
2815 kType_ActivationKey, // key activationKey
2816 // NOTE: read from base cheat (for idx == 0)
2817 kType_Type, // select Type Normal/Delay - Wait - Ignore Decrement - Watch -
2818 // Comment - Select
2819 // NOTE: also uses location type field for comment and select
2820 // if((Type != Comment) && (Type != Select))
2821 // if(Type != Watch)
2822 kType_OneShot, // select OneShot Off - On
2823 kType_RestorePreviousValue,
2824 // select RestorePreviousValue
2825 // Off - On
2826 // if((Type == Normal/Delay) || (Type == Wait))
2827 kType_Delay, // value TypeParameter 0 - 7
2828 // if(Type == Ignore Decrement)
2829 kType_IgnoreDecrementBy,// value TypeParameter 0 - 7
2830 // if(Type == Watch)
2831 kType_WatchSize, // value Data 0x01 - 0xFF (stored as 0x00 - 0xFE)
2832 // NOTE: value is packed in to lower byte of data
2833 kType_WatchSkip, // value Data 0x00 - 0xFF
2834 // NOTE: value is packed in to 0x0000FF00
2835 kType_WatchPerLine, // value Data 0x00 - 0xFF
2836 // NOTE: value is packed in to 0x00FF0000
2837 // and set operation to null
2838 // else
2839 kType_Operation, // select Operation Write - Add/Subtract - Force Range - Set/Clear Bits -
2840 // Null
2841 // if((Operation == Write) && (LocationType != Relative Address))
2842 kType_WriteMask, // value extendData 0x00000000 - 0xFFFFFFFF
2843 // if(Operation == Add/Subtract)
2844 kType_AddSubtract, // select OperationParameter Add - Subtract
2845 // if(LocationType != Relative Address)
2846 // if(OperationParameter == Add)
2847 kType_AddMaximum,
2848 // value extendData 0x00000000 - 0xFFFFFFFF
2849 // else
2850 kType_SubtractMinimum,
2851 // value extendData 0x00000000 - 0xFFFFFFFF
2852 // if((Operation == Force Range) && (LocationType != Relative Address))
2853 kType_RangeMinimum, // value extendData 0x00 - 0xFF
2854 // NOTE: value is packed in to upper byte of extendData
2855 kType_RangeMaximum, // value extendData 0x00 - 0xFF
2856 // NOTE: value is packed in to lower byte of extendData
2857 // if(Operation == Set/Clear)
2858 kType_SetClear, // select OperationParameter Set - Clear
2859 // if((Operation != Null) || (Type == Watch))
2860 // if(Type != Watch)
2861 kType_Data,
2862 kType_UserSelect, // select UserSelectEnable Off - On
2863 // if(UserSelect == On)
2864 kType_UserSelectMinimumDisp,
2865 // value UserSelectMinimumDisplay
2866 // 0 - 1
2867 kType_UserSelectMinimum,
2868 // value UserSelectMinimum 0 - 1
2869 kType_UserSelectBCD,// select UserSelectBCD Off - On
2870 kType_Prefill, // select UserSelectPrefill None - FF - 00 - 01
2871 // if(idx > 0)
2872 kType_CopyPrevious, // select LinkCopyPreviousValue
2873 // Off - On
2874 kType_ByteLength, // value BytesUsed 1 - 4
2875 // if(bytesUsed > 0)
2876 kType_Endianness, // select Endianness Normal - Swap
2877 kType_LocationType, // select LocationType Normal - Region - Mapped Memory - EEPROM -
2878 // Relative Address
2879 // NOTE: also uses LocationParameter for EEPROM type
2880 // if(LocationType == Normal)
2881 kType_CPU, // value LocationParameter 0 - 31
2882 // if(LocationType == Region)
2883 kType_Region, // select LocationParameter CPU1 - CPU2 - CPU3 - CPU4 - CPU5 - CPU6 - CPU7 -
2884 // CPU8 - GFX1 - GFX2 - GFX3 - GFX4 - GFX5 - GFX6 -
2885 // GFX7 - GFX8 - PROMS - SOUND1 - SOUND2 - SOUND3 -
2886 // SOUND4 - SOUND5 - SOUND6 - SOUND7 - SOUND8 -
2887 // USER1 - USER2 - USER3 - USER4 - USER5 - USER6 -
2888 // USER7
2889 // if(LocationType == RelativeAddress)
2890 kType_PackedCPU, // value LocationParameter 0 - 7
2891 // NOTE: packed in to upper three bits of LocationParameter
2892 kType_PackedSize, // value LocationParameter 1 - 4
2893 // NOTE: packed in to lower two bits of LocationParameter
2894 kType_AddressIndex, // value extendData -0x80000000 - 0x7FFFFFFF
2895 kType_Address,
2896
2897 kType_Return,
2898 kType_Divider,
2899
2900 kType_Max
2901 };
2902
2903 INT32 sel;
2904 const char ** menuItem;
2905 const char ** menuSubItem;
2906 char * flagBuf;
2907 char ** extendDataBuf; // FFFFFFFF (-80000000)
2908 char ** addressBuf; // FFFFFFFF
2909 char ** dataBuf; // 80000000 (-2147483648)
2910 char ** watchSizeBuf; // FF
2911 char ** watchSkipBuf; // FF
2912 char ** watchPerLineBuf; // FF
2913 INT32 i;
2914 INT32 total = 0;
2915 MenuItemInfoStruct * info = NULL;
2916 CheatAction * action = NULL;
2917 UINT8 isSelect = 0;
2918 static UINT8 editActive = 0;
2919 UINT32 increment = 1;
2920 UINT8 dirty = 0;
2921 static INT32 currentNameTemplate = 0;
2922
2923 if(!entry)
2924 return 0;
2925
2926 if(menuItemInfoLength < (kType_Max * entry->actionListLength) + 2)
2927 {
2928 menuItemInfoLength = (kType_Max * entry->actionListLength) + 2;
2929
2930 menuItemInfo = realloc(menuItemInfo, menuItemInfoLength * sizeof(MenuItemInfoStruct));
2931 }
2932
2933 RequestStrings((kType_Max * entry->actionListLength) + 2, 6 * entry->actionListLength, 24, 0);
2934
2935 menuItem = menuStrings.mainList;
2936 menuSubItem = menuStrings.subList;
2937 flagBuf = menuStrings.flagList;
2938 extendDataBuf = &menuStrings.mainStrings[entry->actionListLength * 0];
2939 addressBuf = &menuStrings.mainStrings[entry->actionListLength * 1];
2940 dataBuf = &menuStrings.mainStrings[entry->actionListLength * 2];
2941 watchSizeBuf = &menuStrings.mainStrings[entry->actionListLength * 3]; // these fields are wasteful
2942 watchSkipBuf = &menuStrings.mainStrings[entry->actionListLength * 4]; // but the alternative is even more ugly
2943 watchPerLineBuf = &menuStrings.mainStrings[entry->actionListLength * 5];
2944
2945 sel = selection - 1;
2946
2947 memset(flagBuf, 0, (kType_Max * entry->actionListLength) + 2);
2948
2949 for(i = 0; i < entry->actionListLength; i++)
2950 {
2951 CheatAction * traverse = &entry->actionList[i];
2952
2953 UINT32 type = EXTRACT_FIELD(traverse->type, Type);
2954 UINT32 typeParameter = EXTRACT_FIELD(traverse->type, TypeParameter);
2955 UINT32 operation = EXTRACT_FIELD(traverse->type, Operation) |
2956 EXTRACT_FIELD(traverse->type, OperationExtend) << 2;
2957 UINT32 operationParameter = EXTRACT_FIELD(traverse->type, OperationParameter);
2958 UINT32 locationType = EXTRACT_FIELD(traverse->type, LocationType);
2959 UINT32 locationParameter = EXTRACT_FIELD(traverse->type, LocationParameter);
2960
2961 UINT8 wasCommentOrSelect = 0;
2962
2963 if(isSelect)
2964 {
2965 // do extend name field
2966
2967 menuItemInfo[total].subcheat = i;
2968 menuItemInfo[total].fieldType = kType_ExtendName;
2969 menuItem[total] = "Name";
2970
2971 if(traverse->optionalName)
2972 menuSubItem[total] = traverse->optionalName;
2973 else
2974 menuSubItem[total] = "(none)";
2975
2976 total++;
2977 }
2978
2979 if(i == 0)
2980 {
2981 {
2982 // do name field
2983
2984 menuItemInfo[total].subcheat = i;
2985 menuItemInfo[total].fieldType = kType_Name;
2986 menuItem[total] = "Name";
2987
2988 if(entry->name)
2989 menuSubItem[total] = entry->name;
2990 else
2991 menuSubItem[total] = "(none)";
2992
2993 total++;
2994 }
2995
2996 {
2997 // do comment field
2998
2999 menuItemInfo[total].subcheat = i;
3000 menuItemInfo[total].fieldType = kType_Comment;
3001 menuItem[total] = "Comment";
3002
3003 if(entry->comment)
3004 menuSubItem[total] = entry->comment;
3005 else
3006 menuSubItem[total] = "(none)";
3007
3008 total++;
3009 }
3010
3011 {
3012 // do activation key field
3013
3014 menuItemInfo[total].subcheat = i;
3015 menuItemInfo[total].fieldType = kType_ActivationKey;
3016 menuItem[total] = "Activation Key";
3017
3018 if(entry->activationKey < __code_key_first)
3019 entry->activationKey = __code_key_last;
3020 if(entry->activationKey > __code_key_last)
3021 entry->activationKey = __code_key_first;
3022
3023 if( (entry->flags & kCheatFlag_HasActivationKey))
3024 {
3025 menuSubItem[total] = kKeycodeNames[entry->activationKey - __code_key_first];
3026 }
3027 else
3028 {
3029 menuSubItem[total] = "(none)";
3030 }
3031
3032 total++;
3033 }
3034
3035 // check for select cheat
3036
3037 if( (locationType == kLocation_Custom) &&
3038 (locationParameter == kCustomLocation_Select))
3039 isSelect = 1;
3040 }
3041
3042 {
3043 // do type field
3044
3045 menuItemInfo[total].subcheat = i;
3046 menuItemInfo[total].fieldType = kType_Type;
3047 menuItem[total] = "Type";
3048
3049 if(locationType == kLocation_Custom)
3050 {
3051 if(locationParameter == kCustomLocation_Comment)
3052 {
3053 wasCommentOrSelect = 1;
3054
3055 menuSubItem[total] = kTypeNames[4];
3056 }
3057 else if(locationParameter == kCustomLocation_Select)
3058 {
3059 wasCommentOrSelect = 1;
3060
3061 menuSubItem[total] = kTypeNames[5];
3062 }
3063 else
3064 {
3065 menuSubItem[total] = kTypeNames[type & 3];
3066 }
3067 }
3068 else
3069 {
3070 menuSubItem[total] = kTypeNames[type & 3];
3071 }
3072
3073 total++;
3074 }
3075
3076 if(!wasCommentOrSelect)
3077 {
3078 if(type != kType_Watch)
3079 {
3080 {
3081 // do one shot field
3082
3083 menuItemInfo[total].subcheat = i;
3084 menuItemInfo[total].fieldType = kType_OneShot;
3085 menuItem[total] = "One Shot";
3086 menuSubItem[total] = ui_getstring(TEST_FIELD(traverse->type, OneShot) ? UI_on : UI_off);
3087
3088 total++;
3089 }
3090
3091 {
3092 // do restore previous value field
3093
3094 menuItemInfo[total].subcheat = i;
3095 menuItemInfo[total].fieldType = kType_RestorePreviousValue;
3096 menuItem[total] = "Restore Previous Value";
3097 menuSubItem[total] = ui_getstring(TEST_FIELD(traverse->type, RestorePreviousValue) ? UI_on : UI_off);
3098
3099 total++;
3100 }
3101 }
3102
3103 if((type == kType_NormalOrDelay) || (type == kType_WaitForModification))
3104 {
3105 // do delay field
3106
3107 menuItemInfo[total].subcheat = i;
3108 menuItemInfo[total].fieldType = kType_Delay;
3109 menuItem[total] = "Delay";
3110 menuSubItem[total] = kNumbersTable[typeParameter];
3111
3112 total++;
3113 }
3114
3115 if(type == kType_IgnoreIfDecrementing)
3116 {
3117 // do ignore decrement by field
3118
3119 menuItemInfo[total].subcheat = i;
3120 menuItemInfo[total].fieldType = kType_IgnoreDecrementBy;
3121 menuItem[total] = "Ignore Decrement By";
3122 menuSubItem[total] = kNumbersTable[typeParameter];
3123
3124 total++;
3125 }
3126
3127 if(type == kType_Watch)
3128 {
3129 {
3130 // do watch size field
3131
3132 sprintf(watchSizeBuf[i], "%d", (traverse->originalDataField & 0xFF) + 1);
3133
3134 menuItemInfo[total].subcheat = i;
3135 menuItemInfo[total].fieldType = kType_WatchSize;
3136 menuItem[total] = "Watch Size";
3137 menuSubItem[total] = watchSizeBuf[i];
3138
3139 total++;
3140 }
3141
3142 {
3143 // do watch skip field
3144
3145 sprintf(watchSkipBuf[i], "%d", (traverse->data >> 8) & 0xFF);
3146
3147 menuItemInfo[total].subcheat = i;
3148 menuItemInfo[total].fieldType = kType_WatchSkip;
3149 menuItem[total] = "Watch Skip";
3150 menuSubItem[total] = watchSkipBuf[i];
3151
3152 total++;
3153 }
3154
3155 {
3156 // do watch per line field
3157
3158 sprintf(watchPerLineBuf[i], "%d", (traverse->data >> 16) & 0xFF);
3159
3160 menuItemInfo[total].subcheat = i;
3161 menuItemInfo[total].fieldType = kType_WatchPerLine;
3162 menuItem[total] = "Watch Per Line";
3163 menuSubItem[total] = watchPerLineBuf[i];
3164
3165 total++;
3166 }
3167 }
3168 else
3169 {
3170 // do operation field
3171
3172 menuItemInfo[total].subcheat = i;
3173 menuItemInfo[total].fieldType = kType_Operation;
3174 menuItem[total] = "Operation";
3175 menuSubItem[total] = kOperationNames[operation];
3176
3177 total++;
3178 }
3179
3180 if((operation == kOperation_WriteMask) && (locationType != kLocation_IndirectIndexed))
3181 {
3182 // do mask field
3183
3184 int numChars;
3185
3186 if(traverse->flags & kActionFlag_IgnoreMask)
3187 {
3188 menuItemInfo[total].extraData = 0xFFFFFFFF;
3189 numChars = 8;
3190 }
3191 else
3192 {
3193 menuItemInfo[total].extraData = kCheatSizeMaskTable[EXTRACT_FIELD(traverse->type, BytesUsed)];
3194 numChars = kCheatSizeDigitsTable[EXTRACT_FIELD(traverse->type, BytesUsed)];
3195 }
3196
3197 sprintf(extendDataBuf[i], "%.*X", numChars, traverse->extendData);
3198
3199 menuItemInfo[total].subcheat = i;
3200 menuItemInfo[total].fieldType = kType_WriteMask;
3201 menuItem[total] = "Mask";
3202 menuSubItem[total] = extendDataBuf[i];
3203
3204 total++;
3205 }
3206
3207 if(operation == kOperation_AddSubtract)
3208 {
3209 {
3210 // do add/subtract field
3211
3212 menuItemInfo[total].subcheat = i;
3213 menuItemInfo[total].fieldType = kType_AddSubtract;
3214 menuItem[total] = "Add/Subtract";
3215 menuSubItem[total] = kAddSubtractNames[operationParameter];
3216
3217 total++;
3218 }
3219
3220 if(locationType != kLocation_IndirectIndexed)
3221 {
3222 if(operationParameter)
3223 {
3224 // do subtract minimum field
3225
3226 sprintf(extendDataBuf[i], "%.8X", traverse->extendData);
3227
3228 menuItemInfo[total].subcheat = i;
3229 menuItemInfo[total].fieldType = kType_SubtractMinimum;
3230 menuItem[total] = "Minimum Boundary";
3231 menuSubItem[total] = extendDataBuf[i];
3232
3233 total++;
3234 }
3235 else
3236 {
3237 // do add maximum field
3238
3239 sprintf(extendDataBuf[i], "%.8X", traverse->extendData);
3240
3241 menuItemInfo[total].subcheat = i;
3242 menuItemInfo[total].fieldType = kType_AddMaximum;
3243 menuItem[total] = "Maximum Boundary";
3244 menuSubItem[total] = extendDataBuf[i];
3245
3246 total++;
3247 }
3248 }
3249 }
3250
3251 if((operation == kOperation_ForceRange) && (locationType != kLocation_IndirectIndexed))
3252 {
3253 {
3254 // do range minimum field
3255
3256 sprintf(extendDataBuf[i], "%.2X", (traverse->extendData >> 8) & 0xFF);
3257
3258 menuItemInfo[total].subcheat = i;
3259 menuItemInfo[total].fieldType = kType_RangeMinimum;
3260 menuItem[total] = "Range Minimum";
3261 menuSubItem[total] = extendDataBuf[i];
3262
3263 total++;
3264 }
3265
3266 {
3267 // do range maximum field
3268
3269 sprintf(extendDataBuf[i] + 3, "%.2X", (traverse->extendData >> 8) & 0xFF);
3270
3271 menuItemInfo[total].subcheat = i;
3272 menuItemInfo[total].fieldType = kType_RangeMaximum;
3273 menuItem[total] = "Range Maximum";
3274 menuSubItem[total] = extendDataBuf[i] + 3;
3275
3276 total++;
3277 }
3278 }
3279
3280 if(operation == kOperation_SetOrClearBits)
3281 {
3282 // do set/clear field
3283
3284 menuItemInfo[total].subcheat = i;
3285 menuItemInfo[total].fieldType = kType_SetClear;
3286 menuItem[total] = "Set/Clear";
3287 menuSubItem[total] = kSetClearNames[operationParameter];
3288
3289 total++;
3290 }
3291
3292 if((operation != kOperation_None) || (type == kType_Watch))
3293 {
3294 UINT32 userSelect = TEST_FIELD(traverse->type, UserSelectEnable);
3295 UINT32 bytesUsed = EXTRACT_FIELD(traverse->type, BytesUsed);
3296
3297 if(type != kType_Watch)
3298 {
3299 {
3300 // do data field
3301
3302 sprintf(dataBuf[i], "%.*X (%d)", (int)kCheatSizeDigitsTable[bytesUsed], traverse->originalDataField, traverse->originalDataField);
3303
3304 menuItemInfo[total].subcheat = i;
3305 menuItemInfo[total].fieldType = kType_Data;
3306 menuItemInfo[total].extraData = kCheatSizeMaskTable[bytesUsed];
3307 menuItem[total] = "Data";
3308 menuSubItem[total] = dataBuf[i];
3309
3310 total++;
3311 }
3312
3313 {
3314 // do user select field
3315
3316 menuItemInfo[total].subcheat = i;
3317 menuItemInfo[total].fieldType = kType_UserSelect;
3318 menuItem[total] = "User Select";
3319 menuSubItem[total] = ui_getstring(userSelect ? UI_on : UI_off);
3320
3321 total++;
3322 }
3323
3324 if(userSelect)
3325 {
3326 {
3327 // do user select minimum displayed value field
3328
3329 menuItemInfo[total].subcheat = i;
3330 menuItemInfo[total].fieldType = kType_UserSelectMinimumDisp;
3331 menuItem[total] = "Minimum Displayed Value";
3332 menuSubItem[total] = kNumbersTable[EXTRACT_FIELD(traverse->type, UserSelectMinimumDisplay)];
3333
3334 total++;
3335 }
3336
3337 {
3338 // do user select minimum value field
3339
3340 menuItemInfo[total].subcheat = i;
3341 menuItemInfo[total].fieldType = kType_UserSelectMinimum;
3342 menuItem[total] = "Minimum Value";
3343 menuSubItem[total] = kNumbersTable[EXTRACT_FIELD(traverse->type, UserSelectMinimum)];
3344
3345 total++;
3346 }
3347
3348 {
3349 // do user select BCD field
3350
3351 menuItemInfo[total].subcheat = i;
3352 menuItemInfo[total].fieldType = kType_UserSelectBCD;
3353 menuItem[total] = "BCD";
3354 menuSubItem[total] = ui_getstring(TEST_FIELD(traverse->type, UserSelectBCD) ? UI_on : UI_off);
3355
3356 total++;
3357 }
3358
3359 {
3360 // do prefill field
3361
3362 menuItemInfo[total].subcheat = i;
3363 menuItemInfo[total].fieldType = kType_Prefill;
3364 menuItem[total] = "Prefill";
3365 menuSubItem[total] = kPrefillNames[EXTRACT_FIELD(traverse->type, Prefill)];
3366
3367 total++;
3368 }
3369 }
3370
3371 if(i > 0)
3372 {
3373 // do copy previous value field
3374
3375 menuItemInfo[total].subcheat = i;
3376 menuItemInfo[total].fieldType = kType_CopyPrevious;
3377 menuItem[total] = "Copy Previous Value";
3378 menuSubItem[total] = ui_getstring(TEST_FIELD(traverse->type, LinkCopyPreviousValue) ? UI_on : UI_off);
3379
3380 total++;
3381 }
3382 }
3383
3384 {
3385 // do byte length field
3386
3387 menuItemInfo[total].subcheat = i;
3388 menuItemInfo[total].fieldType = kType_ByteLength;
3389 menuItem[total] = "Byte Length";
3390 menuSubItem[total] = kSizeNames[bytesUsed];
3391
3392 total++;
3393 }
3394
3395 if(bytesUsed > 0)
3396 {
3397 // do endianness field
3398
3399 menuItemInfo[total].subcheat = i;
3400 menuItemInfo[total].fieldType = kType_Endianness;
3401 menuItem[total] = "Endianness";
3402 menuSubItem[total] = kEndiannessNames[EXTRACT_FIELD(traverse->type, Endianness)];
3403
3404 total++;
3405 }
3406
3407 {
3408 // do location type field
3409
3410 menuItemInfo[total].subcheat = i;
3411 menuItemInfo[total].fieldType = kType_LocationType;
3412 menuItem[total] = "Location";
3413
3414 if(locationType == kLocation_Custom)
3415 menuSubItem[total] = kCustomLocationNames[locationParameter];
3416 else
3417 menuSubItem[total] = kLocationNames[locationType];
3418
3419 total++;
3420 }
3421
3422 if(locationType == kLocation_Standard)
3423 {
3424 // do cpu field
3425
3426 menuItemInfo[total].subcheat = i;
3427 menuItemInfo[total].fieldType = kType_CPU;
3428 menuItem[total] = "CPU";
3429 menuSubItem[total] = kNumbersTable[locationParameter];
3430
3431 total++;
3432 }
3433
3434 if(locationType == kLocation_MemoryRegion)
3435 {
3436 // do region field
3437
3438 menuItemInfo[total].subcheat = i;
3439 menuItemInfo[total].fieldType = kType_Region;
3440 menuItem[total] = "Region";
3441 menuSubItem[total] = kRegionNames[locationParameter];
3442
3443 total++;
3444 }
3445
3446 if(locationType == kLocation_IndirectIndexed)
3447 {
3448 {
3449 // do packed CPU field
3450
3451 menuItemInfo[total].subcheat = i;
3452 menuItemInfo[total].fieldType = kType_PackedCPU;
3453 menuItem[total] = "CPU";
3454 menuSubItem[total] = kNumbersTable[(locationParameter >> 2) & 7];
3455
3456 total++;
3457 }
3458
3459 {
3460 // do packed size field
3461
3462 menuItemInfo[total].subcheat = i;
3463 menuItemInfo[total].fieldType = kType_PackedSize;
3464 menuItem[total] = "Address Size";
3465 menuSubItem[total] = kNumbersTable[(locationParameter & 3) + 1];
3466
3467 total++;
3468 }
3469
3470 {
3471 // do address index field
3472
3473 // swap if negative
3474 if(traverse->extendData & 0x80000000)
3475 {
3476 int temp = traverse->extendData;
3477
3478 temp = -temp;
3479
3480 sprintf(extendDataBuf[i], "-%.8X", temp);
3481 }
3482 else
3483 {
3484 sprintf(extendDataBuf[i], "%.8X", traverse->extendData);
3485 }
3486
3487 menuItemInfo[total].subcheat = i;
3488 menuItemInfo[total].fieldType = kType_AddressIndex;
3489 menuItem[total] = "Address Index";
3490 menuSubItem[total] = extendDataBuf[i];
3491
3492 total++;
3493 }
3494 }
3495
3496 {
3497 // do address field
3498
3499 int charsToPrint = 8;
3500
3501 switch(EXTRACT_FIELD(traverse->type, LocationType))
3502 {
3503 case kLocation_Standard:
3504 case kLocation_HandlerMemory:
3505 {
3506 CPUInfo * cpuInfo = &cpuInfoList[EXTRACT_FIELD(traverse->type, LocationParameter)];
3507
3508 charsToPrint = cpuInfo->addressCharsNeeded;
3509 menuItemInfo[total].extraData = cpuInfo->addressMask;
3510 }
3511 break;
3512
3513 case kLocation_IndirectIndexed:
3514 {
3515 CPUInfo * cpuInfo = &cpuInfoList[(EXTRACT_FIELD(traverse->type, LocationParameter) >> 2) & 7];
3516
3517 charsToPrint = cpuInfo->addressCharsNeeded;
3518 menuItemInfo[total].extraData = cpuInfo->addressMask;
3519 }
3520 break;
3521
3522 default:
3523 menuItemInfo[total].extraData = 0xFFFFFFFF;
3524 }
3525
3526 sprintf(addressBuf[i], "%.*X", charsToPrint, traverse->address);
3527
3528 menuItemInfo[total].subcheat = i;
3529 menuItemInfo[total].fieldType = kType_Address;
3530 menuItem[total] = "Address";
3531 menuSubItem[total] = addressBuf[i];
3532
3533 total++;
3534 }
3535 }
3536 }
3537
3538 if(i < (entry->actionListLength - 1))
3539 {
3540 menuItemInfo[total].subcheat = i;
3541 menuItemInfo[total].fieldType = kType_Divider;
3542 menuItem[total] = "===";
3543 menuSubItem[total] = NULL;
3544
3545 total++;
3546 }
3547 }
3548
3549 menuItemInfo[total].subcheat = 0;
3550 menuItemInfo[total].fieldType = kType_Return;
3551 menuItem[total] = ui_getstring(UI_returntoprior);
3552 menuSubItem[total] = NULL;
3553 total++;
3554
3555 menuItemInfo[total].subcheat = 0;
3556 menuItemInfo[total].fieldType = kType_Return;
3557 menuItem[total] = NULL;
3558 menuSubItem[total] = NULL;
3559
3560 if(sel < 0)
3561 sel = 0;
3562 if(sel >= total)
3563 sel = total - 1;
3564
3565 info = &menuItemInfo[sel];
3566 action = &entry->actionList[info->subcheat];
3567
3568 if(editActive)
3569 flagBuf[sel] = 1;
3570
3571 ui_displaymenu(bitmap, menuItem, menuSubItem, flagBuf, sel, 0);
3572
3573 if(AltKeyPressed())
3574 increment <<= 4;
3575 if(ControlKeyPressed())
3576 increment <<= 8;
3577 if(ShiftKeyPressed())
3578 increment <<= 16;
3579
3580 if(UIPressedRepeatThrottle(IPT_UI_LEFT, kHorizontalSlowKeyRepeatRate))
3581 {
3582 editActive = 0;
3583 dirty = 1;
3584
3585 switch(info->fieldType)
3586 {
3587 case kType_Name:
3588 currentNameTemplate--;
3589
3590 if(currentNameTemplate < 0)
3591 {
3592 currentNameTemplate = 0;
3593
3594 while(kCheatNameTemplates[currentNameTemplate + 1][0])
3595 {
3596 currentNameTemplate++;
3597 }
3598 }
3599
3600 entry->name = realloc(entry->name, strlen(kCheatNameTemplates[currentNameTemplate]) + 1);
3601 strcpy(entry->name, kCheatNameTemplates[currentNameTemplate]);
3602 break;
3603
3604 case kType_ActivationKey:
3605 entry->activationKey--;
3606
3607 if(entry->activationKey < __code_key_first)
3608 entry->activationKey = __code_key_last;
3609 if(entry->activationKey > __code_key_last)
3610 entry->activationKey = __code_key_first;
3611
3612