| 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 |
|