mirror of
https://github.com/holub/mame
synced 2025-05-22 13:48:55 +03:00

- Roll back older periodic function Now standard/old format work in this function Otherwords, several operations which doesn't exist in older function and added recently are now disabled - Separated load_cheat_code() to 3 indipendent functions And added new cheat options, "Load New/Standard/Old Format Code" (Default : load all format codes) NOTE : delete all cheat options in the database before start or reload default options (Shift + Reload key) in cheat general menu - Added format strings structure to accept huge size strings in loading a database to prevent from breaking other strings - Changed Link in new format Label code is now "Link-Label" and sub-label is "Label-Sub-Link" "Standard-Link" is no longer label - Added choose_label_index() to manage label selection - Fixed build_label_index_table() to prevent from crashing And disabled to build label index table in case of standard/old format - Fixed memory free problem in case of standard/old code - Fixed several reported/found bugs
13468 lines
383 KiB
C
13468 lines
383 KiB
C
/*********************************************************************
|
|
|
|
cheat.c
|
|
|
|
MAME cheat system.
|
|
|
|
Copyright Nicola Salmoria and the MAME Team.
|
|
Visit http://mamedev.org for licensing and usage restrictions.
|
|
|
|
*********************************************************************/
|
|
|
|
#include "driver.h"
|
|
#include "ui.h"
|
|
#include "uimenu.h"
|
|
#include "machine/eeprom.h"
|
|
#include "cheat.h"
|
|
#include "deprecat.h"
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
#ifdef MESS
|
|
#include "cheatms.h"
|
|
#endif
|
|
|
|
#define OSD_READKEY_KLUDGE 1
|
|
|
|
/***************************************************************************
|
|
MACROS
|
|
***************************************************************************/
|
|
|
|
/* easy bitfield extraction and setting, uses *_Shift, *_ShiftedMask, and *_Mask enums */
|
|
#define EXTRACT_FIELD(data, name) (((data) >> k##name##_Shift) & k##name##_ShiftedMask)
|
|
#define SET_FIELD(data, name, in) (data = (data & ~(k##name##_ShiftedMask << k##name##_Shift)) | (((in) & k##name##_ShiftedMask) << k##name##_Shift))
|
|
#define TEST_FIELD(data, name) ((data) & k##name##_Mask)
|
|
#define SET_MASK_FIELD(data, name) ((data) |= k##name##_Mask)
|
|
#define CLEAR_MASK_FIELD(data, name) ((data) &= ~(k##name##_Mask))
|
|
#define TOGGLE_MASK_FIELD(data, name) ((data) ^= k##name##_Mask)
|
|
|
|
#define DEFINE_BITFIELD_ENUM(name, end, start) k##name##_Shift = (int)(end), \
|
|
k##name##_ShiftedMask = (int)(0xFFFFFFFF >> (32 - (start - end + 1))), \
|
|
k##name##_Mask = (int)(k##name##_ShiftedMask << k##name##_Shift)
|
|
|
|
#define REGION_LIST_LENGTH (REGION_MAX - REGION_INVALID)
|
|
#define VALID_CPU(cpu) (cpu < cpu_gettotalcpu())
|
|
|
|
#define TERMINATE_MENU_ITEMS(name) do { menu_item[total] = NULL; menu_sub_item[total] = NULL; menu_item_info[total].field_type = name; } while(0)
|
|
|
|
#define ADJUST_CURSOR(sel, total) do { if(sel < 0) sel = 0; else if(sel > (total - 1)) sel = (total - 1); } while(0)
|
|
#define CURSOR_TO_NEXT(sel, total) do { if(++sel > (total - 1)) sel = 0; } while(0)
|
|
#define CURSOR_TO_PREVIOUS(sel, total) do { if(--sel < 0) sel = (total - 1); } while(0)
|
|
#define CURSOR_PAGE_UP(sel) do { sel -= visible_items; if(sel < 0) sel = 0; } while (0)
|
|
#define CURSOR_PAGE_DOWN(sel, total) do { sel += visible_items; if(sel >= total) sel = (total - 1); } while (0)
|
|
#define SET_MESSAGE(type) do { message_timer = DEFAULT_MESSAGE_TIME; message_type = type; } while(0)
|
|
|
|
/***************************************************************************
|
|
CONSTANTS
|
|
***************************************************************************/
|
|
|
|
#define CHEAT_FILENAME_MAX_LEN (255)
|
|
#define CHEAT_MENU_DEPTH (8)
|
|
#ifdef MESS
|
|
#define DEFAULT_CHEAT_OPTIONS (0x1FFF8)
|
|
#else
|
|
#define DEFAULT_CHEAT_OPTIONS (0x1FEF8)
|
|
#endif
|
|
#define DEFAULT_MESSAGE_TIME (50)
|
|
#define VARIABLE_MAX_ARRAY (8) /* NOTE : Destination in Move code can only accept variable[0]-[3] only */
|
|
#define CHEAT_RETURN_VALUE (0xFF)
|
|
#define SAFE_SEARCH_REGION_RANGE (65536)
|
|
|
|
/********** BIT FIELD **********/
|
|
|
|
enum
|
|
{
|
|
/* type field */
|
|
DEFINE_BITFIELD_ENUM(OneShot, 0, 0),
|
|
DEFINE_BITFIELD_ENUM(DelayEnable, 1, 3),
|
|
DEFINE_BITFIELD_ENUM(PrefillEnable, 4, 5),
|
|
DEFINE_BITFIELD_ENUM(Return, 6, 6),
|
|
DEFINE_BITFIELD_ENUM(RestoreValue, 7, 7),
|
|
DEFINE_BITFIELD_ENUM(ValueSelectEnable, 8, 8), /* = CopyValueEnable */
|
|
DEFINE_BITFIELD_ENUM(ValueSelectMinimumDisplay, 9, 9),
|
|
DEFINE_BITFIELD_ENUM(ValueSelectMinimum, 10, 10),
|
|
DEFINE_BITFIELD_ENUM(ValueSelectBCD, 11, 11), /* = CopyValueBCD */
|
|
DEFINE_BITFIELD_ENUM(ValueSelectNegative, 12, 12), /* = CopyValueNegative */
|
|
DEFINE_BITFIELD_ENUM(PopupParameter, 13, 14),
|
|
DEFINE_BITFIELD_ENUM(DataRead, 15, 15), /* 0 = field, 1 = variable */
|
|
DEFINE_BITFIELD_ENUM(Link, 16, 17), /* 0 = master, 1 = link, 2 = label link, 3 = label sub link */
|
|
DEFINE_BITFIELD_ENUM(AddressSize, 20, 21),
|
|
DEFINE_BITFIELD_ENUM(AddressRead, 22, 23), /* 0 = field, 1 = indirect address from variable, 2 = variable */
|
|
DEFINE_BITFIELD_ENUM(CodeParameter, 24, 27),
|
|
DEFINE_BITFIELD_ENUM(CodeParameterLower, 24, 25),
|
|
DEFINE_BITFIELD_ENUM(CodeParameterUpper, 26, 27),
|
|
DEFINE_BITFIELD_ENUM(CodeType, 28, 31),
|
|
|
|
/* extend field */
|
|
DEFINE_BITFIELD_ENUM(LSB16, 0, 15), /* lower 4 bytes */
|
|
DEFINE_BITFIELD_ENUM(MSB16, 16, 31), /* upper 4 bytes */
|
|
|
|
/* watch code */
|
|
DEFINE_BITFIELD_ENUM(WatchDisplayFormat, 24, 25), /* from type field */
|
|
DEFINE_BITFIELD_ENUM(WatchShowLabel, 26, 27), /* from type field */
|
|
DEFINE_BITFIELD_ENUM(WatchNumElements, 0, 7), /* from data field */
|
|
DEFINE_BITFIELD_ENUM(WatchSkip, 8, 15), /* from data field */
|
|
DEFINE_BITFIELD_ENUM(WatchElementsPerLine, 16, 23), /* from data field */
|
|
DEFINE_BITFIELD_ENUM(WatchAddValue, 24, 31), /* from data field */
|
|
|
|
/* label-selection */
|
|
DEFINE_BITFIELD_ENUM(LabelSelectUseSelector, 4, 4),
|
|
DEFINE_BITFIELD_ENUM(LabelSelectQuickClose, 5, 5),
|
|
|
|
/* cpu/region field */
|
|
DEFINE_BITFIELD_ENUM(CPUIndex, 0, 3),
|
|
DEFINE_BITFIELD_ENUM(AddressSpace, 4, 6),
|
|
// DEFINE_BITFIELD_ENUM(RegionIndex, 0, 6), /* unused ??? */
|
|
|
|
/* old code */
|
|
// DEFINE_BITFIELD_ENUM(OneShot, 0, 0), /* = OneShot in new format */
|
|
DEFINE_BITFIELD_ENUM(Type, 1, 2),
|
|
DEFINE_BITFIELD_ENUM(Operation, 3, 4),
|
|
DEFINE_BITFIELD_ENUM(TypeParameter, 5, 7),
|
|
DEFINE_BITFIELD_ENUM(UserSelectEnable, 8, 8),
|
|
DEFINE_BITFIELD_ENUM(UserSelectMinimumDisplay, 9, 9),
|
|
DEFINE_BITFIELD_ENUM(UserSelectMinimum, 10, 10),
|
|
DEFINE_BITFIELD_ENUM(UserSelectBCD, 11, 11),
|
|
DEFINE_BITFIELD_ENUM(Prefill, 12, 13),
|
|
DEFINE_BITFIELD_ENUM(IndexBytesUsed, 14, 15),
|
|
DEFINE_BITFIELD_ENUM(LinkEnable, 16, 16),
|
|
DEFINE_BITFIELD_ENUM(LinkCopyPreviousValue, 17, 17),
|
|
DEFINE_BITFIELD_ENUM(OperationParameter, 18, 19),
|
|
DEFINE_BITFIELD_ENUM(BytesUsed, 20, 21),
|
|
DEFINE_BITFIELD_ENUM(RemoveFromList, 22, 22),
|
|
DEFINE_BITFIELD_ENUM(RestorePreviousValue, 23, 23),
|
|
DEFINE_BITFIELD_ENUM(LocationParameter, 24, 28),
|
|
DEFINE_BITFIELD_ENUM(LocationType, 29, 31),
|
|
DEFINE_BITFIELD_ENUM(LocationParameterCPU, 24, 26),
|
|
|
|
/* command */
|
|
DEFINE_BITFIELD_ENUM(SearchBox, 0, 1),
|
|
DEFINE_BITFIELD_ENUM(DontPrintNewLabels, 2, 2), /* advanced mode only. in options menu, it is reversed display */
|
|
DEFINE_BITFIELD_ENUM(AutoSaveEnabled, 3, 3),
|
|
DEFINE_BITFIELD_ENUM(ActivationKeyMessage, 4, 4),
|
|
DEFINE_BITFIELD_ENUM(LoadNewCode, 5, 5),
|
|
DEFINE_BITFIELD_ENUM(LoadStandardCode, 6, 6),
|
|
DEFINE_BITFIELD_ENUM(LoadOldCode, 7, 7),
|
|
#ifdef MESS
|
|
DEFINE_BITFIELD_ENUM(SharedCode, 8, 8),
|
|
#endif
|
|
DEFINE_BITFIELD_ENUM(VerticalKeyRepeatSpeed, 9, 12),
|
|
DEFINE_BITFIELD_ENUM(HorizontalKeyRepeatSpeed, 13, 16),
|
|
};
|
|
|
|
/********** OPERATION **********/
|
|
|
|
enum{ // address space for RAM region
|
|
kAddressSpace_Program = 0,
|
|
kAddressSpace_DataSpace,
|
|
kAddressSpace_IOSpace,
|
|
kAddressSpace_OpcodeRAM,
|
|
kAddressSpace_MappedMemory,
|
|
kAddressSpace_DirectMemory,
|
|
kAddressSpace_EEPROM };
|
|
|
|
enum{ // code types
|
|
kCodeType_Write = 0, // EF = Mask
|
|
kCodeType_IWrite, // EF = Index
|
|
kCodeType_RWrite, // EF = Count/Skip
|
|
kCodeType_CWrite, // EF = Condition
|
|
kCodeType_CBit, // EF = Condition
|
|
kCodeType_PDWWrite, // EF = 2nd Data
|
|
kCodeType_Move, // DF = Add Value, EF = Destination
|
|
kCodeType_Branch, // DF = Jump Code, EF = Condition
|
|
kCodeType_Loop,
|
|
kCodeType_Popup, // EF = Condition
|
|
kCodeType_Watch, // EF = position
|
|
kCodeType_Unused };
|
|
|
|
enum{ /* parameter for IWrite */
|
|
IWRITE_WRITE = 0,
|
|
IWRITE_BIT_SET,
|
|
IWRITE_BIT_CLEAR,
|
|
IWRITE_LIMITED_MASK };
|
|
|
|
enum{ /* parameter for CBit */
|
|
CBIT_BIT_SET = 0,
|
|
CBIT_BIT_CLEAR,
|
|
CBIT_LIMITED_MASK };
|
|
|
|
enum{ /* conditions for CWrite, Branch, Popup */
|
|
kCondition_Equal = 0,
|
|
kCondition_NotEqual,
|
|
kCondition_Less,
|
|
kCondition_LessOrEqual,
|
|
kCondition_Greater,
|
|
kCondition_GreaterOrEqual,
|
|
kCondition_BitSet,
|
|
kCondition_BitClear,
|
|
kCondition_Unused1,
|
|
kCondition_Unused2,
|
|
kCondition_Unused3,
|
|
kCondition_Unused4,
|
|
kCondition_PreviousValue,
|
|
kCondition_KeyPressedOnce,
|
|
kCondition_KeyPressedRepeat,
|
|
kCondition_True };
|
|
|
|
enum{ /* conditions for CBit */
|
|
CONDITION_CBIT_BIT_SET = 0,
|
|
CONDITION_CBIT_BIT_CLEAR };
|
|
|
|
enum{ // popup parameter
|
|
kPopup_Label = 0,
|
|
kPopup_Value,
|
|
kPopup_LabelValue,
|
|
kPopup_ValueLabel };
|
|
|
|
enum{ /* custom code */
|
|
CUSTOM_CODE = 0xF0,
|
|
CUSTOM_CODE_COMMENT,
|
|
CUSTOM_CODE_SEPARATOR,
|
|
CUSTOM_CODE_LABEL_SELECT,
|
|
CUSTOM_CODE_LAYER_TAG,
|
|
CUSTOM_CODE_UNUSED_1,
|
|
CUSTOM_CODE_UNUSED_2,
|
|
CUSTOM_CODE_UNUSED_3,
|
|
CUSTOM_CODE_ACTIVATION_KEY,
|
|
CUSTOM_CODE_PRE_ENABLE,
|
|
CUSTOM_CODE_OVER_CLOCK,
|
|
CUSTOM_CODE_REFRESH_RATE };
|
|
|
|
enum{ /* link */
|
|
LINK_MASTER = 0,
|
|
LINK_STANDARD_LINK,
|
|
LINK_LABEL_LINK,
|
|
LINK_LABEL_SUB_LINK
|
|
};
|
|
|
|
enum{ // address read from
|
|
kReadFrom_Address = 0, // $xxxx
|
|
kReadFrom_Index, // $Vx
|
|
kReadFrom_Variable }; // Vx
|
|
|
|
enum // types
|
|
{
|
|
kType_NormalOrDelay = 0,
|
|
kType_WaitForModification,
|
|
kType_IgnoreIfDecrementing,
|
|
kType_Watch
|
|
};
|
|
|
|
enum // operations
|
|
{
|
|
kOperation_WriteMask = 0,
|
|
kOperation_AddSubtract,
|
|
kOperation_ForceRange,
|
|
kOperation_SetOrClearBits,
|
|
kOperation_Unused4,
|
|
kOperation_Unused5,
|
|
kOperation_Unused6,
|
|
kOperation_None
|
|
};
|
|
|
|
//enum // prefills (unused?)
|
|
//{
|
|
// kPrefill_Disable = 0,
|
|
// kPrefill_UseFF,
|
|
// kPrefill_Use00,
|
|
// kPrefill_Use01
|
|
//};
|
|
|
|
enum // location types
|
|
{
|
|
kLocation_Standard = 0,
|
|
kLocation_MemoryRegion,
|
|
kLocation_HandlerMemory,
|
|
kLocation_Custom,
|
|
kLocation_IndirectIndexed,
|
|
kLocation_Unused5,
|
|
kLocation_Unused6,
|
|
kLocation_Unused7
|
|
};
|
|
|
|
enum // location parameters
|
|
{
|
|
kCustomLocation_Comment = 0,
|
|
kCustomLocation_EEPROM,
|
|
kCustomLocation_Select,
|
|
kCustomLocation_AssignActivationKey,
|
|
kCustomLocation_Enable,
|
|
kCustomLocation_Overclock,
|
|
kCustomLocation_RefreshRate
|
|
};
|
|
|
|
enum // memory accessor parameters
|
|
{
|
|
kMemoryLocation_DirectAccess = 0,
|
|
kMemoryLocation_DataSpace,
|
|
kMemoryLocation_IOSpace,
|
|
kMemoryLocation_OpbaseRAM
|
|
};
|
|
|
|
enum // action flags
|
|
{
|
|
/* set if this code is not the newest format */
|
|
kActionFlag_OldFormat = 1 << 0,
|
|
|
|
/* set if this code doesn't need to read/write a value */
|
|
kActionFlag_NoAction = 1 << 1,
|
|
|
|
/* set if this code is custom cheat */
|
|
kActionFlag_Custom = 1 << 2,
|
|
|
|
/* set for one shot cheats after the operation is performed */
|
|
kActionFlag_OperationDone = 1 << 3,
|
|
|
|
/* set if the code is memory writing type (Write, IWrite, RWrite, CWrite, CBit, PDWWrite) */
|
|
kActionFlag_MemoryWrite = 1 << 4,
|
|
|
|
/* set if the extend data field is being used by index adress reading (IWrite, Move) */
|
|
kActionFlag_IndexAddress = 1 << 5,
|
|
|
|
/* set if the code uses limited mask which divids data field to 16-bit data and 16-bit mask (IWrite, CBit) */
|
|
kActionFlag_LimitedMask = 1 << 6,
|
|
|
|
/* set if the code needs to check the condition (CWrite, CBit, Branch, Popup) */
|
|
kActionFlag_CheckCondition = 1 << 7,
|
|
|
|
/* set if the code needs to repeat writing (RWrite) */
|
|
kActionFlag_Repeat = 1 << 8,
|
|
|
|
/* set if the extendData field is being used by 2nd data (PDWWrite) */
|
|
kActionFlag_PDWWrite = 1 << 9,
|
|
|
|
/* set if the lastValue field contains valid data and can be restored if needed */
|
|
kActionFlag_LastValueGood = 1 << 10,
|
|
|
|
/* set after value changes from prefill value */
|
|
kActionFlag_PrefillDone = 1 << 11,
|
|
|
|
/* set after prefill value written */
|
|
kActionFlag_PrefillWritten = 1 << 12,
|
|
|
|
/* set if the code is a label for label-selection code */
|
|
kActionFlag_IsLabel = 1 << 13,
|
|
|
|
/* set if the code is a sub-label for label-selection code */
|
|
kActionFlag_IsSubLabel = 1 << 14,
|
|
|
|
/* set when read/write a data after 1st read/write and clear after 2nd read/write (PDWWrite) */
|
|
kActionFlag_IsFirst = 1 << 16,
|
|
|
|
/* set for wait for modification or ignore if decrementing cheats when the targeted value has changed */
|
|
/* cleared after the operation is performed */
|
|
kActionFlag_WasModified = 1 << 17,
|
|
|
|
/* masks */
|
|
kActionFlag_StateMask = kActionFlag_OperationDone | /* used in reset_action() to clear specified flags */
|
|
kActionFlag_LastValueGood |
|
|
kActionFlag_PrefillDone |
|
|
kActionFlag_PrefillWritten,
|
|
kActionFlag_InfoMask = kActionFlag_IndexAddress | /* ??? unused ??? */
|
|
kActionFlag_WasModified,
|
|
kActionFlag_PersistentMask = kActionFlag_OldFormat | /* used in update_cheat_info(machine, ) to clear other flags */
|
|
kActionFlag_LastValueGood
|
|
};
|
|
|
|
enum // entry flags
|
|
{
|
|
/* true when the cheat is active */
|
|
kCheatFlag_Active = 1 << 0,
|
|
|
|
/* true if the cheat is entirely one shot */
|
|
kCheatFlag_OneShot = 1 << 1,
|
|
|
|
/* true if the cheat is entirely null (ex. a comment) */
|
|
kCheatFlag_Null = 1 << 2,
|
|
|
|
/* true if the cheat is multi-comment code */
|
|
kCheatFlag_ExtendComment = 1 << 3,
|
|
|
|
/* true if the cheat is specified separator */
|
|
kCheatFlag_Separator = 1 << 4,
|
|
|
|
/* true if the cheat contains a user-select element */
|
|
kCheatFlag_UserSelect = 1 << 5,
|
|
|
|
/* true if the cheat is a select cheat */
|
|
kCheatFlag_Select = 1 << 6,
|
|
|
|
/* true if use label-selector */
|
|
kCheatFlag_UseLabelSelector = 1 << 7,
|
|
|
|
/* true if the cheat is layer index cheat */
|
|
kCheatFlag_LayerIndex = 1 << 8,
|
|
|
|
/* true if selected code is layer index cheat */
|
|
kCheatFlag_LayerSelected = 1 << 9,
|
|
|
|
/* true if selected code requests left/right arrow for sub item */
|
|
kCheatFlag_RequestArrow = 1 << 10,
|
|
|
|
/* true if the cheat is not the newest format */
|
|
kCheatFlag_OldFormat = 1 << 11,
|
|
|
|
/* true if wrong cheat code */
|
|
kCheatFlag_HasWrongCode = 1 << 12,
|
|
|
|
/* true if the cheat has been edited or is a new cheat
|
|
checked at auto-save then save the code if true */
|
|
|
|
kCheatFlag_Dirty = 1 << 15,
|
|
|
|
/* masks */
|
|
kCheatFlag_StateMask = kCheatFlag_Active, // used in reset_action() and deactivate_cheat(machine, ) to clear specified flag
|
|
kCheatFlag_InfoMask = kCheatFlag_OneShot | // used in update_cheat_info(machine, ) to detect specified flags
|
|
kCheatFlag_Null |
|
|
kCheatFlag_ExtendComment |
|
|
kCheatFlag_Separator |
|
|
kCheatFlag_UserSelect |
|
|
kCheatFlag_Select |
|
|
kCheatFlag_UseLabelSelector |
|
|
kCheatFlag_LayerIndex |
|
|
kCheatFlag_OldFormat,
|
|
kCheatFlag_PersistentMask = kCheatFlag_Active | // used in update_cheat_info(machine, ) to extract specified flags
|
|
kCheatFlag_Dirty
|
|
};
|
|
|
|
/********** WATCH **********/
|
|
|
|
enum // types
|
|
{
|
|
kWatchLabel_None = 0,
|
|
kWatchLabel_Address,
|
|
kWatchLabel_String,
|
|
|
|
kWatchLabel_MaxPlusOne
|
|
};
|
|
|
|
enum // display types
|
|
{
|
|
kWatchDisplayType_Hex = 0,
|
|
kWatchDisplayType_Decimal,
|
|
kWatchDisplayType_Binary,
|
|
kWatchDisplayType_ASCII,
|
|
|
|
kWatchDisplayType_MaxPlusOne
|
|
};
|
|
|
|
/********** SEARCH REGION **********/
|
|
|
|
enum // flags
|
|
{
|
|
/* true if enabled for search */
|
|
kRegionFlag_Enabled = 1 << 0,
|
|
|
|
/* true if this region has an error */
|
|
kRegionFlag_HasError = 1 << 1,
|
|
|
|
/* true if the memory region has no mapped memory and uses a memory handler (unused?) */
|
|
/* kRegionFlag_UsesHandler = */
|
|
};
|
|
|
|
enum // types
|
|
{
|
|
kRegionType_CPU = 0,
|
|
kRegionType_Memory
|
|
};
|
|
|
|
enum /* search speed */
|
|
{
|
|
SEARCH_SPEED_FAST = 0, /* RAM + some banks */
|
|
SEARCH_SPEED_MEDIUM, /* RAM + BANKx */
|
|
SEARCH_SPEED_SLOW, /* all memory areas except ROM, NOP, and custom handlers */
|
|
SEARCH_SPEED_VERY_SLOW, /* all memory areas except ROM and NOP */
|
|
SEARCH_SPEED_ALL_MEMORY, /* entire CPU address space */
|
|
SEARCH_SPEED_USER_DEFINED, /* user defined region */
|
|
|
|
SEARCH_SPEED_MAX
|
|
};
|
|
|
|
/********** SEARCH INFO **********/
|
|
|
|
enum // operands
|
|
{
|
|
kSearchOperand_Current = 0,
|
|
kSearchOperand_Previous,
|
|
kSearchOperand_First,
|
|
kSearchOperand_Value,
|
|
|
|
kSearchOperand_Max
|
|
};
|
|
|
|
enum // length
|
|
{
|
|
kSearchSize_8Bit = 0,
|
|
kSearchSize_16Bit,
|
|
kSearchSize_24Bit,
|
|
kSearchSize_32Bit,
|
|
kSearchSize_1Bit,
|
|
|
|
kSearchSize_Max = kSearchSize_1Bit
|
|
};
|
|
|
|
enum // comparisons
|
|
{
|
|
kSearchComparison_LessThan = 0,
|
|
kSearchComparison_GreaterThan,
|
|
kSearchComparison_EqualTo,
|
|
kSearchComparison_LessThanOrEqualTo,
|
|
kSearchComparison_GreaterThanOrEqualTo,
|
|
kSearchComparison_NotEqual,
|
|
kSearchComparison_IncreasedBy,
|
|
kSearchComparison_NearTo,
|
|
|
|
kSearchComparison_Max
|
|
};
|
|
|
|
enum /* comparisons for minimum mode */
|
|
{
|
|
MINIMUM_ITEM_EQUAL = 0,
|
|
MINIMUM_ITEM_NOT_EQUAL,
|
|
MINIMUM_ITEM_LESS,
|
|
MINIMUM_ITEM_GREATER,
|
|
MINIMUM_ITEM_INCREMENT,
|
|
MINIMUM_ITEM_DECREMENT,
|
|
|
|
MINIMUM_ITEM_MAX
|
|
};
|
|
|
|
/********** OTHERS **********/
|
|
|
|
enum /* search menu */
|
|
{
|
|
SEARCH_BOX_MINIMUM = 0,
|
|
SEARCH_BOX_STANDARD,
|
|
SEARCH_BOX_ADVANCED
|
|
};
|
|
|
|
enum /* load code */
|
|
{
|
|
LOAD_CHEAT_OPTIONS = 0,
|
|
LOAD_CHEAT_CODE_NEW,
|
|
LOAD_CHEAT_CODE_STANDARD,
|
|
LOAD_CHEAT_CODE_OLD,
|
|
LOAD_USER_REGION
|
|
};
|
|
|
|
enum /* disposition for resizing a list */
|
|
{
|
|
REQUEST_DISPOSE = 0,
|
|
NO_DISPOSE
|
|
};
|
|
|
|
enum /* database open flags */
|
|
{
|
|
DATABASE_LOAD = 0,
|
|
DATABASE_SAVE
|
|
};
|
|
|
|
enum /* message type */
|
|
{
|
|
CHEAT_MESSAGE_NONE = 0, /* this message should be unused */
|
|
CHEAT_MESSAGE_RELOAD_CHEAT_OPTION,
|
|
CHEAT_MESSAGE_RELOAD_CHEAT_CODE,
|
|
CHEAT_MESSAGE_RELOAD_USER_REGION,
|
|
CHEAT_MESSAGE_RESET_OPTIONS,
|
|
CHEAT_MESSAGE_FAILED_TO_LOAD_DATABASE,
|
|
CHEAT_MESSAGE_CHEAT_FOUND,
|
|
CHEAT_MESSAGE_ONE_CHEAT_FOUND,
|
|
CHEAT_MESSAGE_SUCCEEDED_TO_SAVE,
|
|
CHEAT_MESSAGE_FAILED_TO_SAVE,
|
|
CHEAT_MESSAGE_NO_SUPPORTED_OLD_FORMAT,
|
|
CHEAT_MESSAGE_ALL_CHEATS_SAVED,
|
|
CHEAT_MESSAGE_ACTIVATION_KEY_SAVED,
|
|
CHEAT_MESSAGE_NO_ACTIVATION_KEY,
|
|
CHEAT_MESSAGE_PRE_ENABLE_SAVED,
|
|
CHEAT_MESSAGE_SUCCEEDED_TO_ADD,
|
|
CHEAT_MESSAGE_FAILED_TO_ADD,
|
|
CHEAT_MESSAGE_SUCCEEDED_TO_DELETE,
|
|
CHEAT_MESSAGE_FAILED_TO_DELETE,
|
|
CHEAT_MESSAGE_NO_SEARCH_REGION,
|
|
CHEAT_MESSAGE_RESTORE_VALUE,
|
|
CHEAT_MESSAGE_NO_OLD_VALUE,
|
|
CHEAT_MESSAGE_INITIALIZE_MEMORY,
|
|
CHEAT_MESSAGE_INVALIDATE_REGION,
|
|
CHEAT_MESSAGE_FAILED_TO_ALLOCATE,
|
|
CHEAT_MESSAGE_WRONG_CODE,
|
|
|
|
CHEAT_MESSAGE_MAX
|
|
};
|
|
|
|
enum{ // error flags
|
|
kErrorFlag_InvalidLocationType = 1, // old
|
|
kErrorFlag_InvalidOperation = 1 << 1, // old
|
|
kErrorFlag_InvalidCodeType = 1 << 2, // new
|
|
kErrorFlag_InvalidCondition = 1 << 3, // new
|
|
kErrorFlag_InvalidCodeOption = 1 << 4, // new
|
|
kErrorFlag_ConflictedExtendField = 1 << 5, // old
|
|
kErrorFlag_InvalidRange = 1 << 6,
|
|
kErrorFlag_NoRestorePreviousValue = 1 << 7,
|
|
kErrorFlag_NoLabel = 1 << 8,
|
|
kErrorFlag_ConflictedSelects = 1 << 9,
|
|
kErrorFlag_InvalidDataField = 1 << 10,
|
|
kErrorFlag_InvalidExtendDataField = 1 << 11,
|
|
kErrorFlag_ForbittenVariable = 1 << 12, // new
|
|
kErrorFlag_NoSelectableValue = 1 << 13,
|
|
kErrorFlag_InvalidLimitedMaskSize = 1 << 14, // new
|
|
kErrorFlag_NoRepeatCount = 1 << 15, // new
|
|
kErrorFlag_UndefinedAddressRead = 1 << 16, // new
|
|
kErrorFlag_AddressVariableOutRange = 1 << 17, // new
|
|
kErrorFlag_DataVariableOutRange = 1 << 18, // new
|
|
kErrorFlag_OutOfCPURegion = 1 << 19,
|
|
kErrorFlag_InvalidCPURegion = 1 << 20,
|
|
kErrorFlag_InvalidAddressSpace = 1 << 21, // new
|
|
kErrorFlag_RegionOutOfRange = 1 << 22,
|
|
kErrorFlag_InvalidCustomCode = 1 << 23, // new
|
|
|
|
kErrorFlag_Max = 24 };
|
|
|
|
/***************************************************************************
|
|
TYPE DEFINITIONS
|
|
***************************************************************************/
|
|
|
|
/********** ACTION **********/
|
|
|
|
typedef struct _cheat_action cheat_action;
|
|
struct _cheat_action
|
|
{
|
|
char *optional_name; /* label for label selection or popup */
|
|
|
|
UINT32 type; /* packed several information (cpu/region, address size, operation and parameters and so on) */
|
|
UINT32 region; /* the number of cpu or region. in case of cpu, it has a kind of an address space together */
|
|
UINT32 address; /* address. it is changeable by RWrite in the cheat core */
|
|
UINT32 original_address; /* address. it is for edit/view/save */
|
|
UINT32 data; /* data. it is changeable by valuse selector in the cheat core */
|
|
UINT32 original_data; /* data. it is for edit/view/save */
|
|
UINT32 extend_data; /* extend parameter. it is different using by each operations */
|
|
|
|
UINT32 flags; /* internal flags */
|
|
|
|
INT8 frame_timer; /* internal timer */
|
|
UINT32 *last_value; /* back up value before cheating to restore value. PDWWrite uses 2 and RWrite uses about a counter */
|
|
|
|
UINT8 **cached_pointer; /* pointer to specified address space or mapped memory */
|
|
UINT32 cached_offset; /* offset for mapped memory */
|
|
|
|
};
|
|
|
|
/********** ENTRY **********/
|
|
|
|
typedef struct _cheat_entry cheat_entry;
|
|
struct _cheat_entry
|
|
{
|
|
char *name; /* entry name */
|
|
char *comment; /* simple comment */
|
|
|
|
UINT32 flags; /* internal flags */
|
|
|
|
INT32 action_list_length; /* total codes of cheat action. NOTE : minimum length is 1 and 0 is ERROR */
|
|
cheat_action *action_list; /* pointer to cheat action */
|
|
|
|
int activation_key; /* main activation key index (or previous select key in label-select) */
|
|
int activation_sub_key; /* sub activation key index for next select key in label-select) */
|
|
|
|
int selection; /* for label-select to set selected label number (OLD) */
|
|
int label_index_length; /* total tables of index table. NOTE : minimum length is 1 and 0 is ERROR (new) */
|
|
int *label_index; /* pointer of label index table (new) */
|
|
|
|
int layer_index; /* layer index for enable/disable menu */
|
|
};
|
|
|
|
/********** WATCH **********/
|
|
|
|
typedef struct _watch_info watch_info;
|
|
struct _watch_info
|
|
{
|
|
UINT32 address; /* address */
|
|
UINT8 cpu; /* target cpu or region */
|
|
UINT8 num_elements; /* length of this watchpoint */
|
|
UINT8 element_bytes; /* address size of this watchpoint */
|
|
UINT8 label_type; /* header label */
|
|
UINT8 display_type; /* type of value display */
|
|
UINT8 skip; /* address skip */
|
|
UINT8 elements_per_line; /* max watchpoints in the same line */
|
|
INT8 add_value; /* add value */
|
|
INT8 address_shift; /* address shift */
|
|
INT8 data_shift; /* data shift */
|
|
UINT32 xor; /* xor */
|
|
|
|
float x, y; /* position */
|
|
|
|
cheat_entry *linked_cheat; /* relative cheat_entry */
|
|
|
|
char label[256]; /* name of label */
|
|
};
|
|
|
|
/********** REGION **********/
|
|
|
|
typedef struct _search_region search_region;
|
|
struct _search_region
|
|
{
|
|
UINT32 address; /* address */
|
|
UINT32 length; /* total length */
|
|
|
|
INT8 target_type; /* flag for cpu or region */
|
|
INT8 target_idx; /* target cpu/region */
|
|
|
|
UINT8 flags; /* internal flags */
|
|
|
|
UINT8 **cached_pointer; /* pointer to read from memory */
|
|
const address_map_entry
|
|
*write_handler; /* pointer of write handler in address map */
|
|
|
|
UINT8 *first; /* first value in searching */
|
|
UINT8 *last; /* current value in searching */
|
|
|
|
UINT8 *status;
|
|
|
|
UINT8 *backup_last; /* previous value in searching */
|
|
UINT8 *backup_status; /* flag of backup */
|
|
|
|
char name[64]; /* name of this region */
|
|
|
|
UINT32 num_results; /* total results */
|
|
UINT32 old_num_results; /* previous total results */
|
|
};
|
|
|
|
/********** SEARCH **********/
|
|
typedef struct _search_info search_info;
|
|
struct _search_info
|
|
{
|
|
INT32 region_list_length;
|
|
search_region *region_list;
|
|
|
|
char *name; /* advanced. search info name used in select_region() */
|
|
|
|
INT8 bytes; /* 0 = 1, 1 = 2, 2 = 3, 3 = 4, 4 = bit */
|
|
INT8 swap; /* advanced */
|
|
INT8 sign; /* advanced */
|
|
INT8 lhs;
|
|
INT8 rhs;
|
|
INT8 comparison;
|
|
INT8 parameter; /* minimum and standard */
|
|
|
|
INT8 target_type; /* is cpu or region? */
|
|
INT8 target_idx; /* index for cpu or region */
|
|
|
|
UINT32 value; /* advanced and standard */
|
|
|
|
INT8 search_speed;
|
|
|
|
UINT32 num_results;
|
|
UINT32 old_num_results;
|
|
|
|
INT32 current_region_idx;
|
|
INT32 current_results_page;
|
|
|
|
UINT8 backup_valid;
|
|
};
|
|
|
|
/********** CPU **********/
|
|
|
|
typedef struct _cpu_region_info cpu_region_info;
|
|
struct _cpu_region_info
|
|
{
|
|
UINT8 type; /* cpu or region type */
|
|
UINT8 data_bits; /* data bits */
|
|
UINT8 address_bits; /* address bits */
|
|
UINT8 address_chars_needed; /* length of address */
|
|
UINT32 address_mask; /* address mask */
|
|
UINT8 endianness; /* endianness */
|
|
UINT8 address_shift; /* address shift */
|
|
};
|
|
|
|
/********** STRINGS **********/
|
|
|
|
typedef struct _menu_string_list menu_string_list;
|
|
struct _menu_string_list
|
|
{
|
|
const char **main_list; /* main item field in menu items */
|
|
const char **sub_list; /* sub item field in menu items */
|
|
char *flag_list; /* flag of highlight for sub menu field */
|
|
|
|
char **main_strings; /* strings buffer 1 */
|
|
char **sub_strings; /* strings buffer 2 */
|
|
|
|
char *buf; /* internal buffer? (only used in rebuild_string_tables()) */
|
|
|
|
UINT32 length; /* number of total menu items */
|
|
UINT32 num_strings; /* number of strings buffer */
|
|
UINT32 main_string_length; /* length of string in strings buffer 1 */
|
|
UINT32 sub_string_length; /* length of string in strings buffer 2 */
|
|
};
|
|
|
|
/********** MENUS **********/
|
|
|
|
typedef struct _cheat_menu_item_info cheat_menu_item_info;
|
|
struct _cheat_menu_item_info
|
|
{
|
|
UINT32 sub_cheat; /* index of an item */
|
|
UINT32 field_type; /* type of an item */
|
|
UINT32 extra_data; /* it stores an extra data but NOT read (so I don't know how to use)*/
|
|
};
|
|
|
|
typedef struct _cheat_menu_stack cheat_menu_stack;
|
|
typedef int (*cheat_menu_handler)(running_machine *machine, cheat_menu_stack *menu);
|
|
struct _cheat_menu_stack
|
|
{
|
|
cheat_menu_handler handler; /* menu handler for cheat */
|
|
cheat_menu_handler return_handler; /* menu handler to return */
|
|
int sel; /* current cursor position */
|
|
int pre_sel; /* selected item in previous menu */
|
|
UINT8 first_time; /* flags to first setting (1 = first, 0 = not first) */
|
|
};
|
|
|
|
/********** FORMAT **********/
|
|
typedef const struct _cheat_format cheat_format;
|
|
struct _cheat_format
|
|
{
|
|
const char *format_string; /* string templete of a format */
|
|
UINT8 arguments_matched; /* valid arguments of a format */
|
|
UINT8 type_matched; /* valid length of a type field */
|
|
UINT8 data_matched; /* valid length of a data/extend data field */
|
|
UINT8 comment_matched; /* valid arguments to add comment */
|
|
};
|
|
|
|
typedef struct _cheat_format_strings cheat_format_strings;
|
|
struct _cheat_format_strings
|
|
{
|
|
char name[255];
|
|
char type[255];
|
|
char data[255];
|
|
char extend_data[255];
|
|
char description[255];
|
|
char comment[255];
|
|
};
|
|
|
|
/***************************************************************************
|
|
GLOBAL VARIABLES
|
|
***************************************************************************/
|
|
|
|
static const char *cheat_file;
|
|
|
|
static emu_timer *periodic_timer;
|
|
|
|
static cheat_entry *cheat_list;
|
|
static INT32 cheat_list_length;
|
|
|
|
static watch_info *watch_list;
|
|
static INT32 watch_list_length;
|
|
|
|
static search_info *search_list;
|
|
static INT32 search_list_length;
|
|
static INT32 current_search_idx;
|
|
|
|
static cpu_region_info cpu_info_list[MAX_CPU];
|
|
static cpu_region_info region_info_list[REGION_LIST_LENGTH];
|
|
|
|
static int found_database;
|
|
static int cheats_disabled;
|
|
static int watches_disabled;
|
|
|
|
static int full_menu_page_height;
|
|
static int visible_items;
|
|
|
|
static char main_database_name[CHEAT_FILENAME_MAX_LEN + 1];
|
|
|
|
static menu_string_list menu_strings;
|
|
|
|
static cheat_menu_item_info *menu_item_info;
|
|
static INT32 menu_item_info_length;
|
|
|
|
static UINT8 edit_active;
|
|
static INT8 edit_cursor;
|
|
|
|
static INT8 stack_index;
|
|
static cheat_menu_stack menu_stack[CHEAT_MENU_DEPTH];
|
|
|
|
static cheat_format_strings *format_strings;
|
|
|
|
static int cheat_variable[VARIABLE_MAX_ARRAY] = { 0 };
|
|
|
|
static UINT32 cheat_options;
|
|
static UINT32 driverSpecifiedFlag;
|
|
static UINT8 vertical_key_repeat_speed;
|
|
static UINT8 horizontal_key_repeat_speed;
|
|
static UINT8 message_type;
|
|
static UINT8 message_timer;
|
|
|
|
static cpu_region_info raw_cpu_info =
|
|
{
|
|
0, /* type */
|
|
8, /* data_bits */
|
|
8, /* address_bits */
|
|
1, /* address_chars_needed */
|
|
CPU_IS_BE, /* endianness */
|
|
0, /* address_shift */
|
|
};
|
|
|
|
static const int BYTE_DIGITS_TABLE[] =
|
|
{
|
|
2, /* 8-bit (1 byte) */
|
|
4, /* 16-bit (2 bytes) */
|
|
6, /* 24-bit (3 bytes) */
|
|
8, /* 32-bit (4 bytes) */
|
|
1 /* 1-bit <SEARCH MODE ONLY> */
|
|
};
|
|
|
|
static const int BYTE_DEC_DIGITS_TABLE[] =
|
|
{
|
|
3, /* 8-bit (1 byte) */
|
|
5, /* 16-bit (2 bytes) */
|
|
8, /* 24-bit (3 bytes) */
|
|
10, /* 32-bit (4 bytes) */
|
|
1, /* 1-bit */
|
|
};
|
|
|
|
static const int BYTE_INCREMENT_TABLE[] =
|
|
{
|
|
1, /* 8-bit (1 byte) */
|
|
2, /* 16-bit (2 bytes) */
|
|
3, /* 24-bit (3 bytes) */
|
|
4, /* 32-bit (4 bytes) */
|
|
1 /* 1-bit <SEARCH MODE ONLY> */
|
|
};
|
|
|
|
static const int SEARCH_BYTE_STEP[] =
|
|
{
|
|
1, /* 8-bit (1 byte) */
|
|
2, /* 16-bit (2 bytes) */
|
|
1, /* 24-bit (3 bytes) */
|
|
4, /* 32-bit (4 bytes) */
|
|
1 /* 1-bit */
|
|
};
|
|
|
|
static const UINT32 BYTE_LOOP_TABLE[] =
|
|
{
|
|
1, /* 8-bit (1 byte) */
|
|
3, /* 16-bit (2 bytes) */
|
|
5, /* 24-bit (3 bytes) */
|
|
7, /* 32-bit (4 bytes) */
|
|
1 /* 1-bit <SEARCH MODE ONLY> */
|
|
};
|
|
|
|
static const UINT32 BYTE_MASK_TABLE[] =
|
|
{
|
|
0x000000FF, /* 8-bit (1 byte) */
|
|
0x0000FFFF, /* 16-bit (2 bytes) */
|
|
0x00FFFFFF, /* 24-bit (3 bytes) */
|
|
0xFFFFFFFF, /* 32-bit (4 bytes) */
|
|
0x00000001 /* 1-bit <SEARCH MODE ONLY> */
|
|
};
|
|
|
|
static const UINT32 SEARCH_BYTE_SIGN_BIT_TABLE[] =
|
|
{
|
|
0x00000080, /* 8-bit (1 byte) */
|
|
0x00008000, /* 16-bit (2 bytes) */
|
|
0x00800000, /* 24-bit (3 bytes) */
|
|
0x80000000, /* 32-bit (4 bytes) */
|
|
0x00000001 /* 1-bit */
|
|
};
|
|
|
|
static const UINT32 SEARCH_BYTE_UNSIGNED_MASK_TABLE[] =
|
|
{
|
|
0x0000007F, /* 8-bit (1 byte) */
|
|
0x00007FFF, /* 16-bit (2 bytes) */
|
|
0x007FFFFF, /* 24-bit (3 bytes) */
|
|
0x7FFFFFFF, /* 32-bit (4 bytes) */
|
|
0x00000001 /* 1-bit */
|
|
};
|
|
|
|
static const int kByteConversionTable[] =
|
|
{
|
|
kSearchSize_8Bit, kSearchSize_16Bit, kSearchSize_24Bit, kSearchSize_32Bit, kSearchSize_32Bit
|
|
};
|
|
|
|
static const int kWatchSizeConversionTable[] =
|
|
{
|
|
kSearchSize_8Bit, kSearchSize_16Bit, kSearchSize_24Bit, kSearchSize_32Bit, kSearchSize_8Bit
|
|
};
|
|
|
|
static const int kSearchOperandNeedsInit[] =
|
|
{
|
|
0, 1, 1, 0
|
|
};
|
|
|
|
static const UINT32 kPrefillValueTable[] =
|
|
{
|
|
0x00, 0xFF, 0x00, 0x01
|
|
};
|
|
|
|
static const UINT32 kIncrementValueTable[] =
|
|
{
|
|
0x00000001, 0x00000010, 0x00000100, 0x00001000, 0x00010000, 0x00100000, 0x01000000, 0x10000000
|
|
};
|
|
|
|
static const UINT32 kIncrementMaskTable[] =
|
|
{
|
|
0x0000000F, 0x000000F0, 0x00000F00, 0x0000F000, 0x000F0000, 0x00F00000, 0x0F000000, 0xF0000000
|
|
};
|
|
|
|
static const UINT32 kIncrementDecTable[] =
|
|
{
|
|
0x00000009, 0x00000090, 0x00000900, 0x00009000, 0x00090000, 0x00900000, 0x09000000, 0x90000000
|
|
};
|
|
|
|
static const char *const kRegionNames[] = {
|
|
"INVALID",
|
|
"CPU1", "CPU2", "CPU3", "CPU4", "CPU5", "CPU6", "CPU7", "CPU8", /* 01-08 [01-08] : CPU */
|
|
"GFX1", "GFX2", "GFX3", "GFX4", "GFX5", "GFX6", "GFX7", "GFX8", /* 09-16 [08-10] : GFX */
|
|
"PROMS", /* 17 [11] : PROMS */
|
|
"SOUND1", "SOUND2", "SOUND3", "SOUND4", "SOUND5", "SOUND6", "SOUND7", "SOUND8", /* 18-25 [12-19] : SOUND */
|
|
"USER1", "USER2", "USER3", "USER4", "USER5", "USER6", "USER7", "USER8", /* 26-45 [1A-2D] : USER */
|
|
/* USER9 - PLDS are undefined in old format */
|
|
"USER9", "USER10", "USER11", "USER12", "USER13", "USER14", "USER15", "USER16",
|
|
"USER17", "USER18", "USER19", "USER20",
|
|
"DISKS", /* 46 [2E] : DISKS */
|
|
"PLDS" }; /* 47 [2F] : PLDS */
|
|
|
|
static const char *const kNumbersTable[] = {
|
|
"0", "1", "2", "3", "4", "5", "6", "7",
|
|
"8", "9", "10", "11", "12", "13", "14", "15",
|
|
"16", "17", "18", "19", "20", "21", "22", "23",
|
|
"24", "25", "26", "27", "28", "29", "30", "31" };
|
|
|
|
static const char *const kByteSizeStringList[] =
|
|
{
|
|
"8 Bit", "16 Bit", "24 Bit", "32 Bit"
|
|
};
|
|
|
|
static const char *const BIT_SET_CLEAR_NAMES[] =
|
|
{
|
|
"Bit Set", "Bit Clear"
|
|
};
|
|
|
|
static const char *const kWatchLabelStringList[] =
|
|
{
|
|
"None",
|
|
"Address",
|
|
"String"
|
|
};
|
|
|
|
static const char *const kWatchDisplayTypeStringList[] =
|
|
{
|
|
"Hex",
|
|
"Decimal",
|
|
"Binary",
|
|
"ASCII"
|
|
};
|
|
|
|
static const char *const CHEAT_MESSAGE_TABLE[] =
|
|
{
|
|
"INVALID MESSAGE!", /* this message should be unused */
|
|
"cheat option reloaded", /* RELOAD_CHEAT_OPTION */
|
|
"cheat code reloaded", /* RELOAD_CHEAT_CODE */
|
|
"user defined search region reloaded", /* RELOAD_USER_REGION */
|
|
"reset cheat options as default", /* RESET_OPTIONS */
|
|
"failed to load database!", /* FAILED_TO_LOAD_DATABASE */
|
|
"cheats found", /* CHEAT_FOUND */
|
|
"1 result found, added to list", /* ONE_CHEAT_FOUND */
|
|
"succeeded to save", /* SUCCEEDED_TO_SAVE */
|
|
"failed to save!", /* FAILED_TO_SAVE */
|
|
"unsupported old/older format!", /* NO_SUPPORTED_OLD_FORMAT */
|
|
"cheats saved", /* ALL_CHEATS_SAVED */
|
|
"activation key saved", /* ACTIVATION_KEY_SAVED */
|
|
"no activation key!", /* NO_ACTIVATION_KEY */
|
|
"pre-enable saved", /* PRE_ENABLE_SAVED */
|
|
"succeeded to add", /* SUCCEEDED_TO_ADD */
|
|
"failed to add!", /* FAILED_TO_ADD */
|
|
"succeeded to delete", /* SUCCEEDED_TO_DELETE */
|
|
"failed to delete!", /* FAILED_TO_DELETE */
|
|
"no search region!", /* NO_SEARCH_REGION */
|
|
"values restored", /* RESTORE_VALUE */
|
|
"there are no old values!", /* NO_OLD_VALUE */
|
|
"saved all memory regions", /* INITIALIZE_MEMOY */
|
|
"region invalidated remains results are", /* INVALIDATE_REGION */
|
|
"failed to allocate memory!", /* FAILED_TO_ALLOCATE */
|
|
"found wrong code!" /* WRONG_CODE */
|
|
};
|
|
|
|
static const struct _cheat_format cheat_format_table[] =
|
|
{
|
|
/* option - :_command:TYPE */
|
|
{ ":_command:%[^:\n\r]", 1, 8, 0, 0 },
|
|
#ifdef MESS
|
|
/* code (new) - :MACHINE_NAME::CRC::TYPE::ADDRESS::DATA::EXTEND_DATA:(DESCRIPTION:COMMENT) */
|
|
{ ":%8[^:\n\r]::%8X::%10[^:\n\r]::%X::%8[^:\n\r]::%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 6, 10, 8, 8 },
|
|
/* code (old) - :MACHINE_NAME:CRC:TYPE:ADDRESS:DATA:EXTEND_DATA:(DESCRIPTION:COMMENT) */
|
|
{ ":%8[^:\n\r]:8X:%8[^:\n\r]:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 6, 8, 8, 0 },
|
|
/* code (older) - :MACHINE_NAME:CRC:CPU:ADDRESS:DATA:TYPE:(DESCRIPTION:COMMENT) */
|
|
{ "%8[^:\n\r]:%8X:%d:%X:%X:%d:%[^:\n\r]:%[^:\n\r]", 5, 0, 0, 8 },
|
|
/* user region - :MACHINE_NAME:CRC:CPU:ADDRESS_SPACE:START_ADDRESS:END_ADDRESS:STATUS:(DESCRIPTION) */
|
|
{ ":%8[^:\n\r]:%8X:%2X:%2X:%X:%X:%1X:%[^:\n\r]", 7, 0, 0, 0 },
|
|
#else
|
|
/* code (new) - :GAME_NAME::TYPE::ADDRESS::DATA::EXTEND_DATA:(DESCRIPTION:COMMENT) */
|
|
{ ":%8[^:\n\r]::%10[^:\n\r]::%X::%8[^:\n\r]::%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 5, 10, 8, 7 },
|
|
/* code (old) - :GAME_NAME:TYPE:ADDRESS:DATA:EXTEND_DATA:(DESCRIPTION:COMMENT) */
|
|
{ ":%8[^:\n\r]:%8[^:\n\r]:%X:%8[^:\n\r]:%8[^:\n\r]:%[^:\n\r]:%[^:\n\r]", 5, 8, 8, 0 },
|
|
/* code (older) - :GAME_NAME:CPU:ADDRESS:DATA:TYPE:(DESCRIPTION:COMMENT) */
|
|
{ "%8[^:\n\r]:%d:%X:%X:%d:%[^:\n\r]:%[^:\n\r]", 4, 0, 0, 7 },
|
|
/* user region - :GAME_NAME:CPU:ADDRESS_SPACE:START_ADDRESS:END_ADDRESS:STATUS:(DESCRIPTION) */
|
|
{ ":%8[^:\n\r]:%2X:%2X:%X:%X:%1X:%[^:\n\r]", 6, 0, 0, 0 },
|
|
#endif /* MESS */
|
|
/* end of table */
|
|
{ 0 }
|
|
};
|
|
|
|
/***************************************************************************
|
|
FUNCTION PROTOTYPES
|
|
***************************************************************************/
|
|
|
|
static TIMER_CALLBACK( cheat_periodic );
|
|
static void cheat_exit(running_machine *machine);
|
|
|
|
/********** SPECIAL KEY HANDLING **********/
|
|
static int shift_key_pressed(void);
|
|
static int control_key_pressed(void);
|
|
static int alt_key_pressed(void);
|
|
|
|
static int ui_pressed_repeat_throttle(running_machine *machine, int code, int base_speed);
|
|
|
|
/********** KEY INPUT **********/
|
|
static int read_hex_input(void);
|
|
|
|
static char *do_dynamic_edit_text_field(char *buf);
|
|
static void do_static_edit_text_field(char *buf, int size);
|
|
|
|
static UINT32 do_edit_hex_field(running_machine *machine, UINT32 data);
|
|
static UINT32 do_edit_hex_field_signed(UINT32 data, UINT32 mask);
|
|
static INT32 do_edit_dec_field(INT32 data, INT32 min, INT32 max);
|
|
|
|
static UINT32 do_increment_hex_field(UINT32 data, UINT8 digits);
|
|
static UINT32 do_decrement_hex_field(UINT32 data, UINT8 digits);
|
|
static UINT32 do_increment_hex_field_signed(UINT32 data, UINT8 digits, UINT8 bytes);
|
|
static UINT32 do_decrement_hex_field_signed(UINT32 data, UINT8 digits, UINT8 bytes);
|
|
static UINT32 do_increment_dec_field(UINT32 data, UINT8 digits);
|
|
static UINT32 do_decrement_dec_field(UINT32 data, UINT8 digits);
|
|
|
|
/********** VALUE CONVERTER **********/
|
|
static UINT32 bcd_to_decimal(UINT32 value);
|
|
static UINT32 decimal_to_bcd(UINT32 value);
|
|
|
|
/********** STRINGS **********/
|
|
static void rebuild_string_tables(void);
|
|
static void request_strings(UINT32 length, UINT32 num_strings, UINT32 main_string_length, UINT32 sub_string_length);
|
|
static void init_string_table(void);
|
|
static void free_string_table(void);
|
|
|
|
static char *create_string_copy(char *buf);
|
|
static char *create_strings_with_edit_cursor(char *buf, int data, int total_digits, INT8 current_cursor);
|
|
|
|
/********** MENU **********/
|
|
static void old_style_menu(const char **items, const char **sub_items, char *flag, int selected, int arrowize_subitem);
|
|
static void resize_menu_item_info(UINT32 new_length);
|
|
|
|
/********** MENU STACK **********/
|
|
static void init_cheat_menu_stack(void);
|
|
static void cheat_menu_stack_push(cheat_menu_handler new_handler, cheat_menu_handler ret_handler, int selection);
|
|
static void cheat_menu_stack_pop(void);
|
|
static void free_cheat_menu_stack(void);
|
|
|
|
/********** ADDITIONAL MENU FOR CHEAT **********/
|
|
static int user_select_value_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int user_select_label_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int comment_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int extend_comment_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
|
|
/********** CHEAT MENU **********/
|
|
static int cheat_main_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int enable_disable_cheat_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int add_edit_cheat_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int command_add_edit_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int edit_cheat_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int view_cheat_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int analyse_cheat_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
|
|
static int search_main_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int select_search_region_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int view_search_result_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
|
|
static int choose_watch_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int command_watch_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int edit_watch_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
|
|
static int select_option_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int select_search_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
|
|
static int command_cheat_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
|
|
#ifdef MAME_DEBUG
|
|
static int check_activation_key_code_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int view_cpu_region_info_list_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
static int debug_cheat_menu(running_machine *machine, cheat_menu_stack *menu);
|
|
#endif
|
|
|
|
/********** PRINTER **********/
|
|
static UINT32 print_binary(char *buf, UINT32 data, UINT32 mask);
|
|
static UINT32 print_ascii(char *buf, UINT32 data, UINT8 size);
|
|
|
|
/********** ENTRY LIST **********/
|
|
static void resize_cheat_list(UINT32 new_length, UINT8 dispose);
|
|
|
|
static void add_cheat_before(UINT32 idx);
|
|
static void delete_cheat_at(UINT32 idx);
|
|
|
|
static void dispose_cheat(cheat_entry *entry);
|
|
static cheat_entry
|
|
*get_new_cheat(void);
|
|
|
|
/********** ACTION LIST **********/
|
|
static void resize_cheat_action_list(cheat_entry *entry, UINT32 new_length, UINT8 dispose);
|
|
|
|
static void add_action_before(cheat_entry *entry, UINT32 idx);
|
|
static void delete_action_at(cheat_entry *entry, UINT32 idx);
|
|
|
|
static void dispose_action(cheat_action *action);
|
|
|
|
/********** WATCH LIST **********/
|
|
static void init_watch(watch_info *info, UINT32 idx);
|
|
|
|
static void resize_watch_list(UINT32 new_length, UINT8 dispose);
|
|
|
|
static void add_watch_before(UINT32 idx);
|
|
static void delete_watch_at(UINT32 idx);
|
|
|
|
static void dispose_watch(watch_info *watch);
|
|
|
|
static watch_info
|
|
*get_unused_watch(void);
|
|
|
|
static void add_cheat_from_watch(running_machine *machine, watch_info *watch);
|
|
static void add_cheat_from_watch_as_watch(running_machine *machine, cheat_entry *entry, watch_info *watch);
|
|
|
|
static void reset_watch(watch_info *watch);
|
|
|
|
/********** SEARCH LIST **********/
|
|
static void resize_search_list(UINT32 new_length, UINT8 dispose);
|
|
|
|
static void add_search_before(UINT32 idx);
|
|
static void delete_search_at(UINT32 idx);
|
|
|
|
static void init_search(search_info *info);
|
|
static void init_search_box(search_info *info, UINT8 mode);
|
|
|
|
static void dispose_search_reigons(search_info *info);
|
|
static void dispose_search(search_info *info);
|
|
static search_info
|
|
*get_current_search(void);
|
|
|
|
static void fill_buffer_from_region(search_region *region, UINT8 *buf);
|
|
static UINT32 read_region_data(search_region *region, UINT32 offset, UINT8 size, UINT8 swap);
|
|
|
|
static void backup_search(search_info *info);
|
|
static void restore_search_backup(search_info *info);
|
|
static void backup_region(search_region *region);
|
|
static void restore_region_backup(search_region *region);
|
|
static UINT8 default_enable_region(running_machine *machine, search_region *region, search_info *info);
|
|
static void set_search_region_default_name(search_region *region);
|
|
static UINT8 is_search_region_in_range(UINT8 cpu, UINT32 length);
|
|
static void allocate_search_regions(search_info *info);
|
|
static void build_search_regions(running_machine *machine, search_info *info);
|
|
|
|
/********** LOADER **********/
|
|
static int handle_local_command_tag(char *tag);
|
|
static void handle_local_command_cheat(running_machine *machine, int cpu, int type, int address, int data, int extend_data, char *tag);
|
|
|
|
static UINT8 open_cheat_database(mame_file **the_file, char *file_name, UINT8 flag);
|
|
|
|
static void load_cheat_options(char *file_name);
|
|
static void load_cheat_code_new(running_machine *machine, char *file_name);
|
|
static void load_cheat_code_standard(running_machine *machine, char *file_name);
|
|
static void load_cheat_code_old(running_machine *machine, char *file_name);
|
|
static void load_user_defined_search_region(running_machine *machine, char *file_name);
|
|
static void load_cheat_database(running_machine *machine, UINT8 load_code);
|
|
static void reload_cheat_database(running_machine *machine);
|
|
|
|
static void dispose_cheat_database(running_machine *machine);
|
|
|
|
/********** SAVER **********/
|
|
static void save_cheat_code(running_machine *machine, cheat_entry *entry);
|
|
static void save_activation_key(running_machine *machine, cheat_entry *entry, int entryIndex);
|
|
static void save_pre_enable(running_machine *machine, cheat_entry *entry, int entry_index);
|
|
static void save_cheat_options(void);
|
|
static void save_description(running_machine *machine);
|
|
static void save_raw_code(running_machine *machine);
|
|
static void do_auto_save_cheats(running_machine *machine);
|
|
|
|
/********** CODE ADDITION **********/
|
|
static void add_cheat_from_result(running_machine *machine, search_info *search, search_region *region, UINT32 address);
|
|
static void add_cheat_from_first_result(running_machine *machine, search_info *search);
|
|
static void add_watch_from_result(search_info *search, search_region *region, UINT32 address);
|
|
|
|
/********** SEARCH **********/
|
|
static UINT32 search_sign_extend(search_info *search, UINT32 value);
|
|
static UINT32 read_search_operand(UINT8 type, search_info *search, search_region *region, UINT32 address);
|
|
static UINT32 read_search_operand_bit(UINT8 type, search_info *search, search_region *region, UINT32 address);
|
|
static UINT8 do_search_comparison(search_info *search, UINT32 lhs, UINT32 rhs);
|
|
static UINT32 do_search_comparison_bit(search_info *search, UINT32 lhs, UINT32 rhs);
|
|
#if 0
|
|
static UINT8 is_region_offset_valid(search_info *search, search_region *region, UINT32 offset);
|
|
#else
|
|
#define is_region_offset_valid is_region_offset_valid_bit /* ????? */
|
|
#endif
|
|
static UINT8 is_region_offset_valid_bit(search_info *search, search_region *region, UINT32 offset);
|
|
static void invalidate_region_offset(search_info *search, search_region *region, UINT32 offset);
|
|
static void invalidate_region_offset_bit(search_info *search, search_region *region, UINT32 offset, UINT32 invalidate);
|
|
static void invalidate_entire_region(search_info *search, search_region *region);
|
|
|
|
static void init_new_search(search_info *search);
|
|
static void update_search(search_info *search);
|
|
|
|
static void do_search(search_info *search);
|
|
|
|
/********** MEMORY ACCESSOR **********/
|
|
static UINT8 **look_up_handler_memory(UINT8 cpu, UINT32 address, UINT32 *out_relative_address);
|
|
static UINT8 **get_memory_region_base_pointer(UINT8 cpu, UINT8 space, UINT32 address);
|
|
|
|
static UINT32 do_cpu_read(UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap);
|
|
static UINT32 do_memory_read(UINT8 *buf, UINT32 address, UINT8 bytes, UINT8 swap, cpu_region_info *info);
|
|
static void do_cpu_write(UINT32 data, UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap);
|
|
static void do_memory_write(UINT32 data, UINT8 *buf, UINT32 address, UINT8 bytes, UINT8 swap, cpu_region_info *info);
|
|
|
|
static UINT32 read_data(running_machine *machine, cheat_action *action);
|
|
static void write_data(running_machine *machine, cheat_action *action, UINT32 data);
|
|
static UINT32 read_or_write_data(running_machine *machine, cheat_action *action, UINT32 data, int read_or_write);
|
|
|
|
/********** WATCH **********/
|
|
static void watch_cheat_entry(cheat_entry *entry, UINT8 associate);
|
|
static void add_action_watch(cheat_action *action, cheat_entry *entry);
|
|
static void remove_associated_watches(cheat_entry *entry);
|
|
|
|
/********** ACTIVE/DEACTIVE ENTRY **********/
|
|
static void reset_action(running_machine *machine, cheat_action *action);
|
|
static void activate_cheat(running_machine *machine, cheat_entry *entry);
|
|
static void restore_last_value(running_machine *machine, cheat_action *action);
|
|
static void deactivate_cheat(running_machine *machine, cheat_entry *entry);
|
|
static void temp_deactivate_cheat(running_machine *machine, cheat_entry *entry);
|
|
|
|
/********** OPERATION CORE **********/
|
|
static void cheat_periodic_operation(running_machine *machine, cheat_action *action);
|
|
static UINT8 cheat_periodic_condition(running_machine *machine, cheat_action *action);
|
|
static int cheat_periodic_action(running_machine *machine, cheat_action *action, int selection);
|
|
static void cheat_periodic_entry(running_machine *machine, cheat_entry *entry);
|
|
static void cheat_periodic_old_entry(running_machine *machine, cheat_entry *entry);
|
|
|
|
/********** LABEL UTILITY **********/
|
|
static void choose_label_index(running_machine *machine, cheat_entry *entry, int next_or_previous);
|
|
static void build_label_index_table(cheat_entry *entry);
|
|
|
|
/********** CONFIGURE ENTRY **********/
|
|
static void update_all_cheat_info(running_machine *machine);
|
|
static void update_cheat_info(running_machine *machine, cheat_entry *entry, UINT8 is_load_time);
|
|
static UINT32 analyse_code_format(running_machine *machine, cheat_entry *entry, cheat_action *action);
|
|
static void check_code_format(running_machine *machine, cheat_entry *entry);
|
|
static void set_layer_index(void);
|
|
|
|
/********** OTHER STUFF **********/
|
|
static void reset_cheat_options(void);
|
|
static void display_cheat_message(void);
|
|
static UINT8 get_address_length(UINT8 region);
|
|
static char *get_region_name(UINT8 region);
|
|
static void build_cpu_region_info_list(running_machine *machine);
|
|
|
|
/***************************************************************************
|
|
INLINE FUNCTIONS
|
|
***************************************************************************/
|
|
|
|
/*---------------
|
|
get_cpu_info
|
|
---------------*/
|
|
|
|
INLINE cpu_region_info *get_cpu_info(UINT8 cpu)
|
|
{
|
|
if(VALID_CPU(EXTRACT_FIELD(cpu, CPUIndex)))
|
|
return &cpu_info_list[cpu];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*------------------
|
|
get_region_info
|
|
------------------*/
|
|
|
|
INLINE cpu_region_info *get_region_info(UINT8 region)
|
|
{
|
|
if(region >= REGION_CPU1 && region < REGION_MAX)
|
|
return ®ion_info_list[region - REGION_INVALID];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*-------------------------
|
|
get_cpu_or_region_info
|
|
-------------------------*/
|
|
|
|
INLINE cpu_region_info *get_cpu_or_region_info(UINT8 cpu_region)
|
|
{
|
|
if(cpu_region < REGION_INVALID)
|
|
return get_cpu_info(cpu_region);
|
|
else
|
|
return get_region_info(cpu_region);
|
|
}
|
|
|
|
/*-----------------
|
|
cpu_needs_swap
|
|
-----------------*/
|
|
|
|
INLINE UINT8 cpu_needs_swap(UINT8 cpu)
|
|
{
|
|
return cpu_info_list[cpu].endianness ^ 1;
|
|
}
|
|
|
|
/*--------------------
|
|
region_needs_swap
|
|
--------------------*/
|
|
|
|
INLINE UINT8 region_needs_swap(UINT8 region)
|
|
{
|
|
cpu_region_info *temp = get_region_info(region);
|
|
|
|
if(temp)
|
|
return temp->endianness ^ 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*---------------
|
|
swap_address
|
|
---------------*/
|
|
|
|
INLINE UINT32 swap_address(UINT32 address, UINT8 dataSize, cpu_region_info *info)
|
|
{
|
|
switch(info->data_bits)
|
|
{
|
|
case 16:
|
|
if(info->endianness == CPU_IS_BE)
|
|
return BYTE_XOR_BE(address);
|
|
else
|
|
return BYTE_XOR_LE(address);
|
|
|
|
case 32:
|
|
if(info->endianness == CPU_IS_BE)
|
|
return BYTE4_XOR_BE(address);
|
|
else
|
|
return BYTE4_XOR_LE(address);
|
|
}
|
|
|
|
return address;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------------
|
|
is_address_in_range - check the range of address for eeprom and non-cpu region
|
|
---------------------------------------------------------------------------------*/
|
|
|
|
INLINE int is_address_in_range(cheat_action *action, UINT32 length)
|
|
{
|
|
return ((action->address + EXTRACT_FIELD(action->type, AddressSize) + 1) <= length);
|
|
}
|
|
|
|
/*-----------
|
|
do_shift
|
|
-----------*/
|
|
|
|
INLINE UINT32 do_shift(UINT32 input, INT8 shift)
|
|
{
|
|
if(shift > 0) return input >> shift;
|
|
else return input << -shift;
|
|
}
|
|
|
|
/***************************************************************************
|
|
KEY HANDLER
|
|
***************************************************************************/
|
|
|
|
/*--------------------------------------------------------------
|
|
special key handler - check pressing shift, ctrl or alt key
|
|
--------------------------------------------------------------*/
|
|
|
|
static int shift_key_pressed(void)
|
|
{
|
|
return (input_code_pressed(KEYCODE_LSHIFT) || input_code_pressed(KEYCODE_RSHIFT));
|
|
}
|
|
|
|
static int control_key_pressed(void)
|
|
{
|
|
return (input_code_pressed(KEYCODE_LCONTROL) || input_code_pressed(KEYCODE_RCONTROL));
|
|
}
|
|
|
|
static int alt_key_pressed(void)
|
|
{
|
|
return (input_code_pressed(KEYCODE_LALT) || input_code_pressed(KEYCODE_RALT));
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------------------------------------------------
|
|
read_key_async - dirty hack until osd_readkey_unicode is supported in MAMEW re-implementation of osd_readkey_unicode
|
|
-----------------------------------------------------------------------------------------------------------------------*/
|
|
|
|
#if OSD_READKEY_KLUDGE
|
|
|
|
static int read_key_async(int flush)
|
|
{
|
|
int code;
|
|
|
|
if(flush)
|
|
{
|
|
/* check key input */
|
|
while(input_code_poll_keyboard_switches(TRUE) != INPUT_CODE_INVALID) ;
|
|
|
|
return 0;
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
/* check pressed key */
|
|
code = input_code_poll_keyboard_switches(FALSE);
|
|
|
|
if(code == INPUT_CODE_INVALID)
|
|
{
|
|
return 0;
|
|
}
|
|
else if(code >= KEYCODE_A && code <= KEYCODE_Z)
|
|
{
|
|
if(shift_key_pressed()) return 'A' + (code - KEYCODE_A);
|
|
else return 'a' + (code - KEYCODE_A);
|
|
}
|
|
else if(code >= KEYCODE_0 && code <= KEYCODE_9)
|
|
{
|
|
if(shift_key_pressed()) return ")!@#$%^&*("[code - KEYCODE_0];
|
|
else return '0' + (code - KEYCODE_0);
|
|
}
|
|
else if(code >= KEYCODE_0_PAD && code <= KEYCODE_9_PAD)
|
|
{
|
|
return '0' + (code - KEYCODE_0_PAD);
|
|
}
|
|
else if(code == KEYCODE_TILDE)
|
|
{
|
|
if(shift_key_pressed()) return '~';
|
|
else return '`';
|
|
}
|
|
else if(code == KEYCODE_MINUS)
|
|
{
|
|
if(shift_key_pressed()) return '_';
|
|
else return '-';
|
|
}
|
|
else if(code == KEYCODE_EQUALS)
|
|
{
|
|
if(shift_key_pressed()) return '+';
|
|
else return '=';
|
|
}
|
|
else if(code == KEYCODE_BACKSPACE)
|
|
{
|
|
return 0x08;
|
|
}
|
|
else if(code == KEYCODE_OPENBRACE)
|
|
{
|
|
if(shift_key_pressed()) return '{';
|
|
else return '[';
|
|
}
|
|
else if(code == KEYCODE_CLOSEBRACE)
|
|
{
|
|
if(shift_key_pressed()) return '}';
|
|
else return ']';
|
|
}
|
|
else if(code == KEYCODE_COLON)
|
|
{
|
|
if(shift_key_pressed()) return ':';
|
|
else return ';';
|
|
}
|
|
else if(code == KEYCODE_QUOTE)
|
|
{
|
|
if(shift_key_pressed()) return '\"';
|
|
else return '\'';
|
|
}
|
|
else if(code == KEYCODE_BACKSLASH)
|
|
{
|
|
if(shift_key_pressed()) return '|';
|
|
else return '\\';
|
|
}
|
|
else if(code == KEYCODE_COMMA)
|
|
{
|
|
if(shift_key_pressed()) return '<';
|
|
else return ',';
|
|
}
|
|
else if(code == KEYCODE_STOP)
|
|
{
|
|
if(shift_key_pressed()) return '>';
|
|
else return '.';
|
|
}
|
|
else if(code == KEYCODE_SLASH)
|
|
{
|
|
if(shift_key_pressed()) return '?';
|
|
else return '/';
|
|
}
|
|
else if(code == KEYCODE_SLASH_PAD)
|
|
{
|
|
return '/';
|
|
}
|
|
else if(code == KEYCODE_ASTERISK)
|
|
{
|
|
return '*';
|
|
}
|
|
else if(code == KEYCODE_MINUS_PAD)
|
|
{
|
|
return '-';
|
|
}
|
|
else if(code == KEYCODE_PLUS_PAD)
|
|
{
|
|
return '+';
|
|
}
|
|
else if(code == KEYCODE_SPACE)
|
|
{
|
|
return ' ';
|
|
}
|
|
}
|
|
}
|
|
|
|
#define osd_readkey_unicode read_key_async
|
|
|
|
#endif /* OSD_READKEY_KLUDGE */
|
|
|
|
/*---------------------------------------------------
|
|
ui_pressed_repeat_throttle - key repeat handling
|
|
---------------------------------------------------*/
|
|
|
|
static int ui_pressed_repeat_throttle(running_machine *machine, int code, int base_speed)
|
|
{
|
|
int pressed = 0;
|
|
const int delay_ramp_timer = 10;
|
|
static int last_code = -1;
|
|
static int last_speed = -1;
|
|
static int increment_timer = 0;
|
|
|
|
if(input_type_pressed(machine, code, 0))
|
|
{
|
|
if(last_code != code)
|
|
{
|
|
/* pressed different key */
|
|
last_code = code;
|
|
last_speed = base_speed;
|
|
increment_timer = delay_ramp_timer * last_speed;
|
|
}
|
|
else
|
|
{
|
|
/* hold the same key */
|
|
increment_timer--;
|
|
|
|
if(increment_timer <= 0)
|
|
{
|
|
increment_timer = delay_ramp_timer * last_speed;
|
|
|
|
last_speed /= 2;
|
|
|
|
if(last_speed < 1)
|
|
last_speed = 1;
|
|
|
|
pressed = 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(last_code == code)
|
|
last_code = -1;
|
|
}
|
|
|
|
return input_ui_pressed_repeat(machine, code, last_speed);
|
|
}
|
|
|
|
/*-----------------------------------
|
|
read_hex_input - check hex input
|
|
-----------------------------------*/
|
|
|
|
static int read_hex_input(void)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < 10; i++)
|
|
if(input_code_pressed_once(KEYCODE_0 + i)) return i;
|
|
|
|
for(i = 0; i < 10; i++)
|
|
if(input_code_pressed_once(KEYCODE_0_PAD + i)) return i;
|
|
|
|
for(i = 0; i < 6; i++)
|
|
if(input_code_pressed_once(KEYCODE_A + i)) return i + 10;
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------
|
|
do_dynamic_edit_text_field - edit text field with direct key input
|
|
---------------------------------------------------------------------*/
|
|
|
|
static char *do_dynamic_edit_text_field(char *buf)
|
|
{
|
|
char code = osd_readkey_unicode(0) & 0xFF;
|
|
|
|
if(code == 0x08)
|
|
{
|
|
/* backspace */
|
|
if(buf)
|
|
{
|
|
size_t length = strlen(buf);
|
|
|
|
if(length > 0)
|
|
{
|
|
buf[length - 1] = 0;
|
|
|
|
if(length > 1)
|
|
buf = realloc(buf, length);
|
|
else
|
|
{
|
|
free(buf);
|
|
buf = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(isprint(code))
|
|
{
|
|
if(buf)
|
|
{
|
|
size_t length = strlen(buf);
|
|
|
|
buf = realloc(buf, length + 2);
|
|
|
|
buf[length] = code;
|
|
buf[length + 1] = 0;
|
|
}
|
|
else
|
|
{
|
|
buf = malloc(2);
|
|
|
|
buf[0] = code;
|
|
buf[1] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
do_static_edit_text_field - edit text field with direct key input
|
|
--------------------------------------------------------------------*/
|
|
|
|
static void do_static_edit_text_field(char *buf, int size)
|
|
{
|
|
char code = osd_readkey_unicode(0) & 0xFF;
|
|
size_t length;
|
|
|
|
if(!buf) return;
|
|
|
|
length = strlen(buf);
|
|
|
|
if(code == 0x08)
|
|
{
|
|
/* back space */
|
|
if(length > 0)
|
|
buf[length - 1] = 0;
|
|
}
|
|
else if(isprint(code))
|
|
{
|
|
if(length + 1 < size)
|
|
{
|
|
buf[length] = code;
|
|
buf[length + 1] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
do_edit_hex_field - edit hex field with direct key input (unsigned)
|
|
----------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_edit_hex_field(running_machine *machine, UINT32 data)
|
|
{
|
|
INT8 key;
|
|
|
|
if(input_code_pressed_once(KEYCODE_BACKSPACE))
|
|
{
|
|
/* back space */
|
|
data >>= 4;
|
|
return data;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CLEAR))
|
|
{
|
|
/* data clear */
|
|
data = 0;
|
|
return data;
|
|
}
|
|
|
|
key = read_hex_input();
|
|
|
|
if(key != -1)
|
|
{
|
|
data <<= 4;
|
|
data |= key;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
do_edit_hex_field_signed - edit hex field with direct key input (signed)
|
|
---------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_edit_hex_field_signed(UINT32 data, UINT32 mask)
|
|
{
|
|
INT8 key;
|
|
UINT32 is_negative = data & mask;
|
|
|
|
if(is_negative)
|
|
data |= mask;
|
|
|
|
key = read_hex_input();
|
|
|
|
if(key != -1)
|
|
{
|
|
if(is_negative) data = (~data) + 1;
|
|
|
|
data <<= 4;
|
|
data |= key;
|
|
|
|
if(is_negative) data = (~data) + 1;
|
|
}
|
|
else
|
|
{
|
|
if(input_code_pressed_once(KEYCODE_MINUS))
|
|
data = (~data) + 1;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
do_edit_dec_field - edit dec field with direct key input
|
|
-----------------------------------------------------------*/
|
|
|
|
static INT32 do_edit_dec_field(INT32 data, INT32 min, INT32 max)
|
|
{
|
|
char code = osd_readkey_unicode(0) & 0xFF;
|
|
|
|
if((code >= '0') && (code <= '9'))
|
|
{
|
|
data *= 10;
|
|
data += (code - '0');
|
|
}
|
|
else
|
|
{
|
|
if(code == '-')
|
|
data = -data;
|
|
else
|
|
{
|
|
/* backspace */
|
|
if(code == 0x08)
|
|
data /= 10;
|
|
}
|
|
}
|
|
|
|
/* adjust value */
|
|
if(data < min) data = min;
|
|
if(data > max) data = max;
|
|
|
|
return data;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
do_increment_hex_field - increment a specified value in hex field with arrow key
|
|
--------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_increment_hex_field(UINT32 data, UINT8 digits)
|
|
{
|
|
data = ((data & ~kIncrementMaskTable[digits]) |
|
|
(((data & kIncrementMaskTable[digits]) + kIncrementValueTable[digits]) &
|
|
kIncrementMaskTable[digits]));
|
|
|
|
return data;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
do_decrement_hex_field - decrement a specified value in hex field with arrow key
|
|
-----------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_decrement_hex_field(UINT32 data, UINT8 digits)
|
|
{
|
|
data = ((data & ~kIncrementMaskTable[digits]) |
|
|
(((data & kIncrementMaskTable[digits]) - kIncrementValueTable[digits]) &
|
|
kIncrementMaskTable[digits]));
|
|
|
|
return data;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------------------
|
|
do_increment_hex_field_signed - increment a specified value in hex field with arrow key
|
|
------------------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_increment_hex_field_signed(UINT32 data, UINT8 digits, UINT8 bytes)
|
|
{
|
|
UINT32 new_data = data;
|
|
|
|
if(data & SEARCH_BYTE_SIGN_BIT_TABLE[bytes])
|
|
{
|
|
/* MINUS */
|
|
new_data = ((new_data & ~kIncrementMaskTable[digits]) |
|
|
(((new_data & kIncrementMaskTable[digits]) - kIncrementValueTable[digits]) &
|
|
kIncrementMaskTable[digits]));
|
|
|
|
if(new_data & SEARCH_BYTE_SIGN_BIT_TABLE[bytes])
|
|
new_data = ((data & ~kIncrementMaskTable[digits]) | (new_data & kIncrementMaskTable[digits]));
|
|
}
|
|
else
|
|
{
|
|
/* PLUS */
|
|
new_data = ((new_data & ~kIncrementMaskTable[digits]) |
|
|
(((new_data & kIncrementMaskTable[digits]) + kIncrementValueTable[digits]) &
|
|
kIncrementMaskTable[digits]));
|
|
|
|
if((new_data & SEARCH_BYTE_SIGN_BIT_TABLE[bytes]) == 0)
|
|
new_data = ((data & ~kIncrementMaskTable[digits]) | (new_data & kIncrementMaskTable[digits]));
|
|
}
|
|
|
|
return new_data;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------------------
|
|
do_decrement_hex_field_signed - decrement a specified value in hex field with arrow key
|
|
------------------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_decrement_hex_field_signed(UINT32 data, UINT8 digits, UINT8 bytes)
|
|
{
|
|
UINT32 new_data = data;
|
|
|
|
if(data & SEARCH_BYTE_SIGN_BIT_TABLE[bytes])
|
|
{
|
|
/* MINUS */
|
|
new_data = ((new_data & ~kIncrementMaskTable[digits]) |
|
|
(((new_data & kIncrementMaskTable[digits]) + kIncrementValueTable[digits]) &
|
|
kIncrementMaskTable[digits]));
|
|
|
|
if(new_data & SEARCH_BYTE_SIGN_BIT_TABLE[bytes])
|
|
new_data = ((data & ~kIncrementMaskTable[digits]) | (new_data & kIncrementMaskTable[digits]));
|
|
}
|
|
else
|
|
{
|
|
/* PLUS */
|
|
new_data = ((new_data & ~kIncrementMaskTable[digits]) |
|
|
(((new_data & kIncrementMaskTable[digits]) - kIncrementValueTable[digits]) &
|
|
kIncrementMaskTable[digits]));
|
|
|
|
if((new_data & SEARCH_BYTE_SIGN_BIT_TABLE[bytes]) == 0)
|
|
new_data = ((data & ~kIncrementMaskTable[digits]) | (new_data & kIncrementMaskTable[digits]));
|
|
}
|
|
|
|
return new_data;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
do_increment_dec_field - increment a specified value in dec field with arrow key
|
|
-----------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_increment_dec_field(UINT32 data, UINT8 digits)
|
|
{
|
|
UINT32 value = data & kIncrementMaskTable[digits];
|
|
|
|
if(value >= kIncrementDecTable[digits]) value = 0;
|
|
else value += kIncrementValueTable[digits];
|
|
|
|
return ((data & ~kIncrementMaskTable[digits]) | value);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
do_decrement_dec_field - decrement a specified value in dec field with arrow key
|
|
-----------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_decrement_dec_field(UINT32 data, UINT8 digits)
|
|
{
|
|
UINT32 value = data & kIncrementMaskTable[digits];
|
|
|
|
if(value == 0) value = kIncrementDecTable[digits];
|
|
else value -= kIncrementValueTable[digits];
|
|
|
|
return ((data & ~kIncrementMaskTable[digits]) | value);
|
|
}
|
|
|
|
/***************************************************************************
|
|
INITIALIZATION
|
|
***************************************************************************/
|
|
|
|
/*---------------------------------------
|
|
cheat_init - initialize cheat system
|
|
---------------------------------------*/
|
|
|
|
void cheat_init(running_machine *machine)
|
|
{
|
|
/* initialize lists */
|
|
cheat_list = NULL;
|
|
cheat_list_length = 0;
|
|
|
|
watch_list = NULL;
|
|
watch_list_length = 0;
|
|
|
|
search_list = NULL;
|
|
search_list_length = 0;
|
|
|
|
menu_item_info = NULL;
|
|
menu_item_info_length = 0;
|
|
|
|
#ifdef MESS
|
|
InitMessCheats(machine);
|
|
#endif
|
|
|
|
/* initialize flags/parameters */
|
|
current_search_idx = 0;
|
|
found_database = 0;
|
|
cheats_disabled = 0;
|
|
watches_disabled = 0;
|
|
edit_active = 0;
|
|
edit_cursor = 0;
|
|
driverSpecifiedFlag = 0;
|
|
full_menu_page_height = visible_items = floor(1.0f / ui_get_line_height()) - 1;
|
|
|
|
/* allocate huge strings buffer for format */
|
|
format_strings = malloc(sizeof(cheat_format_strings));
|
|
if(format_strings == NULL)
|
|
fatalerror( "cheat: [format strings] memory allocation error"
|
|
" format_strings = %p\n",
|
|
format_strings);
|
|
|
|
/* set cheat options */
|
|
cheat_options = DEFAULT_CHEAT_OPTIONS;
|
|
horizontal_key_repeat_speed = EXTRACT_FIELD(cheat_options, VerticalKeyRepeatSpeed);
|
|
vertical_key_repeat_speed = EXTRACT_FIELD(cheat_options, HorizontalKeyRepeatSpeed);
|
|
load_cheat_database(machine, LOAD_CHEAT_OPTIONS);
|
|
|
|
/* initialize CPU/Region info for cheat system */
|
|
build_cpu_region_info_list(machine);
|
|
|
|
/* set cheat list from database */
|
|
if(TEST_FIELD(cheat_options, LoadNewCode)) load_cheat_database(machine, LOAD_CHEAT_CODE_NEW);
|
|
if(TEST_FIELD(cheat_options, LoadStandardCode)) load_cheat_database(machine, LOAD_CHEAT_CODE_STANDARD);
|
|
if(TEST_FIELD(cheat_options, LoadOldCode)) load_cheat_database(machine, LOAD_CHEAT_CODE_OLD);
|
|
|
|
/* set default search and watch lists */
|
|
resize_search_list(1, REQUEST_DISPOSE);
|
|
resize_watch_list(full_menu_page_height - 1, 0);
|
|
|
|
/* build search region */
|
|
{
|
|
search_info *info = get_current_search();
|
|
|
|
/* attemp to load user region */
|
|
load_cheat_database(machine, LOAD_USER_REGION);
|
|
|
|
/* if no user region or fail to load the database, attempt to build default region */
|
|
if(info->region_list_length)
|
|
info->search_speed = SEARCH_SPEED_USER_DEFINED;
|
|
else
|
|
{
|
|
info->search_speed = SEARCH_SPEED_VERY_SLOW;
|
|
build_search_regions(machine, info);
|
|
}
|
|
|
|
/* memory allocation for search region */
|
|
allocate_search_regions(info);
|
|
|
|
/* set default parameters for each search box */
|
|
init_search_box(info, EXTRACT_FIELD(cheat_options, SearchBox));
|
|
}
|
|
|
|
/* initialize string table */
|
|
init_string_table();
|
|
|
|
/* initialize cheat menu stack */
|
|
init_cheat_menu_stack();
|
|
|
|
{
|
|
astring * sourceName;
|
|
|
|
sourceName = core_filename_extract_base(astring_alloc(), machine->gamedrv->source_file, TRUE);
|
|
|
|
if(!strcmp(astring_c(sourceName), "neodrvr"))
|
|
driverSpecifiedFlag |= 1;
|
|
else if(!strcmp(astring_c(sourceName), "cps2"))
|
|
driverSpecifiedFlag |= 2;
|
|
else if(!strcmp(astring_c(sourceName), "cps3"))
|
|
driverSpecifiedFlag |= 4;
|
|
|
|
astring_free(sourceName);
|
|
}
|
|
|
|
/* NOTE : disable all cheat messages in initializing so that message parameters should be initialized here */
|
|
SET_MESSAGE(0);
|
|
|
|
periodic_timer = timer_alloc(cheat_periodic, NULL);
|
|
timer_adjust_periodic(periodic_timer, video_screen_get_frame_period(machine->primary_screen), 0, video_screen_get_frame_period(machine->primary_screen));
|
|
|
|
add_exit_callback(machine, cheat_exit);
|
|
}
|
|
|
|
/*---------------------------------
|
|
cheat_exit - free cheat system
|
|
---------------------------------*/
|
|
|
|
static void cheat_exit(running_machine *machine)
|
|
{
|
|
int i;
|
|
|
|
/* save all cheats automatically if needed */
|
|
if(TEST_FIELD(cheat_options, AutoSaveEnabled))
|
|
do_auto_save_cheats(machine);
|
|
|
|
/* free cheat list */
|
|
dispose_cheat_database(machine);
|
|
|
|
/* free watch lists */
|
|
if(watch_list)
|
|
{
|
|
for(i = 0; i < watch_list_length; i++)
|
|
dispose_watch(&watch_list[i]);
|
|
|
|
free(watch_list);
|
|
|
|
watch_list = NULL;
|
|
}
|
|
|
|
/* free search lists */
|
|
if(search_list)
|
|
{
|
|
for(i = 0; i < search_list_length; i++)
|
|
dispose_search(&search_list[i]);
|
|
|
|
free(search_list);
|
|
|
|
search_list = NULL;
|
|
}
|
|
|
|
/* free string table */
|
|
free_string_table();
|
|
|
|
/* free cheat menu stack */
|
|
free_cheat_menu_stack();
|
|
|
|
free(menu_item_info);
|
|
menu_item_info = NULL;
|
|
|
|
free(format_strings);
|
|
format_strings = NULL;
|
|
|
|
#ifdef MESS
|
|
StopMessCheats();
|
|
#endif
|
|
|
|
/* free flags */
|
|
cheat_list_length = 0;
|
|
watch_list_length = 0;
|
|
search_list_length = 0;
|
|
current_search_idx = 0;
|
|
found_database = 0;
|
|
cheats_disabled = 0;
|
|
watches_disabled = 0;
|
|
main_database_name[0] = 0;
|
|
menu_item_info_length = 0;
|
|
cheat_variable[0] = 0;
|
|
cheat_options = 0;
|
|
driverSpecifiedFlag = 0;
|
|
SET_MESSAGE(0);
|
|
}
|
|
|
|
/*----------------------------------
|
|
cheat_menu - handle cheat menus
|
|
----------------------------------*/
|
|
|
|
int cheat_menu(running_machine *machine, int selection)
|
|
{
|
|
cheat_menu_stack *menu = &menu_stack[stack_index];
|
|
|
|
/* handle cheat menu */
|
|
selection = (*menu->handler)(machine, menu);
|
|
|
|
/* handle cheat message */
|
|
if(message_type)
|
|
display_cheat_message();
|
|
|
|
if(selection == 0)
|
|
{
|
|
if(stack_index)
|
|
/* return previous "cheat" menu */
|
|
cheat_menu_stack_pop();
|
|
else
|
|
/* return MAME general menu */
|
|
return selection;
|
|
}
|
|
|
|
return selection + 1;
|
|
}
|
|
|
|
/*----------------------------------------
|
|
bcd_to_decimal - convert a value to hex
|
|
----------------------------------------*/
|
|
|
|
static UINT32 bcd_to_decimal(UINT32 value)
|
|
{
|
|
int i;
|
|
UINT32 accumulator = 0;
|
|
UINT32 multiplier = 1;
|
|
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
accumulator += (value & 0xF) * multiplier;
|
|
|
|
multiplier *= 10;
|
|
value >>= 4;
|
|
}
|
|
|
|
return accumulator;
|
|
}
|
|
|
|
/*----------------------------------------
|
|
decimal_to_bcd - convert a value to dec
|
|
----------------------------------------*/
|
|
|
|
static UINT32 decimal_to_bcd(UINT32 value)
|
|
{
|
|
int i;
|
|
UINT32 accumulator = 0;
|
|
UINT32 divisor = 10;
|
|
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
UINT32 temp;
|
|
|
|
temp = value % divisor;
|
|
value -= temp;
|
|
temp /= divisor / 10;
|
|
|
|
accumulator += temp << (i * 4);
|
|
|
|
divisor *= 10;
|
|
}
|
|
|
|
return accumulator;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
rebuild_string_tables - memory allocation for menu string list
|
|
-----------------------------------------------------------------*/
|
|
|
|
static void rebuild_string_tables(void)
|
|
{
|
|
UINT32 i;
|
|
UINT32 storage_needed;
|
|
char *traverse;
|
|
|
|
/* calculate length of total buffer */
|
|
storage_needed = (menu_strings.main_string_length + menu_strings.sub_string_length) * menu_strings.num_strings;
|
|
|
|
/* allocate memory for all items */
|
|
menu_strings.main_list = (const char **) realloc((char *) menu_strings.main_list, sizeof(char *) * menu_strings.length);
|
|
menu_strings.sub_list = (const char **) realloc((char *) menu_strings.sub_list, sizeof(char *) * menu_strings.length);
|
|
menu_strings.flag_list = realloc( menu_strings.flag_list, sizeof(char) * menu_strings.length);
|
|
menu_strings.main_strings = realloc( menu_strings.main_strings, sizeof(char *) * menu_strings.num_strings);
|
|
menu_strings.sub_strings = realloc( menu_strings.sub_strings, sizeof(char *) * menu_strings.num_strings);
|
|
menu_strings.buf = realloc( menu_strings.buf, sizeof(char) * storage_needed);
|
|
|
|
if( (menu_strings.main_list == NULL && menu_strings.length) ||
|
|
(menu_strings.sub_list == NULL && menu_strings.length) ||
|
|
(menu_strings.flag_list == NULL && menu_strings.length) ||
|
|
(menu_strings.main_strings == NULL && menu_strings.num_strings) ||
|
|
(menu_strings.sub_strings == NULL && menu_strings.num_strings) ||
|
|
(menu_strings.buf == NULL && storage_needed))
|
|
{
|
|
fatalerror( "cheat: [string table] memory allocation error\n"
|
|
" length = %.8X\n"
|
|
" num_strings = %.8X\n"
|
|
" main_stringLength = %.8X\n"
|
|
" sub_string_length = %.8X\n"
|
|
"%p %p %p %p %p %p\n",
|
|
menu_strings.length,
|
|
menu_strings.num_strings,
|
|
menu_strings.main_string_length,
|
|
menu_strings.sub_string_length,
|
|
|
|
menu_strings.main_list,
|
|
menu_strings.sub_list,
|
|
menu_strings.flag_list,
|
|
menu_strings.main_strings,
|
|
menu_strings.sub_strings,
|
|
menu_strings.buf);
|
|
}
|
|
|
|
/* allocate string buffer to list */
|
|
for(i = 0, traverse = menu_strings.buf; i < menu_strings.num_strings; i++)
|
|
{
|
|
menu_strings.main_strings[i] = traverse;
|
|
traverse += menu_strings.main_string_length;
|
|
menu_strings.sub_strings[i] = traverse;
|
|
traverse += menu_strings.sub_string_length;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------
|
|
request_strings - check string list and rebuild if needed
|
|
------------------------------------------------------------*/
|
|
|
|
static void request_strings(UINT32 length, UINT32 num_strings, UINT32 main_string_length, UINT32 sub_string_length)
|
|
{
|
|
UINT8 changed = 0;
|
|
|
|
/* total items */
|
|
if(menu_strings.length < length)
|
|
{
|
|
menu_strings.length = length;
|
|
changed = 1;
|
|
}
|
|
|
|
/* total buffer items */
|
|
if(menu_strings.num_strings < num_strings)
|
|
{
|
|
menu_strings.num_strings = num_strings;
|
|
changed = 1;
|
|
}
|
|
|
|
/* length of buffer 1 */
|
|
if(menu_strings.main_string_length < main_string_length)
|
|
{
|
|
menu_strings.main_string_length = main_string_length;
|
|
changed = 1;
|
|
}
|
|
|
|
/* length of buffer 2 */
|
|
if(menu_strings.sub_string_length < sub_string_length)
|
|
{
|
|
menu_strings.sub_string_length = sub_string_length;
|
|
changed = 1;
|
|
}
|
|
|
|
if(changed)
|
|
rebuild_string_tables();
|
|
}
|
|
|
|
/*----------------------------------------------
|
|
init_string_table - initialize string table
|
|
----------------------------------------------*/
|
|
|
|
static void init_string_table(void)
|
|
{
|
|
memset(&menu_strings, 0, sizeof(menu_string_list));
|
|
}
|
|
|
|
/*----------------------------------------
|
|
free_string_table - free string table
|
|
----------------------------------------*/
|
|
|
|
static void free_string_table(void)
|
|
{
|
|
free((char *) menu_strings.main_list);
|
|
free((char *) menu_strings.sub_list);
|
|
free( menu_strings.flag_list);
|
|
free( menu_strings.main_strings);
|
|
free( menu_strings.sub_strings);
|
|
free( menu_strings.buf);
|
|
|
|
memset(&menu_strings, 0, sizeof(menu_string_list));
|
|
}
|
|
|
|
/*-----------------------------------
|
|
create_string_copy - copy stirng
|
|
-----------------------------------*/
|
|
|
|
static char *create_string_copy(char *buf)
|
|
{
|
|
char *temp = NULL;
|
|
|
|
if(buf && buf[0] != 0)
|
|
{
|
|
/* allocate memory */
|
|
size_t length = strlen(buf) + 1;
|
|
temp = malloc_or_die(length);
|
|
|
|
/* copy memory for string */
|
|
if(temp)
|
|
memcpy(temp, buf, length);
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
/*-------------------------------------------------------------
|
|
create_strings_with_edit_cursor - strings with edit cursor
|
|
-------------------------------------------------------------*/
|
|
|
|
static char *create_strings_with_edit_cursor(char *buf, int data, int total_digits, INT8 current_cursor)
|
|
{
|
|
int i;
|
|
|
|
for(i = total_digits; i >= 0; i--)
|
|
{
|
|
if(i == current_cursor)
|
|
buf += sprintf(buf, "[%X]", (data & kIncrementMaskTable[i]) / kIncrementValueTable[i]);
|
|
else
|
|
buf += sprintf(buf, "%X", (data & kIncrementMaskTable[i]) / kIncrementValueTable[i]);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
old_style_menu - export menu items to draw menu
|
|
--------------------------------------------------*/
|
|
|
|
static void old_style_menu(const char **items, const char **sub_items, char *flag, int selected, int arrowize_subitem)
|
|
{
|
|
int menu_items;
|
|
static ui_menu_item item_list[1000];
|
|
|
|
for(menu_items = 0; items[menu_items]; menu_items++)
|
|
{
|
|
item_list[menu_items].text = items[menu_items];
|
|
item_list[menu_items].subtext = sub_items ? sub_items[menu_items] : NULL;
|
|
item_list[menu_items].flags = 0;
|
|
|
|
/* set a highlight for sub-item */
|
|
if(flag && flag[menu_items])
|
|
item_list[menu_items].flags |= MENU_FLAG_INVERT;
|
|
|
|
/* set an arrow for sub-item */
|
|
if(menu_items == selected)
|
|
{
|
|
if (arrowize_subitem & 1)
|
|
item_list[menu_items].flags |= MENU_FLAG_LEFT_ARROW;
|
|
if (arrowize_subitem & 2)
|
|
item_list[menu_items].flags |= MENU_FLAG_RIGHT_ARROW;
|
|
}
|
|
}
|
|
|
|
visible_items = ui_menu_draw(item_list, menu_items, selected, NULL);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------
|
|
resize_menu_item_info - memory allocation for cheat menu item info
|
|
---------------------------------------------------------------------*/
|
|
|
|
static void resize_menu_item_info(UINT32 new_length)
|
|
{
|
|
if(new_length != menu_item_info_length)
|
|
{
|
|
/* reallocate cheat menu item info */
|
|
menu_item_info = realloc(menu_item_info, new_length * sizeof(cheat_menu_item_info));
|
|
|
|
if(menu_item_info == NULL && new_length != 0)
|
|
fatalerror( "cheat: [menu item info] memory allocation error\n"
|
|
" length = %.8X"
|
|
" menu_item_info = %p",
|
|
menu_item_info_length, menu_item_info);
|
|
|
|
memset(menu_item_info, 0, new_length * sizeof(cheat_menu_item_info));
|
|
|
|
menu_item_info_length = new_length;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------
|
|
init_cheat_menu_stack - initilalize cheat menu stack
|
|
-------------------------------------------------------*/
|
|
|
|
static void init_cheat_menu_stack(void)
|
|
{
|
|
cheat_menu_stack *menu = &menu_stack[stack_index = 0];
|
|
|
|
menu->handler = cheat_main_menu;
|
|
menu->return_handler = NULL;
|
|
menu->sel = 0;
|
|
menu->pre_sel = 0;
|
|
menu->first_time = 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------
|
|
cheat_menu_stack_push - push a menu onto the stack
|
|
-----------------------------------------------------*/
|
|
|
|
static void cheat_menu_stack_push(cheat_menu_handler new_handler, cheat_menu_handler ret_handler, int selection)
|
|
{
|
|
cheat_menu_stack *menu = &menu_stack[++stack_index];
|
|
|
|
assert(stack_index < CHEAT_MENU_DEPTH);
|
|
|
|
menu->handler = new_handler;
|
|
menu->return_handler = ret_handler;
|
|
menu->sel = 0;
|
|
menu->pre_sel = selection;
|
|
menu->first_time = 1;
|
|
edit_active = 0;
|
|
}
|
|
|
|
/*---------------------------------------------------
|
|
cheat_menu_stack_pop - pop a menu from the stack
|
|
---------------------------------------------------*/
|
|
|
|
static void cheat_menu_stack_pop(void)
|
|
{
|
|
int i;
|
|
|
|
assert(stack_index > 0);
|
|
|
|
/* NOTE : cheat menu supports deep-return */
|
|
for(i = stack_index; i > 0; i--)
|
|
if(menu_stack[stack_index].return_handler == menu_stack[i].handler)
|
|
break;
|
|
|
|
stack_index = i;
|
|
}
|
|
|
|
/*-----------------------------------------------------
|
|
free_cheat_menu_stack - reset the cheat menu stack
|
|
-----------------------------------------------------*/
|
|
|
|
static void free_cheat_menu_stack(void)
|
|
{
|
|
int i;
|
|
cheat_menu_stack *menu;
|
|
|
|
for(i = 0; i < CHEAT_MENU_DEPTH; i++)
|
|
{
|
|
menu = &menu_stack[i];
|
|
|
|
menu->handler = NULL;
|
|
menu->return_handler = NULL;
|
|
menu->pre_sel = 0;
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
stack_index = 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
user_select_value_menu - management for value-selection menu
|
|
---------------------------------------------------------------*/
|
|
|
|
static int user_select_value_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
int i;
|
|
UINT8 is_bcd;
|
|
UINT32 min;
|
|
UINT32 max;
|
|
static int master = 0;
|
|
static int display_value = -1;
|
|
char buf[256];
|
|
char *strings_buf = buf;
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
cheat_action *action = NULL;
|
|
|
|
/* first setting 1 : search master code of value-selection */
|
|
if(menu->first_time)
|
|
{
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
if(entry->action_list[0].flags & kActionFlag_OldFormat) {
|
|
/* NOTE : old format should be always master = 0 */
|
|
master = 0; break; }
|
|
|
|
/* search value selection master code */
|
|
if(TEST_FIELD(entry->action_list[i].type, ValueSelectEnable)) {
|
|
master = i; break; }
|
|
}
|
|
}
|
|
|
|
/* set value selection master code */
|
|
action = &entry->action_list[master];
|
|
|
|
if(TEST_FIELD(action->type, ValueSelectMinimumDisplay) || TEST_FIELD(action->type, ValueSelectMinimum))
|
|
min = 1;
|
|
else
|
|
min = 0;
|
|
|
|
max = action->original_data + min;
|
|
is_bcd = EXTRACT_FIELD(action->type, ValueSelectBCD);
|
|
|
|
/* first setting 2 : save the value */
|
|
if(menu->first_time)
|
|
{
|
|
display_value = is_bcd ? decimal_to_bcd(bcd_to_decimal(read_data(machine, action))) : read_data(machine, action);
|
|
|
|
if(display_value < min)
|
|
display_value = min;
|
|
else if(display_value > max)
|
|
display_value = max;
|
|
else if(TEST_FIELD(action->type, ValueSelectMinimumDisplay))
|
|
display_value++;
|
|
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
/* ##### MENU CONSTRACTION ##### */
|
|
strings_buf += sprintf(strings_buf, "\t%s\n\t", entry->name);
|
|
|
|
if(edit_active)
|
|
{
|
|
for(i = BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)] - 1; i >= 0; i--)
|
|
{
|
|
if(i == edit_cursor)
|
|
strings_buf += sprintf(strings_buf, "[%X]", (display_value & kIncrementMaskTable[i]) / kIncrementValueTable[i]);
|
|
else
|
|
strings_buf += sprintf(strings_buf, "%X", (display_value & kIncrementMaskTable[i]) / kIncrementValueTable[i]);
|
|
}
|
|
}
|
|
else
|
|
strings_buf += sprintf(strings_buf, "%.*X", BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)], display_value);
|
|
|
|
if(TEST_FIELD(action->type, ValueSelectNegative))
|
|
strings_buf += sprintf( strings_buf, " <%.*X>",
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)],
|
|
(~display_value + 1) & BYTE_MASK_TABLE[EXTRACT_FIELD(action->type, AddressSize)]);
|
|
|
|
if(is_bcd == 0)
|
|
strings_buf += sprintf(strings_buf, " (%d)", display_value);
|
|
|
|
strings_buf += sprintf(strings_buf, "\n\t OK ");
|
|
|
|
/* print it */
|
|
ui_draw_message_window(buf);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(display_value == max)
|
|
display_value = min;
|
|
else
|
|
{
|
|
display_value = is_bcd ? do_increment_dec_field(display_value, edit_cursor) : do_increment_hex_field(display_value, edit_cursor);
|
|
|
|
if(display_value > max)
|
|
display_value = max;
|
|
}
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(display_value == min)
|
|
display_value = max;
|
|
|
|
else
|
|
{
|
|
display_value = is_bcd ? do_decrement_dec_field(display_value, edit_cursor) : do_decrement_hex_field(display_value, edit_cursor);
|
|
|
|
if(display_value > max)
|
|
display_value = max;
|
|
}
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(++edit_cursor > BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)] - 1)
|
|
edit_cursor = 0;
|
|
}
|
|
else
|
|
{
|
|
if(display_value-- == min)
|
|
display_value = max;
|
|
|
|
if(is_bcd)
|
|
display_value = decimal_to_bcd(bcd_to_decimal(display_value));
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(--edit_cursor < 0)
|
|
edit_cursor = BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)] - 1;
|
|
}
|
|
else
|
|
{
|
|
if(++display_value > max)
|
|
display_value = min;
|
|
|
|
if(is_bcd)
|
|
display_value = decimal_to_bcd(bcd_to_decimal(display_value));
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
int i;
|
|
|
|
if(edit_active)
|
|
edit_active = 0;
|
|
|
|
/* adjust a value */
|
|
if(TEST_FIELD(action->type, ValueSelectMinimumDisplay))
|
|
display_value--;
|
|
|
|
if(TEST_FIELD(action->type, ValueSelectMinimum) && display_value == 0)
|
|
display_value = 1;
|
|
|
|
if(TEST_FIELD(action->type, ValueSelectNegative) && display_value)
|
|
display_value = (~display_value + 1) & BYTE_MASK_TABLE[EXTRACT_FIELD(action->type, AddressSize)];
|
|
|
|
/* set/copy value */
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *destination = &entry->action_list[i];
|
|
|
|
int copy_value = display_value;
|
|
|
|
if(i == master)
|
|
{
|
|
/* set value */
|
|
destination->data = display_value;
|
|
}
|
|
else if(TEST_FIELD(destination->type, ValueSelectEnable))
|
|
{
|
|
/* copy value */
|
|
int new_data = destination->original_data;
|
|
|
|
if(TEST_FIELD(destination->type, ValueSelectBCD))
|
|
{
|
|
copy_value = bcd_to_decimal(decimal_to_bcd(copy_value));
|
|
new_data = bcd_to_decimal(decimal_to_bcd(new_data));
|
|
}
|
|
|
|
copy_value += new_data;
|
|
|
|
if(TEST_FIELD(destination->type, ValueSelectBCD))
|
|
copy_value = decimal_to_bcd(bcd_to_decimal(copy_value));
|
|
|
|
if(TEST_FIELD(destination->type, ValueSelectNegative))
|
|
copy_value = (~copy_value + 1) & BYTE_MASK_TABLE[EXTRACT_FIELD(destination->type, AddressSize)];
|
|
|
|
destination->data = copy_value;
|
|
}
|
|
}
|
|
|
|
activate_cheat(machine, entry);
|
|
|
|
menu->sel = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT))
|
|
{
|
|
edit_active ^= 1;
|
|
edit_cursor = 0;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
if(edit_active) edit_active = 0;
|
|
else menu->sel = -1;
|
|
}
|
|
|
|
/* ##### EDIT ##### */
|
|
if(edit_active == 0)
|
|
{
|
|
UINT32 temp;
|
|
|
|
temp = display_value;
|
|
display_value = do_edit_hex_field(machine, display_value) & BYTE_MASK_TABLE[EXTRACT_FIELD(action->type, AddressSize)];
|
|
|
|
if(display_value != temp)
|
|
{
|
|
if(is_bcd)
|
|
display_value = decimal_to_bcd(bcd_to_decimal(display_value));
|
|
|
|
if(display_value < min) display_value = max;
|
|
if(display_value > max) display_value = min;
|
|
}
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------
|
|
user_select_label_menu - management for label-select menu
|
|
------------------------------------------------------------*/
|
|
|
|
static int user_select_label_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
int i;
|
|
UINT8 total = 0;
|
|
const char **menu_item;
|
|
char **buf;
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
|
|
/* required items = (total items + return + terminator) & (strings buf * total items [max chars = 100]) */
|
|
request_strings(entry->action_list_length + 2, entry->action_list_length, 100, 0);
|
|
menu_item = menu_strings.main_list;
|
|
buf = menu_strings.main_strings;
|
|
|
|
/* first setting : compute cursor position from previous menu */
|
|
if(menu->first_time)
|
|
{
|
|
menu->sel = entry->flags & kCheatFlag_OneShot ? entry->selection - 1 : entry->selection;
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 0; i < entry->label_index_length; i++)
|
|
{
|
|
if(i == 0)
|
|
{
|
|
if((entry->flags & kCheatFlag_OneShot) == 0)
|
|
{
|
|
/* add "OFF" item if not one shot at the first time */
|
|
if(!entry->selection)
|
|
sprintf(buf[total], "[ Off ]");
|
|
else
|
|
sprintf(buf[total], "Off");
|
|
|
|
menu_item[total] = buf[total];
|
|
total++;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if(i == entry->selection)
|
|
sprintf(buf[total], "[ %s ]", entry->action_list[entry->label_index[i]].optional_name);
|
|
else
|
|
sprintf(buf[total], "%s", entry->action_list[entry->label_index[i]].optional_name);
|
|
|
|
menu_item[total] = buf[total];
|
|
total++;
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
menu_item[total++] = "Return to Prior Menu";
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, NULL, NULL, menu->sel, 0);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(menu->sel != total - 1)
|
|
{
|
|
entry->selection = entry->flags & kCheatFlag_OneShot ? menu->sel + 1 : menu->sel;
|
|
|
|
/* set new label index */
|
|
if(entry->selection)
|
|
activate_cheat(machine, entry);
|
|
else
|
|
deactivate_cheat(machine, entry);
|
|
|
|
/* NOTE : the index number of master code should be stored into 1st table */
|
|
if(TEST_FIELD(entry->action_list[entry->label_index[0]].type, LabelSelectQuickClose))
|
|
menu->sel = -1;
|
|
}
|
|
else
|
|
menu->sel = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
menu->sel = -1;
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*------------------------------------------------
|
|
comment_menu - management simple comment menu
|
|
------------------------------------------------*/
|
|
|
|
static int comment_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
char buf[2048];
|
|
const char *comment;
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
comment = entry->comment;
|
|
sprintf(buf, "%s\n\t OK ", comment);
|
|
|
|
/* print it */
|
|
ui_draw_message_window(buf);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(input_ui_pressed(machine, IPT_UI_SELECT) || input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
menu->sel = -1;
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
extend_comment_menu - management multi-line comment menu
|
|
-----------------------------------------------------------*/
|
|
|
|
static int extend_comment_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
int i;
|
|
UINT8 total = 0;
|
|
const char **menu_item;
|
|
char **buf;
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/* required items = (display comment lines + return + terminator) + (strings buf * display comment lines) + 100 characters */
|
|
request_strings(entry->action_list_length + 1, entry->action_list_length - 1, 100, 0);
|
|
menu_item = menu_strings.main_list;
|
|
buf = menu_strings.main_strings;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 1; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
/* NOTE : don't display the comment in master code */
|
|
if(i != 0)
|
|
{
|
|
sprintf(buf[total], "%s", action->optional_name);
|
|
menu_item[total] = buf[total];
|
|
total++;
|
|
}
|
|
}
|
|
|
|
/* ##### OK ##### */
|
|
menu_item[total++] = "OK";
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = NULL;
|
|
|
|
/* adjust cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, NULL, NULL, menu->sel, 0);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT) || input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
menu->sel = -1;
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*------------------------------------------------------
|
|
cheat_main_menu - management for cheat general menu
|
|
------------------------------------------------------*/
|
|
|
|
static int cheat_main_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
enum
|
|
{
|
|
MENU_ENABLE_DISABLE = 0,
|
|
MENU_ADD_EDIT,
|
|
MENU_SEARCH,
|
|
MENU_VIEW_RESULT,
|
|
MENU_CHOOSE_WATCH,
|
|
MENU_OPTIONS,
|
|
MENU_COMMANDS,
|
|
#ifdef MAME_DEBUG
|
|
MENU_DEBUG,
|
|
#endif
|
|
MENU_RETURN,
|
|
MENU_MAX
|
|
};
|
|
|
|
int total = 0;
|
|
ui_menu_item menu_item[MENU_MAX + 1];
|
|
|
|
memset(menu_item, 0, sizeof(menu_item));
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/********** MENU CONSTRUCION **********/
|
|
menu_item[total++].text = "Enable/Disable a Cheat";
|
|
menu_item[total++].text = "Add/Edit a Cheat";
|
|
switch(EXTRACT_FIELD(cheat_options, SearchBox))
|
|
{
|
|
case SEARCH_BOX_MINIMUM:
|
|
menu_item[total++].text = "Search a Cheat (Minimum Mode)";
|
|
break;
|
|
|
|
case SEARCH_BOX_STANDARD:
|
|
menu_item[total++].text = "Search a Cheat (Standard Mode)";
|
|
break;
|
|
|
|
case SEARCH_BOX_ADVANCED:
|
|
menu_item[total++].text = "Search a Cheat (Advanced Mode)";
|
|
break;
|
|
|
|
default:
|
|
menu_item[total++].text = "Unknown Search Menu";
|
|
}
|
|
|
|
menu_item[total++].text = "View Last Results";
|
|
menu_item[total++].text = "Configure Watchpoints";
|
|
menu_item[total++].text = "Cheat Options";
|
|
menu_item[total++].text = "Cheat Commands";
|
|
#ifdef MAME_DEBUG
|
|
menu_item[total++].text = "Debug Viewer";
|
|
#endif
|
|
menu_item[total++].text = "Return to Main Menu";
|
|
menu_item[total].text = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* print it */
|
|
ui_menu_draw(menu_item, total, menu->sel, NULL);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case MENU_ENABLE_DISABLE:
|
|
cheat_menu_stack_push(enable_disable_cheat_menu, cheat_main_menu, menu->sel);
|
|
break;
|
|
|
|
case MENU_ADD_EDIT:
|
|
cheat_menu_stack_push(add_edit_cheat_menu, cheat_main_menu, 0);
|
|
break;
|
|
|
|
case MENU_SEARCH:
|
|
cheat_menu_stack_push(search_main_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case MENU_VIEW_RESULT:
|
|
cheat_menu_stack_push(view_search_result_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case MENU_CHOOSE_WATCH:
|
|
cheat_menu_stack_push(choose_watch_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case MENU_OPTIONS:
|
|
cheat_menu_stack_push(select_option_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case MENU_COMMANDS:
|
|
cheat_menu_stack_push(command_cheat_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
#ifdef MAME_DEBUG
|
|
case MENU_DEBUG:
|
|
cheat_menu_stack_push(debug_cheat_menu, menu->handler, menu->sel);
|
|
break;
|
|
#endif
|
|
case MENU_RETURN:
|
|
menu->sel = -1;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT))
|
|
{
|
|
if(shift_key_pressed())
|
|
reset_cheat_options();
|
|
else if(control_key_pressed())
|
|
load_cheat_database(machine, LOAD_CHEAT_OPTIONS);
|
|
else
|
|
reload_cheat_database(machine);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
enable_disable_cheat_menu - management for Enable/Disable menu
|
|
-----------------------------------------------------------------*/
|
|
|
|
static int enable_disable_cheat_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
#define ADD_CHEAT_SELECT_MENU_ITEMS(sub_name, request_arrow) \
|
|
do { menu_sub_item[total] = sub_name; menu_item_info[total].sub_cheat = i; menu_item_info[total].field_type = request_arrow; \
|
|
flag_buf[total] = traverse->comment && traverse->comment[0] ? 1 : 0; total++; } while(0)
|
|
|
|
int i;
|
|
int do_select = 0;
|
|
UINT8 total = 0;
|
|
UINT8 length = cheat_list_length ? cheat_list_length : 2;
|
|
UINT8 is_empty = 0;
|
|
UINT8 request_arrow = 0;
|
|
static INT8 current_layer;
|
|
const char **menu_item;
|
|
const char **menu_sub_item;
|
|
char *flag_buf;
|
|
cheat_entry *entry = NULL;
|
|
cheat_menu_item_info
|
|
*info = NULL;
|
|
|
|
/* first setting : always starts with root layer level */
|
|
if(menu->first_time)
|
|
{
|
|
current_layer = 0;
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
/* required items = total codes + return + terminator */
|
|
request_strings(length + 2, 0, 0, 0);
|
|
menu_item = menu_strings.main_list;
|
|
menu_sub_item = menu_strings.sub_list;
|
|
flag_buf = menu_strings.flag_list;
|
|
|
|
/* allocate memory for menu item info */
|
|
resize_menu_item_info(length + 2);
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 0; i < cheat_list_length && total < visible_items; i++)
|
|
{
|
|
cheat_entry *traverse = &cheat_list[i];
|
|
|
|
/* when return to previous layer, set cursor position to previous layer label code */
|
|
if(traverse->flags & kCheatFlag_LayerSelected)
|
|
{
|
|
menu->sel = total;
|
|
traverse->flags &= ~kCheatFlag_LayerSelected;
|
|
}
|
|
|
|
if(traverse->layer_index == current_layer)
|
|
{
|
|
if(traverse->flags & kCheatFlag_Separator)
|
|
{
|
|
/* ##### SEPARAOTR ##### */
|
|
menu_item[total] = MENU_SEPARATOR_ITEM;
|
|
ADD_CHEAT_SELECT_MENU_ITEMS(NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
/* ##### CODE NAME ##### */
|
|
menu_item[total] = traverse->name && traverse->name[0] ? traverse->name : "(null)";
|
|
|
|
if(traverse->flags & kCheatFlag_HasWrongCode)
|
|
{
|
|
/* ##### ERROR ##### */
|
|
ADD_CHEAT_SELECT_MENU_ITEMS("ERROR", 0);
|
|
traverse->selection = 0;
|
|
}
|
|
else if(traverse->flags & kCheatFlag_Select)
|
|
{
|
|
/* ##### LABEL ##### */
|
|
if(traverse->flags & kCheatFlag_OldFormat)
|
|
ADD_CHEAT_SELECT_MENU_ITEMS(traverse->selection ? traverse->action_list[traverse->selection].optional_name : "Off", 1);
|
|
else
|
|
ADD_CHEAT_SELECT_MENU_ITEMS(traverse->selection ? traverse->action_list[traverse->label_index[traverse->selection]].optional_name : "Off", 1);
|
|
}
|
|
else if(traverse->flags & kCheatFlag_ExtendComment)
|
|
{
|
|
/* ##### READ ##### */
|
|
ADD_CHEAT_SELECT_MENU_ITEMS("Read", 0);
|
|
}
|
|
else if(traverse->flags & kCheatFlag_LayerIndex)
|
|
{
|
|
/* ##### NEXT LAYER ##### */
|
|
ADD_CHEAT_SELECT_MENU_ITEMS(">>>", 0);
|
|
}
|
|
else if(traverse->flags & kCheatFlag_Null)
|
|
{
|
|
/* ##### COMMENT ##### */
|
|
ADD_CHEAT_SELECT_MENU_ITEMS(NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
/* ##### ON/OFF ##### */
|
|
if(traverse->flags & kCheatFlag_OneShot)
|
|
ADD_CHEAT_SELECT_MENU_ITEMS("Set", 0);
|
|
else
|
|
ADD_CHEAT_SELECT_MENU_ITEMS(traverse->flags & kCheatFlag_Active ? "On" : "Off", 1);
|
|
}
|
|
}
|
|
}
|
|
else if(traverse->flags & kCheatFlag_LayerIndex)
|
|
{
|
|
/* specified handling for previous layer select item */
|
|
if(current_layer == traverse->action_list[0].data)
|
|
{
|
|
/* ##### PREVIOUS LAYER ##### */
|
|
menu_item[total] = traverse->comment && traverse->comment[0] ? traverse->comment : "Return to Prior Layer";
|
|
ADD_CHEAT_SELECT_MENU_ITEMS("<<<", 0);
|
|
}
|
|
}
|
|
}
|
|
#undef ADD_CHEAT_SELECT_MENU_ITEMS
|
|
|
|
/* if no code, set special message */
|
|
if(cheat_list_length == 0)
|
|
{
|
|
if(found_database)
|
|
{
|
|
/* the database is found but no code */
|
|
menu_item[total] = "there are no cheats for this game";
|
|
menu_sub_item[total] = NULL;
|
|
menu_item_info[total].sub_cheat = total;
|
|
menu_item_info[total].field_type = 0;
|
|
flag_buf[total++] = 0;
|
|
is_empty = 1;
|
|
}
|
|
else
|
|
{
|
|
/* the database itself is not found */
|
|
menu_item[total] = "cheat database not found";
|
|
menu_sub_item[total] = NULL;
|
|
menu_item_info[total].sub_cheat = total;
|
|
menu_item_info[total].field_type = 0;
|
|
flag_buf[total++] = 0;
|
|
|
|
menu_item[total] = "unzip it and place it in the MAME directory";
|
|
menu_sub_item[total] = NULL;
|
|
menu_item_info[total].sub_cheat = total;
|
|
menu_item_info[total].field_type = 0;
|
|
flag_buf[total++] = 0;
|
|
is_empty = 2;
|
|
}
|
|
}
|
|
else if(current_layer && total == 1)
|
|
{
|
|
/* selected layer doesn't have code */
|
|
menu_item[total] = "selected layer doesn't have sub code";
|
|
menu_sub_item[total] = NULL;
|
|
menu_item_info[total].sub_cheat = menu_item_info[total - 1].sub_cheat;
|
|
menu_item_info[total].field_type = 0;
|
|
flag_buf[total++] = 0;
|
|
is_empty = 3;
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
menu_item[total] = current_layer ? "Return to Root Layer" : "Return to Prior Menu";
|
|
menu_sub_item[total] = NULL;
|
|
menu_item_info[total].sub_cheat = total - 1;
|
|
menu_item_info[total].field_type = 0;
|
|
flag_buf[total++] = 0;
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = menu_sub_item[total] = NULL;
|
|
|
|
/* adjust cursor position */
|
|
switch(is_empty)
|
|
{
|
|
default:
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* if cursor is on comment code, skip it */
|
|
while(menu->sel < total - 1 && (cheat_list[menu_item_info[menu->sel].sub_cheat].flags & kCheatFlag_Null))
|
|
menu->sel++;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
/* no database or code, unselectable message line */
|
|
menu->sel = total - 1;
|
|
break;
|
|
|
|
case 3:
|
|
/* no code in sub layer, unselectable message line */
|
|
if(menu->sel == 1) menu->sel = 0;
|
|
break;
|
|
}
|
|
|
|
/* set selected menu info */
|
|
if(menu->sel < total) info = &menu_item_info[menu->sel];
|
|
|
|
/* set selected entry */
|
|
if(is_empty == 0 && menu->sel < total - 1)
|
|
{
|
|
entry = &cheat_list[info->sub_cheat];
|
|
|
|
/* ignore separator and comment */
|
|
if(entry->flags & kCheatFlag_Null) entry = NULL;
|
|
}
|
|
else
|
|
entry = NULL;
|
|
|
|
/* set left/right arrow for sub item */
|
|
if(info->field_type && (entry->flags & kCheatFlag_OldFormat) == 0) request_arrow = MENU_FLAG_LEFT_ARROW | MENU_FLAG_RIGHT_ARROW;
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, menu_sub_item, flag_buf, menu->sel, request_arrow);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
if(is_empty == 0)
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
|
|
/* if cursor is on comment code, skip it */
|
|
for(i = 0; (i < visible_items / 2) && menu->sel != total - 1 && (cheat_list[menu_item_info[menu->sel].sub_cheat].flags & kCheatFlag_Null); i++)
|
|
{
|
|
if(--menu->sel < 0) menu->sel = total - 1;
|
|
}
|
|
}
|
|
else if(is_empty == 2)
|
|
{
|
|
if(menu->sel) menu->sel = 0;
|
|
else menu->sel = 2;
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
if(is_empty == 0)
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
|
|
/* if cursor is on comment code, skip it */
|
|
for(i = 0; (i < visible_items / 2) && menu->sel < total - 1 && (cheat_list[menu_item_info[menu->sel].sub_cheat].flags & kCheatFlag_Null); i++)
|
|
menu->sel++;
|
|
}
|
|
else if(is_empty == 2)
|
|
{
|
|
if(menu->sel) menu->sel = 0;
|
|
else menu->sel = 2;
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
do_select = -1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
do_select = 1;
|
|
}
|
|
if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(entry == NULL)
|
|
{
|
|
if(current_layer) current_layer = menu->sel = 0;
|
|
else menu->sel = -1;
|
|
}
|
|
else if((entry->flags & kCheatFlag_Null) == 0)
|
|
{
|
|
if(shift_key_pressed() && (entry->comment && entry->comment[0]))
|
|
{
|
|
/* display comment */
|
|
cheat_menu_stack_push(comment_menu, menu->handler, info->sub_cheat);
|
|
}
|
|
else if(entry->flags & kCheatFlag_ExtendComment)
|
|
{
|
|
/* display extend comment */
|
|
cheat_menu_stack_push(extend_comment_menu, menu->handler, info->sub_cheat);
|
|
}
|
|
else
|
|
do_select = 1;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT))
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
/* shift + save : save all codes */
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
save_cheat_code(machine, &cheat_list[i]);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_ALL_CHEATS_SAVED);
|
|
}
|
|
else if(control_key_pressed())
|
|
{
|
|
/* ctrl + save : save activation key */
|
|
save_activation_key(machine, entry, info->sub_cheat);
|
|
}
|
|
else if(alt_key_pressed())
|
|
{
|
|
/* alt + save : save pre-enable */
|
|
save_pre_enable(machine, entry, info->sub_cheat);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT))
|
|
{
|
|
add_cheat_before(info->sub_cheat);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
{
|
|
if(entry) delete_cheat_at(info->sub_cheat);
|
|
else SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_DELETE);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT))
|
|
{
|
|
if(entry) cheat_menu_stack_push(command_add_edit_menu, menu->handler, info->sub_cheat);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_WATCH_VALUE))
|
|
{
|
|
watch_cheat_entry(entry, 0);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT))
|
|
{
|
|
reload_cheat_database(machine);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
/* NOTE : cancel button return cheat main menu directly */
|
|
menu->sel = -1;
|
|
}
|
|
|
|
if(do_select && entry)
|
|
{
|
|
if(entry->flags & kCheatFlag_HasWrongCode)
|
|
{
|
|
/* activate code analyser */
|
|
cheat_menu_stack_push(analyse_cheat_menu, menu->handler, info->sub_cheat);
|
|
}
|
|
else if(entry->flags & kCheatFlag_UserSelect)
|
|
{
|
|
/* activate value-selection menu */
|
|
cheat_menu_stack_push(user_select_value_menu, menu->handler, info->sub_cheat);
|
|
}
|
|
else if(entry->flags & kCheatFlag_Select)
|
|
{
|
|
if(entry->flags & kCheatFlag_UseLabelSelector)
|
|
{
|
|
/* activate label selector */
|
|
cheat_menu_stack_push(user_select_label_menu, menu->handler, info->sub_cheat);
|
|
}
|
|
else
|
|
/* select next/previous label */
|
|
choose_label_index(machine, entry, do_select);
|
|
}
|
|
else if(entry->flags & kCheatFlag_LayerIndex)
|
|
{
|
|
/* go to next/previous layer */
|
|
current_layer = entry->action_list[0].data == current_layer ? entry->action_list[0].address : entry->action_list[0].data;
|
|
entry->flags |= kCheatFlag_LayerSelected;
|
|
}
|
|
else if(entry->flags & kCheatFlag_OneShot)
|
|
{
|
|
/* activate set code */
|
|
activate_cheat(machine, entry);
|
|
}
|
|
else
|
|
{
|
|
/* toggle on/off */
|
|
int active = (entry->flags & kCheatFlag_Active) ^ 1;
|
|
|
|
if(active) activate_cheat(machine, entry);
|
|
else deactivate_cheat(machine, entry);
|
|
}
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
add_edit_cheat_menu - management for Add/Edit cheat menu
|
|
-----------------------------------------------------------*/
|
|
|
|
static int add_edit_cheat_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
int i;
|
|
UINT8 total = 0;
|
|
const char **menu_item;
|
|
cheat_entry *entry;
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/* required items = total codes + return + terminator */
|
|
request_strings(cheat_list_length + 2, 0, 0, 0);
|
|
menu_item = menu_strings.main_list;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
{
|
|
cheat_entry *traverse = &cheat_list[i];
|
|
|
|
/* ##### NAME ##### */
|
|
if(traverse->name)
|
|
menu_item[total++] = traverse->name;
|
|
else
|
|
menu_item[total++] = "(none)";
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
menu_item[total++] = "Return to Prior Menu";
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = NULL;
|
|
|
|
/* adjust cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, NULL, NULL, menu->sel, 0);
|
|
|
|
/* set entry for selected item if valid, otherwise null (return item) */
|
|
if(menu->sel < total - 1)
|
|
entry = &cheat_list[menu->sel];
|
|
else
|
|
entry = NULL;
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(entry)
|
|
{
|
|
if(entry->flags & kCheatFlag_HasWrongCode)
|
|
{
|
|
cheat_menu_stack_push(analyse_cheat_menu, menu->handler, menu->sel);
|
|
}
|
|
else
|
|
cheat_menu_stack_push(command_add_edit_menu, menu->handler, menu->sel);
|
|
}
|
|
else
|
|
menu->sel = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT))
|
|
{
|
|
reload_cheat_database(machine);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT))
|
|
{
|
|
if(entry)
|
|
{
|
|
if(entry->flags & kCheatFlag_HasWrongCode)
|
|
{
|
|
cheat_menu_stack_push(analyse_cheat_menu, menu->handler, menu->sel);
|
|
}
|
|
else
|
|
cheat_menu_stack_push(command_add_edit_menu, menu->handler, menu->sel);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT))
|
|
{
|
|
add_cheat_before(menu->sel);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
{
|
|
delete_cheat_at(menu->sel);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT))
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
/* shift + save = save all codes */
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
save_cheat_code(machine, &cheat_list[i]);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_ALL_CHEATS_SAVED);
|
|
}
|
|
else if(control_key_pressed())
|
|
{
|
|
if(entry->activation_key)
|
|
/* ctrl + save = save activation key */
|
|
save_activation_key(machine, entry, menu->sel);
|
|
}
|
|
else if(alt_key_pressed())
|
|
{
|
|
/* alt + save = save pre-enable code */
|
|
save_pre_enable(machine, entry, menu->sel);
|
|
}
|
|
else
|
|
{
|
|
save_cheat_code(machine, entry);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_WATCH_VALUE))
|
|
{
|
|
watch_cheat_entry(entry, 0);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
command_add_edit_menu - management for code command menu
|
|
-----------------------------------------------------------*/
|
|
|
|
static int command_add_edit_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
enum{
|
|
kMenu_EditCheat = 0,
|
|
kMenu_ReloadDatabase,
|
|
kMenu_WatchCheat,
|
|
kMenu_SaveCheat,
|
|
kMenu_save_activation_key,
|
|
kMenu_save_pre_enable,
|
|
kMenu_SaveAllCodes,
|
|
kMenu_AddCode,
|
|
kMenu_DeleteCode,
|
|
#ifdef MAME_DEBUG
|
|
kMenu_ConvertFormat,
|
|
kMenu_AnalyseCode,
|
|
#endif
|
|
kMenu_Return,
|
|
kMenu_Max };
|
|
|
|
int i;
|
|
UINT8 total = 0;
|
|
ui_menu_item menu_item[kMenu_Max + 1];
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
|
|
memset(menu_item, 0, sizeof(menu_item));
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/********** MENU CONSTRUCION **********/
|
|
if(entry->flags & kCheatFlag_OldFormat)
|
|
menu_item[total++].text = "Edit Code";
|
|
else
|
|
menu_item[total++].text = "View Code";
|
|
menu_item[total++].text = "Reload Database";
|
|
menu_item[total++].text = "Watch Code";
|
|
menu_item[total++].text = "Save Code";
|
|
menu_item[total++].text = "Save Activation Key";
|
|
menu_item[total++].text = "Save PreEnable";
|
|
menu_item[total++].text = "Save All Codes";
|
|
menu_item[total++].text = "Add New Code";
|
|
menu_item[total++].text = "Delete Code";
|
|
#ifdef MAME_DEBUG
|
|
if(entry->flags & kCheatFlag_OldFormat)
|
|
menu_item[total++].text = "Convert To New Format";
|
|
else
|
|
menu_item[total++].text = "Convert To Old Format";
|
|
menu_item[total++].text = "Analyse Code";
|
|
#endif
|
|
menu_item[total++].text = "Return to Prior Menu";
|
|
menu_item[total].text = NULL;
|
|
|
|
/* adjust cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* print it */
|
|
ui_menu_draw(menu_item, total, menu->sel, NULL);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case kMenu_EditCheat:
|
|
if(entry->flags & kCheatFlag_OldFormat)
|
|
cheat_menu_stack_push(edit_cheat_menu, menu->return_handler, menu->pre_sel);
|
|
else
|
|
cheat_menu_stack_push(view_cheat_menu, menu->return_handler, menu->pre_sel);
|
|
break;
|
|
|
|
case kMenu_ReloadDatabase:
|
|
reload_cheat_database(machine);
|
|
cheat_menu_stack_pop();
|
|
break;
|
|
|
|
case kMenu_WatchCheat:
|
|
watch_cheat_entry(entry, 0);
|
|
break;
|
|
|
|
case kMenu_SaveCheat:
|
|
save_cheat_code(machine, entry);
|
|
break;
|
|
|
|
case kMenu_save_activation_key:
|
|
save_activation_key(machine, entry, menu->pre_sel);
|
|
break;
|
|
|
|
case kMenu_save_pre_enable:
|
|
save_pre_enable(machine, entry, menu->pre_sel);
|
|
break;
|
|
|
|
case kMenu_SaveAllCodes:
|
|
{
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
save_cheat_code(machine, &cheat_list[i]);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_ALL_CHEATS_SAVED);
|
|
}
|
|
break;
|
|
|
|
case kMenu_AddCode:
|
|
add_cheat_before(menu->pre_sel);
|
|
menu->sel = -1;
|
|
break;
|
|
|
|
case kMenu_DeleteCode:
|
|
delete_cheat_at(menu->pre_sel);
|
|
menu->sel = -1;
|
|
break;
|
|
|
|
#ifdef MAME_DEBUG
|
|
case kMenu_ConvertFormat:
|
|
if((entry->flags & kCheatFlag_OldFormat) == 0)
|
|
{
|
|
/* new -> old (UNDERCONSTRUCTION) */
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
entry->action_list[i].flags |= kActionFlag_OldFormat;
|
|
update_cheat_info(machine, entry, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* old -> new (UNDERCONSTRUCTION) */
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
entry->action_list[i].flags &= ~kActionFlag_OldFormat;
|
|
update_cheat_info(machine, entry, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kMenu_AnalyseCode:
|
|
cheat_menu_stack_push(analyse_cheat_menu, menu->return_handler, menu->pre_sel);
|
|
break;
|
|
#endif
|
|
case kMenu_Return:
|
|
menu->sel = -1;
|
|
break;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT))
|
|
{
|
|
reload_cheat_database(machine);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL) || input_ui_pressed(machine, IPT_UI_LEFT) || input_ui_pressed(machine, IPT_UI_RIGHT))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
edit_cheat_menu - management for edit code menu
|
|
--------------------------------------------------*/
|
|
|
|
static int edit_cheat_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
#define ADD_EDIT_MENU_ITEMS(name, sub_name, type) \
|
|
do { menu_item[total] = name; menu_sub_item[total] = sub_name; menu_item_info[total].sub_cheat = i; menu_item_info[total].field_type = type; total++; } while(0)
|
|
|
|
static const char *const TYPE_NAMES[] =
|
|
{
|
|
"Normal", "Wait", "Ignore Decrement", "Watch"
|
|
};
|
|
|
|
static const char *const LOCATION_TYPE_NAMES[] =
|
|
{
|
|
"Comment", "EEPROM", "Select", "Activation Key", "Pre-enable", "Overclock", "Refresh Rate"
|
|
};
|
|
|
|
static const char *const PREFILL_NAMES[] =
|
|
{
|
|
"None", "FF", "00", "01"
|
|
};
|
|
|
|
static const char *const LOCATION_NAMES[] =
|
|
{
|
|
"CPU Region", "Non CPU Region", "Mapped Memory", "EEPROM", "Relative Address"
|
|
};
|
|
|
|
enum
|
|
{
|
|
/* if code index == 0 (master code) */
|
|
EDIT_MENU_ENTRY_NAME = 0, /* text name from name field in cheat entry */
|
|
EDIT_MENU_COMMENT, /* text name from comment field in cheat entry */
|
|
EDIT_MENU_ACTIVATION_KEY, /* text name from activation key */
|
|
EDIT_MENU_INDEX, /* value current index of cheat action. UNSELECTABLE */
|
|
EDIT_MENU_NAME, /* text name from optinal name field in cheat action */
|
|
/* type infomation */
|
|
EDIT_MENU_ONE_SHOT, /* select OneShot Off - On */
|
|
EDIT_MENU_RESTORE_VALUE, /* select RestorePreviousValue Off - On */
|
|
EDIT_MENU_TYPE, /* select Type Normal - Wait - Ignore Decrement - Watch */
|
|
EDIT_MENU_TIMER, /* select Parameter 0x00 - 0x07 */
|
|
EDIT_MENU_LOCATION_TYPE, /* select LocationType Normal - Comment - Select */
|
|
EDIT_MENU_OPERATION, /* select Operation Write - Add - Subtract - Force Range - Set Bit - Clear Bit */
|
|
/* if Location != Relative Address */
|
|
/* if Operation == Write && Location */
|
|
EDIT_MENU_WRITE_MASK, /* value Extend Data Field 0x00000000 - 0xFFFFFFFF */
|
|
/* if Operation == Add || Subtract */
|
|
EDIT_MENU_ADD_SUBTRACT, /* value Extend Data Field 0x00000000 - 0xFFFFFFFF */
|
|
/* if Operation == Force Range && Bytes <= 2 Bytes */
|
|
EDIT_MENU_RANGE_MINIMUM, /* value Extend Data Field 0x0000 - 0xFFFF
|
|
NOTE : value is paccked into upper 2 bytes */
|
|
EDIT_MENU_RANGE_MAXIMUM, /* value Extend Data Field 0x0000 - 0xFFFF
|
|
NOTE : value is paccked into lower 2 bytes */
|
|
EDIT_MENU_DATA,
|
|
EDIT_MENU_WATCH_SIZE, /* value Data Field 0x01 - 0xFF (stored as 0x00 - 0xFE)
|
|
NOTE: value is packed in to 0x000000FF */
|
|
EDIT_MENU_WATCH_SKIP, /* value Data Field 0x00 - 0xFF
|
|
NOTE: value is packed in to 0x0000FF00 */
|
|
EDIT_MENU_WATCH_PER_LINE, /* value Data Field 0x00 - 0xFF
|
|
NOTE: value is packed in to 0x00FF0000 */
|
|
EDIT_MENU_WATCH_ADD_VALUE, /* value Data Field -0x80 - 0x7F
|
|
NOTE: value is packed in to 0xFF000000 */
|
|
EDIT_MENU_WATCH_FORMAT, /* select Parameter Hex - Decimal - Binary - ASCII */
|
|
EDIT_MENU_WATCH_LABEL, /* select Parameter Off - On */
|
|
EDIT_MENU_USER_SELECT, /* select UserSelectEnable Off - On */
|
|
EDIT_MENU_USER_SELECT_MINIMUM_DISP, /* select UserSelectMinimumDisplay 0 - 1 */
|
|
EDIT_MENU_USER_SELECT_MINIMUM, /* select UserSelectMinimum 0 - 1 */
|
|
EDIT_MENU_USER_SELECT_BCD, /* select UserSelectBCD Off - On */
|
|
EDIT_MENU_PREFILL, /* select Prefill None - FF - 00 - 01 */
|
|
EDIT_MENU_BYTES_LENGTH, /* select BytesUsed 1 - 4 */
|
|
EDIT_MENU_LOCATION, /* select Location CPU Region - Non-CPU Region - Mapped Memory - EEPROM - Relative Address */
|
|
EDIT_MENU_REGION, /* select LocationParameter CPU1 - CPU2 - CPU3 - CPU4 - CPU5 - CPU6 - CPU7 - CPU8 -
|
|
GFX1 - GFX2 - GFX3 - GFX4 - GFX5 - GFX6 - GFX7 - GFX8 -
|
|
PROMS -
|
|
SOUND1 - SOUND2 - SOUND3 - SOUND4 - SOUND5 - SOUND6 - SOUND7 - SOUND8 -
|
|
USER1 - USER2 - USER3 - USER4 - USER5 - USER6 - USER7
|
|
NOTE : unsupported USER8 - PLDS in old/older format */
|
|
EDIT_MENU_PACKED_SIZE, /* select IndexBytesUsed 1 - 4 */
|
|
EDIT_MENU_ADDRESS_INDEX, /* value Extend Data Field -0x7FFFFFFF - 0x7FFFFFFF */
|
|
EDIT_MENU_ADDRESS,
|
|
|
|
EDIT_MENU_SEPARATOR,
|
|
EDIT_MENU_RETURN,
|
|
|
|
EDIT_MENU_MAX = 48
|
|
};
|
|
|
|
int i;
|
|
int total = 0;
|
|
int do_select = 0;
|
|
int dirty = 0;
|
|
const char **menu_item;
|
|
const char **menu_sub_item;
|
|
char *flag_buf;
|
|
char **buf_index;
|
|
char **buf_extend_data; /* FFFFFFFF (-7FFFFFFF) */
|
|
char **buf_address; /* FFFFFFFF */
|
|
char **buf_data; /* 7FFFFFFF (-2147483647) 999 999 999 999 */
|
|
cheat_menu_item_info *info = NULL;
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
cheat_action *action = NULL;
|
|
astring *key_strings = astring_alloc();
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/* required items = (total menu items * total codes + return + terminator) + (4 strings buffers * total codes) + 2048 characters */
|
|
request_strings(EDIT_MENU_MAX * entry->action_list_length + 2, 4 * entry->action_list_length, 2048, 0);
|
|
|
|
/* allocate memory for menu item info */
|
|
resize_menu_item_info(EDIT_MENU_MAX * entry->action_list_length + 2);
|
|
|
|
menu_item = menu_strings.main_list;
|
|
menu_sub_item = menu_strings.sub_list;
|
|
flag_buf = menu_strings.flag_list;
|
|
buf_index = &menu_strings.main_strings[entry->action_list_length * 0];
|
|
buf_extend_data = &menu_strings.main_strings[entry->action_list_length * 1];
|
|
buf_address = &menu_strings.main_strings[entry->action_list_length * 2];
|
|
buf_data = &menu_strings.main_strings[entry->action_list_length * 3];
|
|
|
|
memset(flag_buf, 0, EDIT_MENU_MAX * entry->action_list_length + 2);
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *traverse = &entry->action_list[i];
|
|
|
|
if(i == 0)
|
|
{
|
|
/* ##### ENTRY NAME ##### */
|
|
ADD_EDIT_MENU_ITEMS("Entry Name", entry->name && entry->name[0] ? entry->name : "(none)", EDIT_MENU_ENTRY_NAME);
|
|
|
|
/* ##### COMMENT ##### */
|
|
ADD_EDIT_MENU_ITEMS("Comment", entry->comment && entry->comment[0] ? entry->comment : "(none)", EDIT_MENU_COMMENT);
|
|
|
|
/* ##### ACTIVATION KEY ##### */
|
|
ADD_EDIT_MENU_ITEMS( "Activation Key",
|
|
entry->activation_key ? astring_c(input_code_name(key_strings, entry->activation_key)) : "(none)",
|
|
EDIT_MENU_ACTIVATION_KEY);
|
|
|
|
/* ##### SEPARATOR ##### */
|
|
ADD_EDIT_MENU_ITEMS(MENU_SEPARATOR_ITEM, NULL, EDIT_MENU_SEPARATOR);
|
|
}
|
|
|
|
/* ##### ENTRY NAME ##### */
|
|
ADD_EDIT_MENU_ITEMS("Name", traverse->optional_name && traverse->optional_name[0] ? traverse->optional_name : "(none)", EDIT_MENU_NAME);
|
|
|
|
/* ##### INDEX ##### */
|
|
sprintf(buf_index[i], "%2.2d/%2.2d", i + 1, entry->action_list_length);
|
|
ADD_EDIT_MENU_ITEMS("Code Index", buf_index[i], EDIT_MENU_INDEX);
|
|
|
|
/* ##### ONE SHOT ##### */
|
|
ADD_EDIT_MENU_ITEMS("One Shot", TEST_FIELD(traverse->type, OneShot) ? "On" : "Off", EDIT_MENU_ONE_SHOT);
|
|
|
|
/* ##### RESTORE VALUE ##### */
|
|
ADD_EDIT_MENU_ITEMS("Restore Previous Value", TEST_FIELD(traverse->type, RestorePreviousValue) ? "On" : "Off", EDIT_MENU_RESTORE_VALUE);
|
|
|
|
/* ##### TYPE ##### */
|
|
ADD_EDIT_MENU_ITEMS("Type", TYPE_NAMES[EXTRACT_FIELD(traverse->type, Type)], EDIT_MENU_TYPE);
|
|
|
|
/* ##### TIMER ##### */
|
|
ADD_EDIT_MENU_ITEMS("Timer", kNumbersTable[EXTRACT_FIELD(traverse->type, TypeParameter)], EDIT_MENU_TIMER);
|
|
|
|
/* ##### LOCATION TYPE ##### */
|
|
if(EXTRACT_FIELD(traverse->type, LocationType) == kLocation_Custom)
|
|
ADD_EDIT_MENU_ITEMS("Loction Type", LOCATION_TYPE_NAMES[EXTRACT_FIELD(traverse->type, LocationParameter)], EDIT_MENU_LOCATION_TYPE);
|
|
else
|
|
ADD_EDIT_MENU_ITEMS("Location Type", "Normal", EDIT_MENU_LOCATION_TYPE);
|
|
|
|
/* ##### OPERATION ##### */
|
|
switch(EXTRACT_FIELD(traverse->type, Operation))
|
|
{
|
|
case kOperation_WriteMask: ADD_EDIT_MENU_ITEMS("Operation", "Write", EDIT_MENU_OPERATION); break;
|
|
case kOperation_AddSubtract: ADD_EDIT_MENU_ITEMS("Operation", TEST_FIELD(traverse->type, OperationParameter) ?
|
|
"Subtract" : "Add", EDIT_MENU_OPERATION); break;
|
|
case kOperation_ForceRange: ADD_EDIT_MENU_ITEMS("Operation", "Force Range", EDIT_MENU_OPERATION); break;
|
|
case kOperation_SetOrClearBits: ADD_EDIT_MENU_ITEMS("Operation", BIT_SET_CLEAR_NAMES[EXTRACT_FIELD(traverse->type, OperationParameter)],
|
|
EDIT_MENU_OPERATION); break;
|
|
default: ADD_EDIT_MENU_ITEMS("Operation", "Unknown", EDIT_MENU_OPERATION); break;
|
|
}
|
|
|
|
/* ##### MASK ##### */
|
|
{
|
|
int num_chars;
|
|
|
|
if(traverse->flags & kActionFlag_IndexAddress)
|
|
{
|
|
menu_item_info[total].extra_data = ~0; num_chars = 8;
|
|
}
|
|
else
|
|
{
|
|
menu_item_info[total].extra_data = BYTE_MASK_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)];
|
|
num_chars = BYTE_DIGITS_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)];
|
|
}
|
|
sprintf(buf_extend_data[i], "%.*X", num_chars, traverse->extend_data & BYTE_MASK_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)]);
|
|
ADD_EDIT_MENU_ITEMS("Mask", buf_extend_data[i], EDIT_MENU_WRITE_MASK);
|
|
}
|
|
|
|
/* ##### ADD/SUBTRACT ##### */
|
|
sprintf(buf_extend_data[i] + 16, "%*.*X", (int)BYTE_DIGITS_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)],
|
|
(int)BYTE_DIGITS_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)],
|
|
traverse->extend_data & BYTE_MASK_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)]);
|
|
ADD_EDIT_MENU_ITEMS(TEST_FIELD(traverse->type, OperationParameter) ? "Minimum Boundary" : "Maximum Boundary", buf_extend_data[i] + 16, EDIT_MENU_ADD_SUBTRACT);
|
|
|
|
/* ##### RANGE MINIMUM ##### */
|
|
sprintf(buf_extend_data[i] + 32, "%4.4X", EXTRACT_FIELD(traverse->extend_data, LSB16));
|
|
ADD_EDIT_MENU_ITEMS("Range Minimum", buf_extend_data[i] + 32, EDIT_MENU_RANGE_MINIMUM);
|
|
|
|
/* ##### RANGE MAXIMUM ##### */
|
|
sprintf(buf_extend_data[i] + 48, "%4.4X", EXTRACT_FIELD(traverse->extend_data, MSB16));
|
|
ADD_EDIT_MENU_ITEMS("Range Maximum", buf_extend_data[i] + 48, EDIT_MENU_RANGE_MAXIMUM);
|
|
|
|
/* ##### DATA ##### */
|
|
menu_item_info[total].extra_data = BYTE_MASK_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)];
|
|
sprintf(buf_data[i], "%*.*X (%*.*d)", (int)BYTE_DIGITS_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)],
|
|
(int)BYTE_DIGITS_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)],
|
|
traverse->original_data & BYTE_MASK_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)],
|
|
(int)BYTE_DEC_DIGITS_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)],
|
|
(int)BYTE_DEC_DIGITS_TABLE[EXTRACT_FIELD(traverse->type, BytesUsed)],
|
|
traverse->original_data);
|
|
ADD_EDIT_MENU_ITEMS("Data", buf_data[i], EDIT_MENU_DATA);
|
|
|
|
/* ##### WATCH SIZE ##### */
|
|
sprintf(buf_data[i] + 32, "%.3d", EXTRACT_FIELD(traverse->original_data, WatchNumElements) + 1);
|
|
ADD_EDIT_MENU_ITEMS("Watch Size", buf_data[i] + 32, EDIT_MENU_WATCH_SIZE);
|
|
|
|
/* ##### WATCH SKIP ##### */
|
|
sprintf(buf_data[i] + 48, "%.3d", EXTRACT_FIELD(traverse->original_data, WatchSkip));
|
|
ADD_EDIT_MENU_ITEMS("Watch Skip", buf_data[i] + 48, EDIT_MENU_WATCH_SKIP);
|
|
|
|
/* ##### WATCH PER LINE ##### */
|
|
sprintf(buf_data[i] + 64, "%.3d", EXTRACT_FIELD(traverse->original_data, WatchElementsPerLine));
|
|
ADD_EDIT_MENU_ITEMS("Watch Per Line", buf_data[i] + 64, EDIT_MENU_WATCH_PER_LINE);
|
|
|
|
/* ##### WATCH ADD VALUE ##### */
|
|
if(EXTRACT_FIELD(traverse->original_data, WatchAddValue) < 0)
|
|
sprintf(buf_data[i] + 80, "-%.3d", EXTRACT_FIELD(traverse->original_data, WatchAddValue));
|
|
else
|
|
sprintf(buf_data[i] + 80, "%.3d", EXTRACT_FIELD(traverse->original_data, WatchAddValue));
|
|
ADD_EDIT_MENU_ITEMS("Watch Add Value", buf_data[i] + 80, EDIT_MENU_WATCH_ADD_VALUE);
|
|
|
|
/* ##### WATCH FORMAT ##### */
|
|
ADD_EDIT_MENU_ITEMS("Watch Format", kWatchDisplayTypeStringList[(EXTRACT_FIELD(traverse->type, TypeParameter) >> 0) & 0x03], EDIT_MENU_WATCH_FORMAT);
|
|
|
|
/* ##### WATCH LABEL ##### */
|
|
ADD_EDIT_MENU_ITEMS("Watch Label", EXTRACT_FIELD(traverse->type, TypeParameter) >> 2 & 0x01 ? "On" : "Off", EDIT_MENU_WATCH_LABEL);
|
|
|
|
/* ##### USER SELECT ##### */
|
|
ADD_EDIT_MENU_ITEMS("User Select", TEST_FIELD(traverse->type, UserSelectEnable) ? "On" : "Off", EDIT_MENU_USER_SELECT);
|
|
|
|
/* ##### USER SELECT MINIMUM DISPLAY ##### */
|
|
ADD_EDIT_MENU_ITEMS("Minimum Display", TEST_FIELD(traverse->type, UserSelectMinimumDisplay) ? "1" : "0", EDIT_MENU_USER_SELECT_MINIMUM_DISP);
|
|
|
|
/* ##### USER SELECT MINIMUM ##### */
|
|
ADD_EDIT_MENU_ITEMS("Minimum Value", TEST_FIELD(traverse->type, UserSelectMinimum) ? "1" : "0", EDIT_MENU_USER_SELECT_MINIMUM);
|
|
|
|
/* ##### USER SELECT BCD ##### */
|
|
ADD_EDIT_MENU_ITEMS("BCD", TEST_FIELD(traverse->type, UserSelectBCD) ? "On" : "Off", EDIT_MENU_USER_SELECT_BCD);
|
|
|
|
/* ##### PREFILL ##### */
|
|
ADD_EDIT_MENU_ITEMS("Prefill", PREFILL_NAMES[EXTRACT_FIELD(traverse->type, Prefill)], EDIT_MENU_PREFILL);
|
|
|
|
/* ##### BYTE LENGTH ##### */
|
|
ADD_EDIT_MENU_ITEMS("Byte Length", kByteSizeStringList[EXTRACT_FIELD(traverse->type, BytesUsed)], EDIT_MENU_BYTES_LENGTH);
|
|
|
|
/* ##### LOCATION ##### */
|
|
if(EXTRACT_FIELD(traverse->type, LocationType) == kLocation_Custom)
|
|
ADD_EDIT_MENU_ITEMS("Location", "EEPROM", EDIT_MENU_LOCATION);
|
|
else if(EXTRACT_FIELD(traverse->type, LocationType) == kLocation_HandlerMemory)
|
|
ADD_EDIT_MENU_ITEMS("Location", "Mapped Memory", EDIT_MENU_LOCATION);
|
|
else
|
|
ADD_EDIT_MENU_ITEMS("Location", LOCATION_NAMES[EXTRACT_FIELD(traverse->type, LocationType)], EDIT_MENU_LOCATION);
|
|
|
|
/* ##### CPU/REGION ##### */
|
|
ADD_EDIT_MENU_ITEMS( EXTRACT_FIELD(traverse->type, LocationType) != kLocation_MemoryRegion ?
|
|
"CPU" : "Region",
|
|
EXTRACT_FIELD(traverse->type, LocationType) != kLocation_MemoryRegion ?
|
|
kNumbersTable[EXTRACT_FIELD(traverse->type, LocationParameterCPU)] : kRegionNames[EXTRACT_FIELD(traverse->type, LocationParameter) + 1],
|
|
EDIT_MENU_REGION);
|
|
|
|
/* ##### PACKED SIZE ##### */
|
|
ADD_EDIT_MENU_ITEMS("Packed Size", kByteSizeStringList[EXTRACT_FIELD(traverse->type, IndexBytesUsed)], EDIT_MENU_PACKED_SIZE);
|
|
|
|
/* ##### ADDRESS INDEX ##### */
|
|
if(traverse->extend_data > SEARCH_BYTE_SIGN_BIT_TABLE[EXTRACT_FIELD(traverse->type, IndexBytesUsed)])
|
|
sprintf(buf_extend_data[i] + 64, "-%.8X", -traverse->extend_data);
|
|
else
|
|
sprintf(buf_extend_data[i] + 64, "%.8X", traverse->extend_data);
|
|
ADD_EDIT_MENU_ITEMS("Index", buf_extend_data[i] + 64, EDIT_MENU_ADDRESS_INDEX);
|
|
|
|
/* ##### ADDRESS ##### */
|
|
switch(EXTRACT_FIELD(traverse->type, LocationType))
|
|
{
|
|
case kLocation_Standard:
|
|
case kLocation_HandlerMemory:
|
|
case kLocation_MemoryRegion:
|
|
case kLocation_IndirectIndexed:
|
|
{
|
|
cpu_region_info *info = get_cpu_info(0);
|
|
menu_item_info[total].extra_data = info->address_mask;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
menu_item_info[total].extra_data = ~0;
|
|
break;
|
|
}
|
|
sprintf(buf_address[i], "%.*X", get_address_length(EXTRACT_FIELD(traverse->type, LocationParameterCPU)), traverse->address);
|
|
ADD_EDIT_MENU_ITEMS("Address", buf_address[i], EDIT_MENU_ADDRESS);
|
|
|
|
/* NOTE : ignore final sepeartor between final and return items */
|
|
if(i < entry->action_list_length - 1)
|
|
ADD_EDIT_MENU_ITEMS(MENU_SEPARATOR_ITEM, NULL, EDIT_MENU_SEPARATOR);
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
ADD_EDIT_MENU_ITEMS("Return to Prior Menu", NULL, EDIT_MENU_RETURN);
|
|
|
|
/* ##### TERMINATOR ##### */
|
|
TERMINATE_MENU_ITEMS(EDIT_MENU_MAX);
|
|
#undef ADD_EDIT_MENU_ITEMS
|
|
|
|
/* adjust cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
if(menu_item_info[menu->sel].field_type == EDIT_MENU_SEPARATOR) menu->sel++;
|
|
|
|
info = &menu_item_info[menu->sel];
|
|
action = &entry->action_list[info->sub_cheat];
|
|
|
|
/* higlighted sub-item if edit mode */
|
|
if(edit_active) flag_buf[menu->sel] = 1;
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, menu_sub_item, flag_buf, menu->sel, 0);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
|
|
if(menu_item_info[menu->sel].field_type == EDIT_MENU_SEPARATOR) menu->sel--;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
|
|
if(menu_item_info[menu->sel].field_type == EDIT_MENU_SEPARATOR) menu->sel++;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
|
|
if(menu_item_info[menu->sel].field_type == EDIT_MENU_SEPARATOR) menu->sel++;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
|
|
if(menu_item_info[menu->sel].field_type == EDIT_MENU_SEPARATOR) menu->sel--;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
do_select = 1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
do_select = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(edit_active)
|
|
edit_active = 0;
|
|
else
|
|
{
|
|
switch(info->field_type)
|
|
{
|
|
case EDIT_MENU_ONE_SHOT: TOGGLE_MASK_FIELD(action->type, OneShot); dirty = 1; break;
|
|
case EDIT_MENU_RESTORE_VALUE: TOGGLE_MASK_FIELD(action->type, RestorePreviousValue); dirty = 1; break;
|
|
case EDIT_MENU_USER_SELECT: TOGGLE_MASK_FIELD(action->type, UserSelectEnable); dirty = 1; break;
|
|
case EDIT_MENU_USER_SELECT_MINIMUM_DISP: TOGGLE_MASK_FIELD(action->type, UserSelectMinimumDisplay); dirty = 1; break;
|
|
case EDIT_MENU_USER_SELECT_MINIMUM: TOGGLE_MASK_FIELD(action->type, UserSelectMinimum); dirty = 1; break;
|
|
case EDIT_MENU_USER_SELECT_BCD: TOGGLE_MASK_FIELD(action->type, UserSelectBCD); dirty = 1; break;
|
|
case EDIT_MENU_RETURN: menu->sel = -1; break;
|
|
default: edit_active = 1; break;
|
|
}
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT))
|
|
{
|
|
add_action_before(entry, info->sub_cheat);
|
|
|
|
entry->action_list[info->sub_cheat].extend_data = ~0;
|
|
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
/* set link option */
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
if(i == 0) CLEAR_MASK_FIELD(action->type, LinkEnable);
|
|
else SET_MASK_FIELD(action->type, LinkEnable);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
{
|
|
delete_action_at(entry, info->sub_cheat);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_WATCH_VALUE))
|
|
{
|
|
watch_cheat_entry(entry, 0);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
if(edit_active) edit_active = 0;
|
|
else menu->sel = -1;
|
|
}
|
|
|
|
if(do_select)
|
|
{
|
|
switch(info->field_type)
|
|
{
|
|
case EDIT_MENU_ONE_SHOT: TOGGLE_MASK_FIELD(action->type, OneShot); break;
|
|
case EDIT_MENU_RESTORE_VALUE: TOGGLE_MASK_FIELD(action->type, RestorePreviousValue); break;
|
|
case EDIT_MENU_USER_SELECT: TOGGLE_MASK_FIELD(action->type, UserSelectEnable); break;
|
|
case EDIT_MENU_USER_SELECT_MINIMUM_DISP: TOGGLE_MASK_FIELD(action->type, UserSelectMinimumDisplay); break;
|
|
case EDIT_MENU_USER_SELECT_MINIMUM: TOGGLE_MASK_FIELD(action->type, UserSelectMinimum); break;
|
|
case EDIT_MENU_USER_SELECT_BCD: TOGGLE_MASK_FIELD(action->type, UserSelectBCD); break;
|
|
case EDIT_MENU_WRITE_MASK: action->extend_data = action->extend_data + do_select; break;
|
|
case EDIT_MENU_DATA: action->original_data = (action->original_data + do_select) &
|
|
BYTE_MASK_TABLE[EXTRACT_FIELD(action->type, BytesUsed)]; break;
|
|
case EDIT_MENU_ADDRESS: action->address = (action->address + do_select) &
|
|
BYTE_MASK_TABLE[EXTRACT_FIELD(action->type, BytesUsed)]; break;
|
|
}
|
|
|
|
dirty = 1;
|
|
}
|
|
|
|
if(dirty)
|
|
{
|
|
update_cheat_info(machine, entry, 0);
|
|
entry->flags |= kCheatFlag_Dirty;
|
|
}
|
|
|
|
/* free astring for activation key */
|
|
astring_free(key_strings);
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------
|
|
view_cheat_menu - management for code viewer for new format
|
|
--------------------------------------------------------------*/
|
|
|
|
static int view_cheat_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
#define ADD_VIEW_MENU_ITEMS(name, sub_name, type) \
|
|
do { menu_item[total] = name; menu_sub_item[total] = sub_name; menu_item_info[total].field_type = type; total++; }while(0)
|
|
|
|
static const char *const kAddressSpaceNames[] = {
|
|
"Program", "Data Space", "I/O Space", "Opcode RAM", "Mapped Memory", "Direct Memory", "EEPROM" };
|
|
|
|
static const char *const kCodeTypeNames[] = {
|
|
"Write", "IWrite", "RWrite", "CWrite", "CBit", "PDWWrite", "Move", "Branch", "Loop", "Popup", "Watch" };
|
|
|
|
static const char *const kCustomCodeTypeNames[] = {
|
|
"NOP", "Comment", "Separator", "Label Select", "Layer Tag",
|
|
"Unused 1", "Unused2", "Unused 3",
|
|
/* NOTE : the following command codes should be removed when database is loaded */
|
|
"Activation Key 1", "Activation Key 2", "Pre-enable", "Overclock", "Refresh Rate" };
|
|
|
|
static const char *const kIWriteParameterNames[] = {
|
|
"Write", "Bit Set", "Bit Clear", "Limited Mask" };
|
|
|
|
static const char *const kCBitParameterNames[] = {
|
|
"Bit Set", "Bit Clear", "Limited Mask" };
|
|
|
|
static const char *const kConditionNames[] = {
|
|
"Equal", "Not Equal", "Less", "Less or Equal", "Greater", "Greater or Equal", "Bit Set", "Bit Clear",
|
|
"Unused 1", "Unused 2", "Unused 3", "Unused 4",
|
|
"Previous Value", "Key Pressed", "Key Hold", "TRUE" };
|
|
|
|
static const char *const kDataNames[] = {
|
|
"Data", "Data", "Data", "Data", "Bit", "1st Data", "Add Value", "Jump Index", "-----", "-----", "-----" };
|
|
|
|
static const char *const kPopupOptionNames[] = {
|
|
"Label", "Value", "Label + Value", "Value + Label" };
|
|
|
|
enum{
|
|
kViewMenu_Header = 1, /* format : [index / total] */
|
|
kViewMenu_InternalIndex, /* layer index and link level (UNEDITABLE) */
|
|
kViewMenu_Name, /* master code = entry->name, linked code = action->optionalName */
|
|
kViewMenu_Comment,
|
|
kViewMenu_ActivationKey1,
|
|
kViewMenu_ActivationKey2,
|
|
/* if(CustomCode == 0) */
|
|
kViewMenu_CPURegion, /* add address space if CPU region */
|
|
kViewMenu_CodeType,
|
|
/* if(CodeType == IWrite) */
|
|
kViewMenu_IWriteParameter,
|
|
/* if(CodeType == CWrite, CBit, Branch, Popup) */
|
|
kViewMenu_Condition,
|
|
/* if(CodeType == CBit) */
|
|
kViewMenu_CBitParameter,
|
|
kViewMenu_CBitCondition,
|
|
/* if(CodeType == Watch) */
|
|
kViewMenu_WatchParameter,
|
|
/* if(CodeType == Popup) */
|
|
kViewMenu_PopupParameter,
|
|
/* if(CodeType == RWrite, CWrite, CBit, Branch, Popup */
|
|
kViewMenu_Extend,
|
|
kViewMenu_Address,
|
|
kViewMenu_AddressSize,
|
|
/* if(CodeType == IWrite, Move) */
|
|
kViewMenu_IndexOffset,
|
|
kViewMenu_IndexAddressSize,
|
|
/* if(CodeType == Move) */
|
|
kViewMenu_MoveParameter, /* variable 0-3 */
|
|
kViewMenu_Data,
|
|
/* if(LimitedMask) */
|
|
kViewMenu_LimitedMask, /* for IWrite, CBit */
|
|
/* if(CodeType == PDWWRite) */
|
|
kViewMenu_SubData,
|
|
kViewMenu_SubDataSize,
|
|
/* if(ValueSelect) */
|
|
kViewMenu_ValueSelectOptions,
|
|
kViewMenu_Options, /* One-shot, Delay, Return, Prefill, RestoreValue */
|
|
/* if(CustomCode) */
|
|
/* if(LayerIndex) */
|
|
kViewMenu_LayerDisplayLevel,
|
|
kViewMenu_LayerSetLevel,
|
|
kViewMenu_LayerSetLength,
|
|
/* if(LabelSelect) */
|
|
kViewMenu_LabelSelector,
|
|
kViewMenu_LabelSelectorQuickClose,
|
|
kViewMenu_Return,
|
|
kViewMenu_Max };
|
|
|
|
int total = 0;
|
|
static int page_index = 0;
|
|
INT8 code_type = 0;
|
|
INT8 address_length = 0;
|
|
INT8 address_size = 0;
|
|
INT8 request_arrow = 0;
|
|
INT8 do_edit = 0;
|
|
INT8 do_increment = 0;
|
|
INT8 do_update = 0;
|
|
const char **menu_item;
|
|
const char **menu_sub_item;
|
|
char *flag_buf;
|
|
char *header;
|
|
char *buf_code;
|
|
char *buf_type;
|
|
char *buf_cpu;
|
|
char *buf_address;
|
|
char *buf_size;
|
|
char *buf_sub_size;
|
|
char *buf_data;
|
|
char *buf_extend;
|
|
char *buf_limited_mask;
|
|
char *buf_options;
|
|
char *buf_code_type_options;
|
|
cheat_menu_item_info
|
|
*menu_info = NULL;
|
|
cpu_region_info *cpu_info = NULL;
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
cheat_action *action = NULL;
|
|
astring *activation_key_string = NULL;
|
|
astring *activation_sub_key_string = NULL;
|
|
|
|
/* first setting : forced set page as 0 when first open */
|
|
if(menu->first_time)
|
|
{
|
|
page_index = 0;
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
action = &entry->action_list[page_index];
|
|
cpu_info = get_cpu_or_region_info(action->region);
|
|
code_type = EXTRACT_FIELD(action->type, CodeType);
|
|
address_length = get_address_length(action->region);
|
|
address_size = EXTRACT_FIELD(action->type, AddressSize);
|
|
|
|
/* required items = (total items + return + terminator) + (strings buf * 12) + 32 characters */
|
|
request_strings(kViewMenu_Max + 2, 12, 32, 0);
|
|
menu_item = menu_strings.main_list;
|
|
menu_sub_item = menu_strings.sub_list;
|
|
flag_buf = menu_strings.flag_list;
|
|
header = menu_strings.main_strings[0];
|
|
buf_code = menu_strings.main_strings[1];
|
|
buf_type = menu_strings.main_strings[1];
|
|
buf_cpu = menu_strings.main_strings[3];
|
|
buf_address = menu_strings.main_strings[4];
|
|
buf_size = menu_strings.main_strings[5];
|
|
buf_sub_size = menu_strings.main_strings[6];
|
|
buf_data = menu_strings.main_strings[7];
|
|
buf_extend = menu_strings.main_strings[8];
|
|
buf_limited_mask = menu_strings.main_strings[9];
|
|
buf_options = menu_strings.main_strings[10];
|
|
buf_code_type_options = menu_strings.main_strings[11];
|
|
|
|
memset(flag_buf, 0, kViewMenu_Max + 2);
|
|
|
|
/* allocate memory for menu item info */
|
|
resize_menu_item_info(kViewMenu_Max + 2);
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### HEADER ##### */
|
|
sprintf(header, "%2.2d/%2.2d", page_index + 1, entry->action_list_length);
|
|
ADD_VIEW_MENU_ITEMS("Page", header, kViewMenu_Header);
|
|
|
|
/* ##### LAYER INDEX ##### */
|
|
sprintf(buf_code, "%2.2X", entry->layer_index);
|
|
ADD_VIEW_MENU_ITEMS("Layer Index", buf_code, kViewMenu_InternalIndex);
|
|
|
|
/* ##### NAME ##### */
|
|
if(entry->name)
|
|
{
|
|
/* NOTE : master code is from cheat entry and others are from cheat action */
|
|
ADD_VIEW_MENU_ITEMS("Name", page_index ? action->optional_name : entry->name, kViewMenu_Name);
|
|
}
|
|
else
|
|
ADD_VIEW_MENU_ITEMS("Name", "< none >", kViewMenu_Name);
|
|
|
|
/* ##### COMMENT ##### */
|
|
if(page_index == 0 && entry->comment)
|
|
ADD_VIEW_MENU_ITEMS("Comment", entry->comment, kViewMenu_Comment);
|
|
|
|
/* ##### ACTIVATION KEY ##### */
|
|
if(entry->flags & kCheatFlag_Select)
|
|
{
|
|
if(entry->activation_key)
|
|
{
|
|
activation_key_string = astring_alloc();
|
|
ADD_VIEW_MENU_ITEMS("Activation Key - Prev", astring_c(input_code_name(activation_key_string, entry->activation_key)), kViewMenu_ActivationKey1);
|
|
}
|
|
|
|
if(entry->activation_sub_key)
|
|
{
|
|
activation_sub_key_string = astring_alloc();
|
|
ADD_VIEW_MENU_ITEMS("Activation Key - Next", astring_c(input_code_name(activation_sub_key_string, entry->activation_sub_key)), kViewMenu_ActivationKey2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(entry->activation_key)
|
|
{
|
|
activation_key_string = astring_alloc();
|
|
ADD_VIEW_MENU_ITEMS("Activation Key", astring_c(input_code_name(activation_key_string, entry->activation_key)), kViewMenu_ActivationKey1);
|
|
}
|
|
}
|
|
|
|
/* ##### CPU/REGION ##### */
|
|
if((action->flags & kActionFlag_Custom) == 0)
|
|
{
|
|
if(action->region < REGION_INVALID)
|
|
{
|
|
/* cpu region */
|
|
sprintf(buf_cpu, "%s (%s)", kRegionNames[EXTRACT_FIELD(action->region, CPUIndex) + 1], kAddressSpaceNames[EXTRACT_FIELD(action->region, AddressSpace)]);
|
|
ADD_VIEW_MENU_ITEMS("CPU", buf_cpu, kViewMenu_CPURegion);
|
|
}
|
|
else
|
|
/* non-cpu region */
|
|
ADD_VIEW_MENU_ITEMS("Region", kRegionNames[action->region - REGION_INVALID], kViewMenu_CPURegion);
|
|
}
|
|
|
|
/* ##### CODE TYPE ##### */
|
|
if(action->flags & kActionFlag_Custom)
|
|
ADD_VIEW_MENU_ITEMS("Custom Type", kCustomCodeTypeNames[action->region - CUSTOM_CODE], kViewMenu_CodeType);
|
|
else
|
|
ADD_VIEW_MENU_ITEMS("Code Type", kCodeTypeNames[code_type], kViewMenu_CodeType);
|
|
|
|
if((action->flags & kActionFlag_Custom) == 0)
|
|
{
|
|
/* ##### CODE PARAMETER ##### */
|
|
if(code_type == kCodeType_IWrite)
|
|
{
|
|
/* writing parameter */
|
|
ADD_VIEW_MENU_ITEMS("Parameter", kIWriteParameterNames[EXTRACT_FIELD(action->type, CodeParameterUpper)], kViewMenu_IWriteParameter);
|
|
}
|
|
|
|
if(code_type == kCodeType_RWrite)
|
|
{
|
|
/* repeat parameter */
|
|
sprintf(buf_extend, "%4.4X / %4.4X",
|
|
EXTRACT_FIELD(action->extend_data, LSB16),
|
|
EXTRACT_FIELD(action->extend_data, MSB16));
|
|
ADD_VIEW_MENU_ITEMS("Count / Skip", buf_extend, kViewMenu_Extend);
|
|
}
|
|
|
|
if(action->flags & kActionFlag_CheckCondition)
|
|
{
|
|
if(code_type == kCodeType_CBit)
|
|
{
|
|
/* bit parameter for CBit */
|
|
ADD_VIEW_MENU_ITEMS("Parameter", kCBitParameterNames[EXTRACT_FIELD(action->type, CodeParameterUpper)], kViewMenu_CBitParameter);
|
|
|
|
/* bit condition for CBit */
|
|
ADD_VIEW_MENU_ITEMS("Condition", BIT_SET_CLEAR_NAMES[EXTRACT_FIELD(action->type, CodeParameterLower)], kViewMenu_CBitCondition);
|
|
|
|
}
|
|
else
|
|
{
|
|
/* condition for CWrite, Branch, Popup */
|
|
ADD_VIEW_MENU_ITEMS("Condition", kConditionNames[EXTRACT_FIELD(action->type, CodeParameter)], kViewMenu_Condition);
|
|
}
|
|
|
|
if(EXTRACT_FIELD(action->type, CodeParameter) != kCondition_PreviousValue)
|
|
{
|
|
sprintf(buf_extend, "%*.*X", BYTE_DIGITS_TABLE[address_size], BYTE_DIGITS_TABLE[address_size], action->extend_data);
|
|
ADD_VIEW_MENU_ITEMS("Comparison", buf_extend, kViewMenu_Extend);
|
|
}
|
|
}
|
|
|
|
if(code_type == kCodeType_Popup)
|
|
{
|
|
/* popup parameter */
|
|
ADD_VIEW_MENU_ITEMS("Parameter", kPopupOptionNames[EXTRACT_FIELD(action->type, PopupParameter)], kViewMenu_PopupParameter);
|
|
}
|
|
|
|
/* ##### ADDRESS ##### */
|
|
switch(EXTRACT_FIELD(action->type, AddressRead))
|
|
{
|
|
case kReadFrom_Address:
|
|
{
|
|
char *buf_strings = buf_address;
|
|
|
|
if(edit_active && menu->sel == total)
|
|
buf_strings = create_strings_with_edit_cursor(buf_strings, action->original_address, address_length - 1, edit_cursor);
|
|
else
|
|
buf_strings += sprintf(buf_strings, "%*.*X", address_length, address_length, action->original_address);
|
|
}
|
|
break;
|
|
|
|
case kReadFrom_Index:
|
|
sprintf(buf_address, "(V%s)", kNumbersTable[action->original_address]);
|
|
break;
|
|
|
|
case kReadFrom_Variable:
|
|
sprintf(buf_address, "V%s", kNumbersTable[action->original_address]);
|
|
}
|
|
|
|
ADD_VIEW_MENU_ITEMS("Address", buf_address, kViewMenu_Address);
|
|
|
|
/* ##### SIZE ##### */
|
|
sprintf(buf_size, "%s", kByteSizeStringList[address_size]);
|
|
ADD_VIEW_MENU_ITEMS("Size", buf_size, kViewMenu_AddressSize);
|
|
|
|
/* ##### INDEX ##### */
|
|
if(action->flags & kActionFlag_IndexAddress)
|
|
{
|
|
/* index offset for IWrite, Move */
|
|
sprintf(buf_extend, "%*.*X", address_length, address_length, action->extend_data);
|
|
ADD_VIEW_MENU_ITEMS("Index Offset", buf_extend, kViewMenu_IndexOffset);
|
|
|
|
/* index size for IWrite, Move */
|
|
sprintf(buf_sub_size, "%s", kByteSizeStringList[EXTRACT_FIELD(action->type, CodeParameterLower)]);
|
|
ADD_VIEW_MENU_ITEMS("Index Size", buf_sub_size, kViewMenu_IndexAddressSize);
|
|
}
|
|
|
|
/* ##### DESTINATION ##### */
|
|
if(code_type == kCodeType_Move)
|
|
{
|
|
sprintf(buf_type, "%s", kNumbersTable[EXTRACT_FIELD(action->type, CodeParameterUpper)]);
|
|
ADD_VIEW_MENU_ITEMS("Destination", buf_type, kViewMenu_MoveParameter);
|
|
}
|
|
|
|
/* ##### DATA ##### */
|
|
if(action->flags & kActionFlag_MemoryWrite)
|
|
{
|
|
int count = BYTE_LOOP_TABLE[address_size];
|
|
int display_data = action->original_data;
|
|
char *buf_strings = buf_data;
|
|
|
|
if(action->flags & kActionFlag_LimitedMask)
|
|
{
|
|
if(TEST_FIELD(action->type, DataRead))
|
|
display_data = EXTRACT_FIELD(action->original_data, MSB16);
|
|
}
|
|
|
|
if(TEST_FIELD(action->type, DataRead))
|
|
{
|
|
count = 0;
|
|
buf_strings += sprintf(buf_strings, "V");
|
|
}
|
|
|
|
if(edit_active && menu->sel == total)
|
|
buf_strings = create_strings_with_edit_cursor(buf_strings, display_data, count, edit_cursor);
|
|
else
|
|
buf_strings += sprintf(buf_strings, "%*.*X", BYTE_DIGITS_TABLE[address_size], BYTE_DIGITS_TABLE[address_size], display_data);
|
|
|
|
ADD_VIEW_MENU_ITEMS(kDataNames[EXTRACT_FIELD(action->type, CodeType)], buf_data, kViewMenu_Data);
|
|
}
|
|
|
|
/* ##### MASK ##### */
|
|
if(code_type == kCodeType_Write)
|
|
{
|
|
sprintf(buf_extend, "%*.*X", address_size, address_size, action->extend_data);
|
|
ADD_VIEW_MENU_ITEMS("Mask", buf_extend, kViewMenu_Extend);
|
|
}
|
|
else if(action->flags & kActionFlag_LimitedMask)
|
|
{
|
|
/* NOTE : mask is lower 2 bytes from data field in case of limited mask */
|
|
sprintf(buf_limited_mask, "%*.*X", address_size, address_size, EXTRACT_FIELD(action->original_data, LSB16));
|
|
ADD_VIEW_MENU_ITEMS("Mask", buf_limited_mask, kViewMenu_LimitedMask);
|
|
}
|
|
|
|
/* ##### SUB DATA ##### */
|
|
if(code_type == kCodeType_PDWWrite)
|
|
{
|
|
/* 2nd data */
|
|
sprintf(buf_extend, "%*.*X",
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, CodeParameterLower)],
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, CodeParameterLower)],
|
|
action->extend_data);
|
|
ADD_VIEW_MENU_ITEMS("2nd Data", buf_extend, kViewMenu_Extend);
|
|
|
|
/* 2nd data size */
|
|
sprintf(buf_sub_size, "%s", kByteSizeStringList[EXTRACT_FIELD(action->type, CodeParameterLower)]);
|
|
ADD_VIEW_MENU_ITEMS("2nd Data Size", buf_sub_size, kViewMenu_SubDataSize);
|
|
}
|
|
|
|
/* ##### JUMP INDEX ##### */
|
|
if(code_type == kCodeType_Branch)
|
|
{
|
|
/* jump index for branch */
|
|
sprintf(buf_extend, "%2.2d", action->original_data + 1);
|
|
ADD_VIEW_MENU_ITEMS("Jump Index", buf_extend, kViewMenu_Extend);
|
|
}
|
|
|
|
/* ##### OPTIONS ##### */
|
|
sprintf(buf_options, "%s %s %s %s %s",
|
|
TEST_FIELD(action->type, OneShot) ? "One" : "-",
|
|
TEST_FIELD(action->type, DelayEnable) ? "Del" : "-",
|
|
TEST_FIELD(action->type, PrefillEnable) ? "Pre" : "-",
|
|
TEST_FIELD(action->type, Return) ? "Ret" : "-",
|
|
TEST_FIELD(action->type, RestoreValue) ? "Rst" : "-");
|
|
ADD_VIEW_MENU_ITEMS("Options", buf_options, kViewMenu_Options);
|
|
|
|
/* ##### CODE TYPE OPTIONS ##### */
|
|
if(TEST_FIELD(action->type, ValueSelectEnable))
|
|
{
|
|
sprintf(buf_code_type_options, "%s %s %s %s",
|
|
TEST_FIELD(action->type, ValueSelectMinimumDisplay) ? "MinD" : "-",
|
|
TEST_FIELD(action->type, ValueSelectMinimum) ? "Min" : "-",
|
|
TEST_FIELD(action->type, ValueSelectBCD) ? "BCD" : "-",
|
|
TEST_FIELD(action->type, ValueSelectNegative) ? "Neg" : "-");
|
|
ADD_VIEW_MENU_ITEMS("Value Select Options", buf_code_type_options, kViewMenu_ValueSelectOptions);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* ##### CUSTOM CODE PARAMETER ##### */
|
|
if(action->region == CUSTOM_CODE_LAYER_TAG)
|
|
{
|
|
/* ##### LAYER TAG ##### */
|
|
sprintf(buf_address, "%2.2X", action->original_address);
|
|
ADD_VIEW_MENU_ITEMS("Display Level", buf_address, kViewMenu_LayerDisplayLevel);
|
|
|
|
sprintf(buf_data, "%2.2X", action->original_data);
|
|
ADD_VIEW_MENU_ITEMS("Set Level", buf_data, kViewMenu_LayerSetLevel);
|
|
|
|
sprintf(buf_extend, "%2.2X", action->extend_data);
|
|
ADD_VIEW_MENU_ITEMS("Set Length", buf_extend, kViewMenu_LayerSetLength);
|
|
}
|
|
|
|
if(action->region == CUSTOM_CODE_LABEL_SELECT)
|
|
{
|
|
/* ##### LABEL SELECTOR ##### */
|
|
ADD_VIEW_MENU_ITEMS("Label Selector", TEST_FIELD(action->type, LabelSelectUseSelector) ? "On" : "Off", kViewMenu_LabelSelector);
|
|
|
|
/* ##### QUICK MENU CLOSE ##### */
|
|
ADD_VIEW_MENU_ITEMS("Quick Selector Close", TEST_FIELD(action->type, LabelSelectQuickClose) ? "On" : "Off", kViewMenu_LabelSelectorQuickClose);
|
|
}
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
ADD_VIEW_MENU_ITEMS("Return to Prior Menu", NULL, kViewMenu_Return);
|
|
|
|
/* ##### TERMINATOR ##### */
|
|
TERMINATE_MENU_ITEMS(kViewMenu_Max);
|
|
#undef ADD_VIEW_MENU_ITEMS
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
menu_info = &menu_item_info[menu->sel];
|
|
|
|
switch(menu_info->field_type)
|
|
{
|
|
case kViewMenu_Header:
|
|
if(entry->action_list_length > 1)
|
|
request_arrow = MENU_FLAG_LEFT_ARROW | MENU_FLAG_RIGHT_ARROW;
|
|
break;
|
|
|
|
case kViewMenu_Address:
|
|
case kViewMenu_Data:
|
|
request_arrow = MENU_FLAG_LEFT_ARROW | MENU_FLAG_RIGHT_ARROW;
|
|
break;
|
|
|
|
default:
|
|
request_arrow = 0;
|
|
break;
|
|
}
|
|
|
|
if(edit_active)
|
|
flag_buf[menu->sel] = 1;
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, menu_sub_item, flag_buf, menu->sel, request_arrow);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
do_increment = 1;
|
|
else
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
do_increment = -1;
|
|
else
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
do_edit = edit_active ? 1 : -1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
do_edit = edit_active ? -1 : 1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active == 0)
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active == 0)
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(edit_active)
|
|
edit_active = 0;
|
|
else
|
|
{
|
|
switch(menu_info->field_type)
|
|
{
|
|
case kViewMenu_Address:
|
|
case kViewMenu_Data:
|
|
edit_active = 1;
|
|
edit_cursor = 0;
|
|
break;
|
|
|
|
case kViewMenu_Return:
|
|
menu->sel = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT))
|
|
{
|
|
save_cheat_code(machine, entry);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_WATCH_VALUE))
|
|
{
|
|
watch_cheat_entry(entry, 0);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
if(edit_active) edit_active = 0;
|
|
else menu->sel = -1;
|
|
}
|
|
|
|
if(do_edit)
|
|
{
|
|
if(edit_active)
|
|
{
|
|
edit_cursor += do_edit;
|
|
|
|
switch(menu_info->field_type)
|
|
{
|
|
case kViewMenu_Address:
|
|
if(edit_cursor < 0) edit_cursor = address_length - 1;
|
|
else if(edit_cursor > address_length - 1) edit_cursor = 0;
|
|
break;
|
|
|
|
case kViewMenu_Data:
|
|
if(edit_cursor < 0) edit_cursor = BYTE_DIGITS_TABLE[address_size];
|
|
else if(edit_cursor >= BYTE_DIGITS_TABLE[address_size]) edit_cursor = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(menu_info->field_type)
|
|
{
|
|
case kViewMenu_Header:
|
|
page_index += do_edit;
|
|
if(page_index < 0) page_index = entry->action_list_length - 1;
|
|
else if(page_index > entry->action_list_length - 1) page_index = 0;
|
|
break;
|
|
|
|
case kViewMenu_Address:
|
|
action->original_address += do_edit;
|
|
action->original_address &= cpu_info->address_mask;
|
|
do_update = 1;
|
|
break;
|
|
|
|
case kViewMenu_Data:
|
|
action->original_data += do_edit;
|
|
action->original_data &= BYTE_MASK_TABLE[address_size];
|
|
do_update = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(do_increment)
|
|
{
|
|
switch(menu_info->field_type)
|
|
{
|
|
case kViewMenu_Address:
|
|
action->original_address = do_increment == 1 ? do_increment_hex_field(action->original_address, edit_cursor) :
|
|
do_decrement_hex_field(action->original_address, edit_cursor);
|
|
action->original_address &= cpu_info->address_mask;
|
|
action->address = action->original_address;
|
|
do_update = 1;
|
|
break;
|
|
|
|
case kViewMenu_Data:
|
|
action->original_data = do_increment == 1 ? do_increment_hex_field(action->original_data, edit_cursor) :
|
|
do_decrement_hex_field(action->original_data, edit_cursor);
|
|
action->data &= BYTE_MASK_TABLE[address_size];
|
|
action->data = action->original_data;
|
|
do_update = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(do_update) update_cheat_info(machine, entry, 0);
|
|
if(activation_key_string) astring_free(activation_key_string);
|
|
if(activation_sub_key_string) astring_free(activation_sub_key_string);
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------
|
|
analyse_cheat_menu - management for code analizer menu
|
|
---------------------------------------------------------*/
|
|
|
|
static int analyse_cheat_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
static const char *const FORMAT_ERROR_MESSAGE_TABLE[] = {
|
|
"Invalid Location Type",
|
|
"Invalid Operation",
|
|
"Invalid Code Type",
|
|
"Invalid Condition",
|
|
"Invalid Code Option",
|
|
"Relative Address conflicts other operations",
|
|
"Maximum range is smaller than minimum",
|
|
"Missing Restore Previous Value flag",
|
|
"Missing label link code",
|
|
"Both Value and Label Select are defined",
|
|
"Invalid Data Field",
|
|
"Invalid Extend Data Field",
|
|
"Don't set Variable in this type",
|
|
"Value Select can't select any value",
|
|
"Limited Mask is over length",
|
|
"RWrite doesn't have counter",
|
|
"Invalid Address Read",
|
|
"Invalid Variable in address field",
|
|
"Invalid Variable in extend data field",
|
|
"CPU/Region is out of range",
|
|
"Invalid CPU/Region number",
|
|
"Invalid Address Space",
|
|
"An address is out of range",
|
|
"Invalid Custom Code" };
|
|
|
|
int i, j;
|
|
int total = 0;
|
|
UINT8 is_edit = 0;
|
|
const char **menu_item;
|
|
cheat_entry *entry = &cheat_list[menu->pre_sel];
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/* required items = ((items + header + 2 separators) * total_actions) + edit + return + terminator) */
|
|
request_strings(((kErrorFlag_Max + 3) * entry->action_list_length) + 3, 0, 0, 0);
|
|
menu_item = menu_strings.main_list;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
UINT32 flags = analyse_code_format(machine, entry, action);
|
|
|
|
menu_item[total++] = action->optional_name ? action->optional_name : "(Null)";
|
|
menu_item[total++] = MENU_SEPARATOR_ITEM;
|
|
|
|
if(flags)
|
|
{
|
|
for(j = 0; j < kErrorFlag_Max; j++)
|
|
{
|
|
if((flags >> j) & 1)
|
|
menu_item[total++] = FORMAT_ERROR_MESSAGE_TABLE[j];
|
|
}
|
|
}
|
|
else
|
|
menu_item[total++] = "No Problem";
|
|
|
|
menu_item[total++] = MENU_SEPARATOR_ITEM;
|
|
}
|
|
|
|
menu_item[total++] = "Edit This Entry";
|
|
menu_item[total++] = "Return to Prior Menu";
|
|
menu_item[total] = NULL;
|
|
|
|
/* adjust cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
old_style_menu(menu_item, NULL, NULL, menu->sel, 0);
|
|
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT))
|
|
{
|
|
is_edit = 1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(menu->sel == total - 2)
|
|
is_edit = 1;
|
|
else
|
|
menu->sel = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
if(is_edit)
|
|
{
|
|
if(entry->flags & kCheatFlag_OldFormat)
|
|
cheat_menu_stack_push(edit_cheat_menu, menu->return_handler, menu->pre_sel);
|
|
else
|
|
cheat_menu_stack_push(view_cheat_menu, menu->return_handler, menu->pre_sel);
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*------------------------------------------------
|
|
search_main_menu - management for search menu
|
|
------------------------------------------------*/
|
|
|
|
static int search_main_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
#define ADD_SEARCH_MENU_ITEMS(name, sub_name, type) \
|
|
do { menu_item[total] = name; menu_sub_item[total] = sub_name; menu_item_info[total].field_type = type; }while(0)
|
|
|
|
enum{
|
|
/* separator */
|
|
SEARCH_MENU_NULL = 0,
|
|
/* for standard and advanced */
|
|
SEARCH_MENU_COMPARISON, SEARCH_MENU_VALUE,
|
|
/* for minimum mode */
|
|
SEARCH_MENU_MINIMUM_ITEMS,
|
|
/* for standard mode */
|
|
SEARCH_MENU_STANDARD_MODE,
|
|
/* for advanced mode */
|
|
SEARCH_MENU_ADVANCED_LHS, SEARCH_MENU_ADVANCED_RHS, SEARCH_MENU_ADVANCED_SIZE, SEARCH_MENU_ADVANCED_SWAP,
|
|
SEARCH_MENU_ADVANCED_SIGN, SEARCH_MENU_ADVANCED_NAME, SEARCH_MENU_ADVANCED_DO_SEARCH,
|
|
/* common items */
|
|
SEARCH_MENU_CPU, SEARCH_MENU_SAVE_MEMORY, SEARCH_MENU_VIEW_RESULT, SEARCH_MENU_RESTORE_SEARCH,
|
|
SEARCH_MENU_RETURN,
|
|
|
|
SEARCH_MENU_MAX = 20 };
|
|
|
|
static const char *const MINIMUM_ITEMS[] = {
|
|
"[ == ] != < > + -", "== [ != ] < > + -", "== != [ < ] > + -", "== != < [ > ] + -", "== != < > [ + ] -", "== != < > + [ - ]" };
|
|
|
|
static const char *const MINIMUM_SUB_ITEMS[] = {
|
|
"Equal", "Not Equal", "Less", "Greater", "Inc.", "Dec." };
|
|
|
|
static const char *const STANDARD_MODE_ITEMS[] = {
|
|
"Current", "Comparison", "Comparison (Slow)", "Value Extraction" };
|
|
|
|
static const char *const OPERAND_NAME_TABLE[] = {
|
|
"Current", "Previous", "First", "Value" };
|
|
|
|
static const char *const COMPARISON_NAME_TABLE[] = {
|
|
"Less", "Greater", "Equal", "Less or Equal", "Greater or Equal", "Not Equal", "Increased by", "Near To" };
|
|
|
|
static const char *const SEARCH_BYTE_NAME_TABLE[] = {
|
|
"1", "2", "3", "4", "Bit" };
|
|
|
|
static const UINT8 SEARCH_MENU_ITEM_TABLE[][SEARCH_MENU_MAX] =
|
|
{
|
|
{ /* minimum mode */
|
|
SEARCH_MENU_CPU, SEARCH_MENU_NULL, SEARCH_MENU_MINIMUM_ITEMS, SEARCH_MENU_NULL,
|
|
SEARCH_MENU_SAVE_MEMORY, SEARCH_MENU_VIEW_RESULT, SEARCH_MENU_RESTORE_SEARCH,
|
|
SEARCH_MENU_RETURN, SEARCH_MENU_MAX
|
|
},
|
|
{ /* standard mode */
|
|
SEARCH_MENU_STANDARD_MODE, SEARCH_MENU_COMPARISON, SEARCH_MENU_VALUE, SEARCH_MENU_NULL,
|
|
SEARCH_MENU_CPU, SEARCH_MENU_VIEW_RESULT, SEARCH_MENU_RESTORE_SEARCH, SEARCH_MENU_SAVE_MEMORY,
|
|
SEARCH_MENU_RETURN, SEARCH_MENU_MAX
|
|
},
|
|
{ /* advanced mode */
|
|
SEARCH_MENU_CPU, SEARCH_MENU_NULL,
|
|
SEARCH_MENU_ADVANCED_LHS, SEARCH_MENU_COMPARISON, SEARCH_MENU_ADVANCED_RHS, SEARCH_MENU_NULL, SEARCH_MENU_VALUE,
|
|
SEARCH_MENU_ADVANCED_SIZE, SEARCH_MENU_ADVANCED_SWAP, SEARCH_MENU_ADVANCED_SIGN, SEARCH_MENU_ADVANCED_NAME, SEARCH_MENU_NULL,
|
|
SEARCH_MENU_ADVANCED_DO_SEARCH, SEARCH_MENU_SAVE_MEMORY, SEARCH_MENU_VIEW_RESULT, SEARCH_MENU_RESTORE_SEARCH,
|
|
SEARCH_MENU_RETURN, SEARCH_MENU_MAX
|
|
}
|
|
};
|
|
|
|
static const UINT8 SEARCH_MINIMUM_CONVERSION_TABLE[] =
|
|
{ kSearchComparison_EqualTo, kSearchComparison_NotEqual, kSearchComparison_LessThan, kSearchComparison_GreaterThan,
|
|
kSearchComparison_IncreasedBy, kSearchComparison_IncreasedBy };
|
|
|
|
UINT8 total = 0;
|
|
UINT8 mode = EXTRACT_FIELD(cheat_options, SearchBox);
|
|
UINT8 is_signed = 0;
|
|
UINT8 is_minus = 0;
|
|
UINT8 request_arrow = MENU_FLAG_LEFT_ARROW | MENU_FLAG_RIGHT_ARROW;
|
|
INT8 do_increment = 0;
|
|
UINT8 do_rebuild = 0;
|
|
UINT8 request_search = 0;
|
|
UINT32 display_value;
|
|
static UINT8 done_memory_save = 0;
|
|
const char *menu_item[SEARCH_MENU_MAX] = { 0 };
|
|
const char *menu_sub_item[SEARCH_MENU_MAX] = { 0 };
|
|
char buf_value[32] = { 0 }; /* advanced and standard only */
|
|
char buf_cpu[32] = { 0 };
|
|
char buf_num_results[32] = { 0 };
|
|
char *buf_strings; /* edit mode only */
|
|
search_info *search = get_current_search();
|
|
cheat_menu_item_info
|
|
*info = NULL;
|
|
|
|
/* first setting : adjust cursor */
|
|
if(menu->first_time)
|
|
{
|
|
if(done_memory_save)
|
|
{
|
|
/* if memory is saved, set cursor to search item */
|
|
switch(mode)
|
|
{
|
|
case SEARCH_BOX_MINIMUM: menu->sel = 2; break;
|
|
case SEARCH_BOX_STANDARD: menu->sel = 0; break;
|
|
case SEARCH_BOX_ADVANCED: menu->sel = 3; break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* if memory is unsaved, set cursor to initialize item */
|
|
switch(mode)
|
|
{
|
|
case SEARCH_BOX_MINIMUM: menu->sel = 4; break;
|
|
case SEARCH_BOX_STANDARD: menu->sel = 7; break;
|
|
case SEARCH_BOX_ADVANCED: menu->sel = 13; break;
|
|
}
|
|
}
|
|
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
/* check status of value */
|
|
if(search->sign || (search->comparison == kSearchComparison_IncreasedBy))
|
|
{
|
|
is_signed = 1;
|
|
|
|
if(search->value & SEARCH_BYTE_SIGN_BIT_TABLE[search->bytes])
|
|
is_minus = 1;
|
|
}
|
|
|
|
/* allocate memory for menu item info */
|
|
resize_menu_item_info(SEARCH_MENU_MAX + 2);
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(total = 0; SEARCH_MENU_ITEM_TABLE[mode][total] != SEARCH_MENU_MAX; total++)
|
|
{
|
|
switch(SEARCH_MENU_ITEM_TABLE[mode][total])
|
|
{
|
|
case SEARCH_MENU_NULL:
|
|
ADD_SEARCH_MENU_ITEMS(MENU_SEPARATOR_ITEM, NULL, SEARCH_MENU_NULL);
|
|
break;
|
|
|
|
case SEARCH_MENU_COMPARISON:
|
|
if(mode == SEARCH_BOX_STANDARD)
|
|
ADD_SEARCH_MENU_ITEMS("Comaprison", COMPARISON_NAME_TABLE[search->comparison], SEARCH_MENU_COMPARISON);
|
|
else
|
|
ADD_SEARCH_MENU_ITEMS( TEST_FIELD(cheat_options, DontPrintNewLabels) ? COMPARISON_NAME_TABLE[search->comparison] : "Comparison",
|
|
TEST_FIELD(cheat_options, DontPrintNewLabels) ? NULL : COMPARISON_NAME_TABLE[search->comparison],
|
|
SEARCH_MENU_COMPARISON);
|
|
break;
|
|
|
|
case SEARCH_MENU_VALUE:
|
|
display_value = search->value;
|
|
buf_strings = buf_value;
|
|
|
|
if(is_signed)
|
|
{
|
|
if(edit_active && edit_cursor == BYTE_DIGITS_TABLE[search->bytes])
|
|
{
|
|
if(is_minus)
|
|
{
|
|
buf_strings += sprintf(buf_strings, "[-]");
|
|
display_value = ~display_value + 1;
|
|
display_value &= SEARCH_BYTE_UNSIGNED_MASK_TABLE[search->bytes];
|
|
}
|
|
else
|
|
buf_strings += sprintf(buf_strings, "[+]");
|
|
}
|
|
else
|
|
{
|
|
if(is_minus)
|
|
{
|
|
buf_strings += sprintf(buf_strings, "-");
|
|
display_value = ~display_value + 1;
|
|
display_value &= SEARCH_BYTE_UNSIGNED_MASK_TABLE[search->bytes];
|
|
}
|
|
else
|
|
buf_strings += sprintf(buf_strings, "+");
|
|
}
|
|
}
|
|
|
|
if(edit_active)
|
|
buf_strings = create_strings_with_edit_cursor(buf_strings, display_value, BYTE_LOOP_TABLE[search->bytes], edit_cursor);
|
|
else
|
|
buf_strings += sprintf(buf_strings, "%.*X", BYTE_DIGITS_TABLE[search->bytes], display_value);
|
|
|
|
if(is_signed)
|
|
{
|
|
if(is_minus)
|
|
buf_strings += sprintf(buf_strings, " (-");
|
|
else
|
|
buf_strings += sprintf(buf_strings, " (+");
|
|
}
|
|
else
|
|
buf_strings += sprintf(buf_strings, " (");
|
|
|
|
buf_strings += sprintf(buf_strings, "%.*d)", BYTE_DEC_DIGITS_TABLE[search->bytes], display_value);
|
|
|
|
if(mode == SEARCH_BOX_STANDARD)
|
|
{
|
|
char buf[10];
|
|
|
|
if(is_signed)
|
|
sprintf(buf, is_minus ? "Decrement" : "Increment");
|
|
else if(search->comparison == kSearchComparison_NearTo)
|
|
sprintf(buf, "== or +1");
|
|
else
|
|
sprintf(buf, "Value");
|
|
|
|
ADD_SEARCH_MENU_ITEMS(buf, buf_value, SEARCH_MENU_VALUE);
|
|
}
|
|
else
|
|
{
|
|
ADD_SEARCH_MENU_ITEMS( TEST_FIELD(cheat_options, DontPrintNewLabels) ? buf_value : "Value",
|
|
TEST_FIELD(cheat_options, DontPrintNewLabels) ? NULL : buf_value,
|
|
SEARCH_MENU_VALUE);
|
|
}
|
|
break;
|
|
|
|
case SEARCH_MENU_MINIMUM_ITEMS:
|
|
ADD_SEARCH_MENU_ITEMS(MINIMUM_ITEMS[search->parameter], MINIMUM_SUB_ITEMS[search->parameter], SEARCH_MENU_MINIMUM_ITEMS);
|
|
break;
|
|
|
|
case SEARCH_MENU_STANDARD_MODE:
|
|
ADD_SEARCH_MENU_ITEMS("Mode", STANDARD_MODE_ITEMS[search->rhs], SEARCH_MENU_STANDARD_MODE);
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_LHS:
|
|
ADD_SEARCH_MENU_ITEMS( TEST_FIELD(cheat_options, DontPrintNewLabels) ? OPERAND_NAME_TABLE[search->lhs] : "LHS",
|
|
TEST_FIELD(cheat_options, DontPrintNewLabels) ? NULL : OPERAND_NAME_TABLE[search->lhs],
|
|
SEARCH_MENU_ADVANCED_LHS);
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_RHS:
|
|
ADD_SEARCH_MENU_ITEMS( TEST_FIELD(cheat_options, DontPrintNewLabels) ? OPERAND_NAME_TABLE[search->rhs] : "RHS",
|
|
TEST_FIELD(cheat_options, DontPrintNewLabels) ? NULL : OPERAND_NAME_TABLE[search->rhs],
|
|
SEARCH_MENU_ADVANCED_RHS);
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_SIZE:
|
|
ADD_SEARCH_MENU_ITEMS("Size", SEARCH_BYTE_NAME_TABLE[search->bytes], SEARCH_MENU_ADVANCED_SIZE);
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_SWAP:
|
|
ADD_SEARCH_MENU_ITEMS("Swap", search->swap ? "On" : "Off", SEARCH_MENU_ADVANCED_SWAP);
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_SIGN:
|
|
ADD_SEARCH_MENU_ITEMS("Signed", search->sign ? "On" : "Off", SEARCH_MENU_ADVANCED_SIGN);
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_NAME:
|
|
ADD_SEARCH_MENU_ITEMS("Name", (search->name && search->name[0] != 0) ? search->name : "(none)", SEARCH_MENU_ADVANCED_NAME);
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_DO_SEARCH:
|
|
ADD_SEARCH_MENU_ITEMS("Do Search", NULL, SEARCH_MENU_ADVANCED_DO_SEARCH);
|
|
break;
|
|
|
|
case SEARCH_MENU_CPU:
|
|
sprintf(buf_cpu, "%d", search->target_idx);
|
|
ADD_SEARCH_MENU_ITEMS("CPU", buf_cpu, SEARCH_MENU_CPU);
|
|
break;
|
|
|
|
case SEARCH_MENU_SAVE_MEMORY:
|
|
ADD_SEARCH_MENU_ITEMS(done_memory_save ? "Save Memory" : "Initialize Memory", NULL, SEARCH_MENU_SAVE_MEMORY);
|
|
break;
|
|
|
|
case SEARCH_MENU_VIEW_RESULT:
|
|
if(search->num_results)
|
|
{
|
|
sprintf(buf_num_results, "%d", search->num_results);
|
|
ADD_SEARCH_MENU_ITEMS("Results", buf_num_results, SEARCH_MENU_VIEW_RESULT);
|
|
}
|
|
else
|
|
ADD_SEARCH_MENU_ITEMS("No Result", NULL, SEARCH_MENU_VIEW_RESULT);
|
|
break;
|
|
|
|
case SEARCH_MENU_RESTORE_SEARCH:
|
|
ADD_SEARCH_MENU_ITEMS("Restore Previous Value", NULL, SEARCH_MENU_RESTORE_SEARCH);
|
|
break;
|
|
|
|
case SEARCH_MENU_RETURN:
|
|
ADD_SEARCH_MENU_ITEMS("Return to Prior Menu", NULL, SEARCH_MENU_RETURN);
|
|
break;
|
|
|
|
default:
|
|
ADD_SEARCH_MENU_ITEMS("UNKNOWN", NULL, SEARCH_MENU_MAX);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ##### TERMINATOR ##### */
|
|
TERMINATE_MENU_ITEMS(SEARCH_MENU_MAX);
|
|
#undef ADD_SEARCH_MENU_ITEMS
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* set current menu item info */
|
|
info = &menu_item_info[menu->sel];
|
|
|
|
/* skip separator */
|
|
if(info->field_type == SEARCH_MENU_NULL)
|
|
menu->sel++;
|
|
|
|
/* set left/right arrow for sub-item */
|
|
if(edit_active == 0)
|
|
{
|
|
switch(info->field_type)
|
|
{
|
|
case SEARCH_MENU_ADVANCED_NAME:
|
|
case SEARCH_MENU_ADVANCED_DO_SEARCH:
|
|
case SEARCH_MENU_SAVE_MEMORY:
|
|
case SEARCH_MENU_VIEW_RESULT:
|
|
case SEARCH_MENU_RESTORE_SEARCH:
|
|
case SEARCH_MENU_RETURN:
|
|
request_arrow = 0;
|
|
}
|
|
}
|
|
else
|
|
request_arrow = 0;
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, menu_sub_item, NULL, menu->sel, request_arrow);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(is_signed == 0)
|
|
search->value = do_increment_hex_field(search->value, edit_cursor);
|
|
else
|
|
{
|
|
if(edit_cursor == BYTE_DIGITS_TABLE[search->bytes])
|
|
search->value = ~search->value + 1;
|
|
else
|
|
search->value = do_increment_hex_field_signed(search->value, edit_cursor, search->bytes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
|
|
if(menu_item_info[menu->sel].field_type == SEARCH_MENU_NULL)
|
|
menu->sel--;
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(is_signed == 0)
|
|
search->value = do_decrement_hex_field(search->value, edit_cursor);
|
|
else
|
|
{
|
|
if(edit_cursor == BYTE_DIGITS_TABLE[search->bytes])
|
|
search->value = ~search->value + 1;
|
|
else
|
|
search->value = do_decrement_hex_field_signed(search->value, edit_cursor, search->bytes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
|
|
if(menu_item_info[menu->sel].field_type == SEARCH_MENU_NULL)
|
|
menu->sel++;
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(is_signed == 0)
|
|
{
|
|
if(++edit_cursor >= BYTE_DIGITS_TABLE[search->bytes])
|
|
edit_cursor = 0;
|
|
}
|
|
else
|
|
{
|
|
if(++edit_cursor > BYTE_DIGITS_TABLE[search->bytes])
|
|
edit_cursor = 0;
|
|
}
|
|
}
|
|
else
|
|
do_increment = -1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
if(is_signed == 0)
|
|
{
|
|
if(--edit_cursor < 0)
|
|
edit_cursor = BYTE_DIGITS_TABLE[search->bytes] - 1;
|
|
}
|
|
else
|
|
{
|
|
if(--edit_cursor < 0)
|
|
edit_cursor = BYTE_DIGITS_TABLE[search->bytes];
|
|
}
|
|
}
|
|
else
|
|
do_increment = 1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
edit_active = 0;
|
|
|
|
if(mode == SEARCH_BOX_STANDARD)
|
|
request_search = 1;
|
|
}
|
|
else
|
|
{
|
|
switch(info->field_type)
|
|
{
|
|
case SEARCH_MENU_MINIMUM_ITEMS:
|
|
if(search->parameter == MINIMUM_ITEM_INCREMENT) search->value = 0x01;
|
|
else if(search->parameter == MINIMUM_ITEM_DECREMENT) search->value = 0xFF;
|
|
|
|
search->comparison = SEARCH_MINIMUM_CONVERSION_TABLE[search->parameter];
|
|
request_search = 1;
|
|
break;
|
|
|
|
case SEARCH_MENU_COMPARISON:
|
|
if(mode == SEARCH_BOX_STANDARD)
|
|
request_search = 1;
|
|
break;
|
|
|
|
case SEARCH_MENU_VALUE:
|
|
edit_active = 1;
|
|
edit_cursor = 0;
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_DO_SEARCH:
|
|
request_search = 1;
|
|
break;
|
|
|
|
case SEARCH_MENU_CPU:
|
|
cheat_menu_stack_push(select_search_region_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case SEARCH_MENU_SAVE_MEMORY:
|
|
done_memory_save = 0;
|
|
request_search = 1;
|
|
break;
|
|
|
|
case SEARCH_MENU_VIEW_RESULT:
|
|
if(search->region_list_length)
|
|
cheat_menu_stack_push(view_search_result_menu, menu->handler, menu->sel);
|
|
else
|
|
/* if no search region (eg, sms.c in HazeMD), don't open result viewer to avoid the crash */
|
|
SET_MESSAGE(CHEAT_MESSAGE_NO_SEARCH_REGION);
|
|
break;
|
|
|
|
case SEARCH_MENU_RESTORE_SEARCH:
|
|
restore_search_backup(search);
|
|
break;
|
|
|
|
case SEARCH_MENU_RETURN:
|
|
menu->sel = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
if(edit_active) edit_active = 0;
|
|
else menu->sel = -1;
|
|
}
|
|
|
|
if(do_increment)
|
|
{
|
|
switch(info->field_type)
|
|
{
|
|
case SEARCH_MENU_COMPARISON:
|
|
search->comparison += do_increment;
|
|
|
|
if(search->rhs == kSearchOperand_Value)
|
|
{
|
|
if(search->comparison < 0) search->comparison = kSearchComparison_NotEqual;
|
|
if(search->comparison > kSearchComparison_NotEqual) search->comparison = 0;
|
|
}
|
|
else
|
|
{
|
|
if(search->comparison < 0) search->comparison = kSearchComparison_Max - 1;
|
|
if(search->comparison >= kSearchComparison_Max) search->comparison = 0;
|
|
}
|
|
break;
|
|
|
|
case SEARCH_MENU_VALUE:
|
|
search->value = (search->value + do_increment) & BYTE_MASK_TABLE[search->bytes];
|
|
|
|
if(search->comparison == kSearchComparison_IncreasedBy)
|
|
{
|
|
if(search->value == SEARCH_BYTE_SIGN_BIT_TABLE[search->bytes] || search->value == 0)
|
|
search->value = (search->value + do_increment) & BYTE_MASK_TABLE[search->bytes];
|
|
}
|
|
break;
|
|
|
|
case SEARCH_MENU_MINIMUM_ITEMS:
|
|
search->parameter += do_increment;
|
|
|
|
if(search->parameter < 0) search->parameter = MINIMUM_ITEM_MAX - 1;
|
|
if(search->parameter >= MINIMUM_ITEM_MAX) search->parameter = 0;
|
|
break;
|
|
|
|
case SEARCH_MENU_STANDARD_MODE:
|
|
search->rhs += do_increment;
|
|
|
|
if(search->rhs < 1) search->rhs = kSearchOperand_Max - 1;
|
|
if(search->rhs >= kSearchOperand_Max) search->rhs = 1;
|
|
|
|
if(search->rhs == kSearchOperand_Value)
|
|
{
|
|
if(search->comparison > kSearchComparison_NotEqual)
|
|
search->comparison = kSearchComparison_EqualTo;
|
|
}
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_LHS:
|
|
search->lhs += do_increment;
|
|
|
|
if(search->lhs < 0) search->lhs = kSearchOperand_Max - 1;
|
|
if(search->lhs >= kSearchOperand_Max) search->lhs = 0;
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_RHS:
|
|
search->rhs += do_increment;
|
|
|
|
if(search->rhs < 0) search->rhs = kSearchOperand_Max - 1;
|
|
if(search->rhs >= kSearchOperand_Max) search->rhs = 0;
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_SIZE:
|
|
search->bytes += do_increment;
|
|
|
|
if(search->bytes < 0) search->bytes = kSearchSize_Max - 1;
|
|
if(search->bytes >= kSearchSize_Max) search->bytes = 0;
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_SWAP:
|
|
search->swap ^= 1;
|
|
break;
|
|
|
|
case SEARCH_MENU_ADVANCED_SIGN:
|
|
search->sign ^= 1;
|
|
break;
|
|
|
|
case SEARCH_MENU_CPU:
|
|
search->target_idx += do_increment;
|
|
|
|
if(search->target_idx < 0) search->target_idx = cpu_gettotalcpu() - 1;
|
|
if(search->target_idx >= cpu_gettotalcpu()) search->target_idx = 0;
|
|
do_rebuild = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(do_rebuild)
|
|
{
|
|
if(search->search_speed != SEARCH_SPEED_USER_DEFINED) build_search_regions(machine, search);
|
|
else load_cheat_database(machine, LOAD_USER_REGION);
|
|
|
|
allocate_search_regions(search);
|
|
|
|
done_memory_save = 0;
|
|
}
|
|
|
|
if(request_search)
|
|
{
|
|
if(done_memory_save == 0)
|
|
init_new_search(search);
|
|
|
|
if(done_memory_save || (mode == SEARCH_BOX_STANDARD && search->rhs == kSearchOperand_Value))
|
|
{
|
|
backup_search(search);
|
|
do_search(search);
|
|
}
|
|
|
|
update_search(search);
|
|
|
|
if(done_memory_save || (mode == SEARCH_BOX_STANDARD && search->rhs == kSearchOperand_Value))
|
|
SET_MESSAGE(CHEAT_MESSAGE_CHEAT_FOUND);
|
|
else
|
|
SET_MESSAGE(CHEAT_MESSAGE_INITIALIZE_MEMORY);
|
|
|
|
if(search->num_results == 1)
|
|
{
|
|
add_cheat_from_first_result(machine, search);
|
|
SET_MESSAGE(CHEAT_MESSAGE_ONE_CHEAT_FOUND);
|
|
}
|
|
|
|
done_memory_save = 1;
|
|
}
|
|
|
|
if(edit_active != 0 && info->field_type == SEARCH_MENU_VALUE)
|
|
{
|
|
search->value = do_edit_hex_field(machine, search->value);
|
|
search->value &= BYTE_MASK_TABLE[search->bytes];
|
|
}
|
|
|
|
if(info->field_type == SEARCH_MENU_ADVANCED_NAME)
|
|
search->name = do_dynamic_edit_text_field(search->name);
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
select_search_region_menu - management for search regions selection menu
|
|
---------------------------------------------------------------------------*/
|
|
|
|
static int select_search_region_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
static const char *const ksearch_speedList[] =
|
|
{
|
|
"Fast",
|
|
"Medium",
|
|
"Slow",
|
|
"Very Slow",
|
|
"All Memory",
|
|
"User Defined"
|
|
};
|
|
|
|
int total = 0;
|
|
UINT8 do_rebuild = 0;
|
|
UINT8 do_reallocate = 0;
|
|
const char **menu_item;
|
|
const char **menu_sub_item;
|
|
search_info *search = get_current_search();
|
|
search_region *region;
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/* required items = speed + total regions + return + terminator */
|
|
request_strings(search->region_list_length + 4, 0, 0, 0);
|
|
menu_item = menu_strings.main_list;
|
|
menu_sub_item = menu_strings.sub_list;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### SEARCH SPEED ##### */
|
|
menu_item[total] = "Search Speed";
|
|
menu_sub_item[total++] = ksearch_speedList[search->search_speed];
|
|
|
|
/* ##### REGIONS ##### */
|
|
if(search->region_list_length)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < search->region_list_length; i++)
|
|
{
|
|
search_region *region = &search->region_list[i];
|
|
|
|
menu_item[total] = region->name;
|
|
|
|
if(region->flags & kRegionFlag_HasError)
|
|
menu_sub_item[total++] = "Locked";
|
|
else
|
|
menu_sub_item[total++] = region->flags & kRegionFlag_Enabled ? "On" : "Off";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
/* in case of no search region */
|
|
menu_item[total] = "No Search Region";
|
|
menu_sub_item[total++] = NULL;
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
menu_item[total] = "Return to Prior Menu";
|
|
menu_sub_item[total++] = NULL;
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = NULL;
|
|
menu_sub_item[total] = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, menu_sub_item, NULL, menu->sel, 0);
|
|
|
|
if(search->region_list_length && menu->sel && menu->sel < total - 1)
|
|
{
|
|
region = &search->region_list[menu->sel - 1];
|
|
|
|
if(region->flags & kRegionFlag_HasError)
|
|
region = NULL;
|
|
}
|
|
else
|
|
region = NULL;
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
if(region)
|
|
{
|
|
/* toggle ON/OFF */
|
|
region->flags ^= kRegionFlag_Enabled;
|
|
|
|
do_reallocate = 1;
|
|
}
|
|
else if(menu->sel == 0)
|
|
{
|
|
if(--search->search_speed < 0)
|
|
/* "Fast" -> "User Defined" */
|
|
search->search_speed = SEARCH_SPEED_MAX - 1;
|
|
|
|
do_rebuild = 1;
|
|
do_reallocate = 1;
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
if(region)
|
|
{
|
|
/* toggle ON/OFF */
|
|
region->flags ^= kRegionFlag_Enabled;
|
|
|
|
do_reallocate = 1;
|
|
}
|
|
else if(menu->sel == 0)
|
|
{
|
|
if(++search->search_speed >= SEARCH_SPEED_MAX)
|
|
/* "User Defined" -> "Fast" */
|
|
search->search_speed = SEARCH_SPEED_FAST;
|
|
|
|
do_rebuild = 1;
|
|
do_reallocate = 1;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
{
|
|
if(shift_key_pressed() && region && search)
|
|
{
|
|
/* SHIFT + CHEAT DELETE = invalidate selected region */
|
|
invalidate_entire_region(search, region);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT))
|
|
{
|
|
if(search->search_speed == SEARCH_SPEED_USER_DEFINED)
|
|
/* reload user region */
|
|
do_rebuild = 1;
|
|
do_reallocate = 1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(region)
|
|
{
|
|
region->flags ^= kRegionFlag_Enabled;
|
|
do_reallocate = 1;
|
|
}
|
|
else if(menu->sel == 0)
|
|
{
|
|
do_rebuild = 1;
|
|
do_reallocate = 1;
|
|
}
|
|
else if(menu->sel == total - 1)
|
|
menu->sel = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
menu->sel = -1;
|
|
|
|
/********** REBUILD SEARCH REGION **********/
|
|
if(do_rebuild)
|
|
{
|
|
if(search->search_speed != SEARCH_SPEED_USER_DEFINED)
|
|
/* rebuild search region from memory map */
|
|
build_search_regions(machine, search);
|
|
else
|
|
/* rebuild search region from user-defined map */
|
|
load_cheat_database(machine, LOAD_USER_REGION);
|
|
}
|
|
|
|
if(do_reallocate)
|
|
/* reallocate search region */
|
|
allocate_search_regions(search);
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------
|
|
view_search_result_menu - management for search result menu
|
|
--------------------------------------------------------------*/
|
|
|
|
static int view_search_result_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
enum{
|
|
kMenu_Header = 0,
|
|
kMenu_FirstResult,
|
|
|
|
kMaxResultsPerPage = 100 };
|
|
|
|
int i;
|
|
int total = 0;
|
|
int numPages;
|
|
int resultsPerPage;
|
|
int numToSkip;
|
|
UINT8 hadResults = 0;
|
|
UINT8 pageSwitch = 0;
|
|
UINT8 resultsFound = 0;
|
|
UINT8 selectedAddressGood = 0;
|
|
UINT32 selectedAddress = 0;
|
|
UINT32 selectedOffset = 0;
|
|
UINT32 traverse;
|
|
const char ** menu_item;
|
|
char ** buf;
|
|
char * header;
|
|
search_info *search = get_current_search();
|
|
search_region *region;
|
|
|
|
/* first setting : initialize region index and page number */
|
|
if(menu->first_time)
|
|
{
|
|
search->current_region_idx = 0;
|
|
search->current_results_page = 0;
|
|
|
|
/* set current REGION for first display */
|
|
for(traverse = 0; traverse < search->region_list_length; traverse++)
|
|
{
|
|
region = &search->region_list[traverse];
|
|
|
|
if(region->num_results)
|
|
{
|
|
search->current_region_idx = traverse;
|
|
break;
|
|
}
|
|
}
|
|
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
/* required items = (header + defined max items + return + terminator) + (strings buf * (header + defined max items)) + 32 characters */
|
|
request_strings(kMaxResultsPerPage + 3, kMaxResultsPerPage, 32, 0);
|
|
menu_item = menu_strings.main_list;
|
|
header = menu_strings.main_strings[0];
|
|
buf = &menu_strings.main_strings[1];
|
|
|
|
/* adjust current REGION */
|
|
if(search->current_region_idx >= search->region_list_length)
|
|
search->current_region_idx = search->region_list_length - 1;
|
|
if(search->current_region_idx < 0)
|
|
search->current_region_idx = 0;
|
|
|
|
region = &search->region_list[search->current_region_idx];
|
|
|
|
/* set the number of items per PAGE */
|
|
resultsPerPage = full_menu_page_height - 3;
|
|
|
|
/* adjust total items per PAGE */
|
|
if(resultsPerPage <= 0)
|
|
resultsPerPage = 1;
|
|
else if(resultsPerPage > kMaxResultsPerPage)
|
|
resultsPerPage = kMaxResultsPerPage;
|
|
|
|
/* get the number of total PAGEs */
|
|
if(region->flags & kRegionFlag_Enabled)
|
|
numPages = (region->num_results / SEARCH_BYTE_STEP[search->bytes] + resultsPerPage - 1) / resultsPerPage;
|
|
else
|
|
numPages = 0;
|
|
|
|
if(numPages > full_menu_page_height)
|
|
numPages = full_menu_page_height;
|
|
|
|
/* adjust current PAGE */
|
|
if(search->current_results_page >= numPages)
|
|
search->current_results_page = numPages - 1;
|
|
if(search->current_results_page < 0)
|
|
search->current_results_page = 0;
|
|
|
|
/* set the number of skipping results to undisplay */
|
|
numToSkip = resultsPerPage * search->current_results_page;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### HEADER ##### */
|
|
sprintf(header, "%s %d/%d", region->name, search->current_results_page + 1, numPages);
|
|
|
|
menu_item[total++] = header;
|
|
|
|
traverse = 0;
|
|
|
|
if((region->length < BYTE_INCREMENT_TABLE[search->bytes]) || !(region->flags & kRegionFlag_Enabled))
|
|
{
|
|
; // no results...
|
|
}
|
|
else
|
|
{
|
|
/* ##### RESULT ##### */
|
|
for(i = 0; i < resultsPerPage && traverse < region->length && resultsFound < region->num_results;)
|
|
{
|
|
while(is_region_offset_valid(search, region, traverse) == 0 && traverse < region->length)
|
|
traverse += SEARCH_BYTE_STEP[search->bytes];
|
|
|
|
if(traverse < region->length)
|
|
{
|
|
if(numToSkip > 0)
|
|
numToSkip--;
|
|
else
|
|
{
|
|
if(total == menu->sel)
|
|
{
|
|
selectedAddress = region->address + traverse;
|
|
selectedOffset = traverse;
|
|
selectedAddressGood = 1;
|
|
}
|
|
|
|
sprintf( buf[total],
|
|
"%.8X (%.*X %.*X %.*X)",
|
|
region->address + traverse,
|
|
BYTE_DIGITS_TABLE[search->bytes],
|
|
read_search_operand(kSearchOperand_First, search, region, region->address + traverse),
|
|
BYTE_DIGITS_TABLE[search->bytes],
|
|
read_search_operand(kSearchOperand_Previous, search, region, region->address + traverse),
|
|
BYTE_DIGITS_TABLE[search->bytes],
|
|
read_search_operand(kSearchOperand_Current, search, region, region->address + traverse));
|
|
|
|
menu_item[total] = buf[total];
|
|
total++;
|
|
|
|
i++;
|
|
}
|
|
|
|
traverse += SEARCH_BYTE_STEP[search->bytes];
|
|
resultsFound++;
|
|
hadResults = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set special message if empty REGION */
|
|
if(!hadResults)
|
|
{
|
|
if(search->num_results)
|
|
menu_item[total++] = "no results for this region";
|
|
else
|
|
menu_item[total++] = "no results found";
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
menu_item[total++] = "Return to Prior Menu";
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
if(menu->sel <= kMenu_Header)
|
|
menu->sel = kMenu_FirstResult;
|
|
if(menu->sel > total - 1 || !hadResults)
|
|
menu->sel = total - 1;
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, NULL, NULL, menu->sel, 0);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
if(--menu->sel < 1)
|
|
menu->sel = total - 1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
if(++menu->sel >= total)
|
|
menu->sel = kMenu_FirstResult;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
/* shift + right = go to last PAGE */
|
|
search->current_results_page = numPages - 1;
|
|
}
|
|
else if(control_key_pressed())
|
|
{
|
|
/* ctrl + right = go to next REGION */
|
|
search->current_region_idx++;
|
|
|
|
if(search->current_region_idx >= search->region_list_length)
|
|
search->current_region_idx = 0;
|
|
}
|
|
else
|
|
{
|
|
/* otherwise, go to next PAGE */
|
|
pageSwitch = 1;
|
|
}
|
|
|
|
menu->sel = kMenu_FirstResult;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
/* shift + left = go to first PAGE */
|
|
search->current_results_page = 0;
|
|
}
|
|
else if(control_key_pressed())
|
|
{
|
|
/* ctrl + left = go to previous REGION */
|
|
search->current_region_idx--;
|
|
|
|
if(search->current_region_idx < 0)
|
|
search->current_region_idx = search->region_list_length - 1;
|
|
}
|
|
else
|
|
{
|
|
/* otherwise, go to previous PAGE */
|
|
pageSwitch = 2;
|
|
}
|
|
|
|
menu->sel = kMenu_FirstResult;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, horizontal_key_repeat_speed))
|
|
{
|
|
menu->sel -=full_menu_page_height;
|
|
|
|
if(menu->sel <= kMenu_Header)
|
|
menu->sel = kMenu_FirstResult;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, horizontal_key_repeat_speed))
|
|
{
|
|
menu->sel +=full_menu_page_height;
|
|
|
|
if(menu->sel >= total)
|
|
menu->sel = total - 1;
|
|
}
|
|
else if(input_code_pressed_once(KEYCODE_HOME))
|
|
{
|
|
/* go to first PAGE */
|
|
search->current_results_page = 0;
|
|
}
|
|
else if(input_code_pressed_once(KEYCODE_END))
|
|
{
|
|
/* go to last PAGE */
|
|
search->current_results_page = numPages - 1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PREV_GROUP, vertical_key_repeat_speed))
|
|
{
|
|
/* go to previous REGION */
|
|
search->current_region_idx--;
|
|
|
|
if(search->current_region_idx < 0)
|
|
search->current_region_idx = search->region_list_length - 1;
|
|
|
|
menu->sel = kMenu_FirstResult;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_NEXT_GROUP, vertical_key_repeat_speed))
|
|
{
|
|
/* go to next REGION */
|
|
search->current_region_idx++;
|
|
|
|
if(search->current_region_idx >= search->region_list_length)
|
|
search->current_region_idx = 0;
|
|
|
|
menu->sel = kMenu_FirstResult;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT))
|
|
{
|
|
if(selectedAddressGood)
|
|
add_cheat_from_result(machine, search, region, selectedAddress);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
if(region && search)
|
|
/* shift + delete = invalidate all results in current REGION */
|
|
invalidate_entire_region(search, region);
|
|
}
|
|
else if(selectedAddressGood)
|
|
{
|
|
/* otherwise, delete selected result */
|
|
invalidate_region_offset(search, region, selectedOffset);
|
|
search->num_results--;
|
|
region->num_results--;
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_DELETE);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_WATCH_VALUE))
|
|
{
|
|
if(selectedAddressGood)
|
|
add_watch_from_result(search, region, selectedAddress);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT) || input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
menu->sel = -1;
|
|
|
|
switch(pageSwitch)
|
|
{
|
|
case 1: // go to next PAGE
|
|
search->current_results_page++;
|
|
|
|
/* if current PAGE is the last, go to first PAGE in next REGION */
|
|
if(search->current_results_page >= numPages)
|
|
{
|
|
search->current_results_page = 0;
|
|
search->current_region_idx++;
|
|
|
|
/* if current REGION is the last, go to first REGION */
|
|
if(search->current_region_idx >= search->region_list_length)
|
|
search->current_region_idx = 0;
|
|
|
|
/* if next REGION is empty, search next "non-empty" REGION.
|
|
but incomplete because last REGION is displayed even if empty */
|
|
for(traverse = search->current_region_idx; traverse < search->region_list_length; traverse++)
|
|
{
|
|
search->current_region_idx = traverse;
|
|
|
|
if(search->region_list[traverse].num_results)
|
|
break;
|
|
}
|
|
}
|
|
|
|
menu->sel = kMenu_FirstResult;
|
|
break;
|
|
|
|
case 2: // go to previous PAGE
|
|
search->current_results_page--;
|
|
|
|
/* if current PAGE is first, go to previous REGION */
|
|
if(search->current_results_page < 0)
|
|
{
|
|
search->current_results_page = 0;
|
|
search->current_region_idx--;
|
|
|
|
/* if current REGION is first, go to last REGION */
|
|
if(search->current_region_idx < 0)
|
|
search->current_region_idx = search->region_list_length - 1;
|
|
|
|
/* if previous REGION is empty, search previous "non-empty" REGION.
|
|
but incomplete because first REGION is displayed even if empty */
|
|
for(i = search->current_region_idx; i >= 0; i--)
|
|
{
|
|
search->current_region_idx = i;
|
|
|
|
if(search->region_list[i].num_results)
|
|
break;
|
|
}
|
|
|
|
/* go to last PAGE in previous REGION */
|
|
{
|
|
/* get the number of total PAGEs for previous REGION */
|
|
search_region *new_region = &search->region_list[search->current_region_idx];
|
|
UINT32 nextNumPages = (new_region->num_results / SEARCH_BYTE_STEP[search->bytes] + resultsPerPage - 1) / resultsPerPage;
|
|
|
|
if(nextNumPages <= 0)
|
|
nextNumPages = 1;
|
|
|
|
search->current_results_page = nextNumPages - 1;
|
|
}
|
|
}
|
|
|
|
menu->sel = kMenu_FirstResult;
|
|
break;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
choose_watch_menu - management for watchpoint list menu
|
|
----------------------------------------------------------*/
|
|
|
|
static int choose_watch_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
int i;
|
|
UINT8 total = 0;
|
|
const char **menu_item;
|
|
char **buf;
|
|
char *buf_strings; /* "USER20 FFFFFFFF (99:32 Bit)" 27 chars */
|
|
watch_info *watch;
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/* required items = (total watchpoints + return + terminator) + (strings buf * total watchpoints) + 32 characters */
|
|
request_strings(watch_list_length + 2, watch_list_length, 32, 0);
|
|
menu_item = menu_strings.main_list;
|
|
buf = menu_strings.main_strings;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 0; i < watch_list_length; i++)
|
|
{
|
|
watch_info *traverse = &watch_list[i];
|
|
cpu_region_info *info = get_cpu_or_region_info(traverse->cpu);
|
|
|
|
if(edit_active && menu->sel == i)
|
|
{
|
|
/* insert edit cursor in quick edit mode */
|
|
switch(edit_cursor)
|
|
{
|
|
default:
|
|
{
|
|
buf_strings = buf[i];
|
|
|
|
buf_strings += sprintf(buf_strings, "%s ", get_region_name(traverse->cpu));
|
|
buf_strings = create_strings_with_edit_cursor(buf_strings, traverse->address, info->address_chars_needed - 1, edit_cursor - 2);
|
|
buf_strings += sprintf(buf_strings, " (%d:%s)", traverse->num_elements, kByteSizeStringList[traverse->element_bytes]);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
sprintf(buf[i], "%s:%.*X ([%d]:%s)",
|
|
get_region_name(traverse->cpu),
|
|
info->address_chars_needed,
|
|
traverse->address,
|
|
traverse->num_elements,
|
|
kByteSizeStringList[traverse->element_bytes]);
|
|
break;
|
|
|
|
case 0:
|
|
sprintf(buf[i], "%s:%.*X (%d:[%s])",
|
|
get_region_name(traverse->cpu),
|
|
info->address_chars_needed,
|
|
traverse->address,
|
|
traverse->num_elements,
|
|
kByteSizeStringList[traverse->element_bytes]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* FORMAT : "CPU/Region : Address (Length : Bytes)" */
|
|
sprintf(buf[i], "%s:%.*X (%d:%s)",
|
|
get_region_name(traverse->cpu),
|
|
info->address_chars_needed,
|
|
traverse->address,
|
|
traverse->num_elements,
|
|
kByteSizeStringList[traverse->element_bytes]);
|
|
}
|
|
menu_item[total] = buf[i];
|
|
total++;
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
menu_item[total++] = "Return to Prior Menu";
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, NULL, NULL, menu->sel, 0);
|
|
|
|
if(menu->sel < watch_list_length) watch = &watch_list[menu->sel];
|
|
else watch = NULL;
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
switch(edit_cursor)
|
|
{
|
|
default:
|
|
watch->address = do_increment_hex_field(watch->address, edit_cursor - 2);
|
|
break;
|
|
|
|
case 1:
|
|
if(watch->num_elements < 99)
|
|
watch->num_elements++;
|
|
break;
|
|
|
|
case 0:
|
|
watch->element_bytes = (watch->element_bytes + 1) & 0x03;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
switch(edit_cursor)
|
|
{
|
|
default:
|
|
watch->address = do_decrement_hex_field(watch->address, edit_cursor - 2);
|
|
break;
|
|
|
|
case 1:
|
|
if(watch->num_elements > 0)
|
|
watch->num_elements--;
|
|
break;
|
|
|
|
case 0:
|
|
watch->element_bytes = (watch->element_bytes - 1) & 0x03;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active == 0)
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active == 0)
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
cpu_region_info *info = get_cpu_or_region_info(watch->cpu);
|
|
|
|
if(++edit_cursor > info->address_chars_needed + 1)
|
|
edit_cursor = 0;
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, vertical_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
cpu_region_info *info = get_cpu_or_region_info(watch->cpu);
|
|
|
|
if(--edit_cursor < 0)
|
|
edit_cursor = info->address_chars_needed + 1;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(edit_active)
|
|
edit_active = 0;
|
|
else
|
|
{
|
|
if(watch)
|
|
cheat_menu_stack_push(command_watch_menu, menu->handler, menu->sel);
|
|
else
|
|
menu->sel = -1;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT))
|
|
{
|
|
if(!edit_active && watch)
|
|
{
|
|
if(shift_key_pressed())
|
|
add_cheat_from_watch(machine, watch);
|
|
else if(control_key_pressed())
|
|
{
|
|
cheat_entry *entry = get_new_cheat();
|
|
|
|
add_cheat_from_watch_as_watch(machine, entry, watch);
|
|
|
|
/* when fails to add, delete this entry because it causes the crash */
|
|
if(message_type == CHEAT_MESSAGE_FAILED_TO_ADD)
|
|
{
|
|
delete_cheat_at(cheat_list_length - 1);
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_ADD);
|
|
}
|
|
}
|
|
else
|
|
add_watch_before(menu->sel);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
{
|
|
if(!edit_active && watch)
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
delete_watch_at(menu->sel);
|
|
}
|
|
else if(control_key_pressed())
|
|
{
|
|
for(i = 0; i < watch_list_length; i++)
|
|
watch_list[i].num_elements = 0;
|
|
}
|
|
else
|
|
{
|
|
if(watch)
|
|
watch->num_elements = 0;
|
|
}
|
|
}
|
|
else if(edit_active)
|
|
{
|
|
switch(edit_cursor)
|
|
{
|
|
default:
|
|
watch->address = 0;
|
|
break;
|
|
|
|
case 1:
|
|
watch->num_elements = 0;
|
|
break;
|
|
|
|
case 0:
|
|
watch->element_bytes = 0;
|
|
}
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT))
|
|
{
|
|
if(!edit_active && watch)
|
|
{
|
|
cheat_entry entry;
|
|
|
|
memset(&entry, 0, sizeof(cheat_entry));
|
|
|
|
add_cheat_from_watch_as_watch(machine, &entry, watch);
|
|
save_cheat_code(machine, &entry);
|
|
dispose_cheat(&entry);
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_EDIT_CHEAT))
|
|
{
|
|
if(watch)
|
|
{
|
|
edit_cursor = 2;
|
|
edit_active ^= 1;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CLEAR))
|
|
{
|
|
if(!edit_active)
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
reset_watch(watch);
|
|
}
|
|
else
|
|
{
|
|
for(i = 0; i < watch_list_length; i++)
|
|
reset_watch(&watch_list[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
watch->address = 0;
|
|
watch->num_elements = 0;
|
|
watch->element_bytes = 0;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
if(edit_active)
|
|
edit_active = 0;
|
|
else
|
|
menu->sel = -1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------
|
|
command_watch_menu - management for wathcpoint command menu
|
|
--------------------------------------------------------------*/
|
|
|
|
static int command_watch_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
enum{
|
|
kMenu_EditWatch = 0,
|
|
kMenu_DisableWatch,
|
|
kMenu_DisableAllWatch,
|
|
kMenu_ResetWatch,
|
|
kMenu_ResetAllWatch,
|
|
kMenu_AddAsCheatCode,
|
|
kMenu_AddAsWatchCode,
|
|
kMenu_SaveAsCheatCode,
|
|
kMenu_SaveAsWatchCode,
|
|
kMenu_AddWatch,
|
|
kMenu_DeleteWatch,
|
|
kMenu_Return,
|
|
kMenu_Max };
|
|
|
|
int i;
|
|
UINT8 total = 0;
|
|
ui_menu_item menuItem[kMenu_Max + 1];
|
|
watch_info *entry = &watch_list[menu->pre_sel];
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
memset(menuItem, 0, sizeof(menuItem));
|
|
|
|
/********** MENU CONSTRUCION **********/
|
|
menuItem[total++].text = "Edit Watchpoint";
|
|
menuItem[total++].text = "Disable Watchpoint";
|
|
menuItem[total++].text = "Disable All Watchpoints";
|
|
menuItem[total++].text = "Reset Watchpoint";
|
|
menuItem[total++].text = "Reset All Watchpoints";
|
|
menuItem[total++].text = "Add as Cheat Code";
|
|
menuItem[total++].text = "Add as Watch Code";
|
|
menuItem[total++].text = "Save as Cheat Code";
|
|
menuItem[total++].text = "Save as Watch Code";
|
|
menuItem[total++].text = "Add New Watchpoint";
|
|
menuItem[total++].text = "Delete Watchpoint";
|
|
menuItem[total++].text = "Return to Prior Menu";
|
|
menuItem[total].text = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* print it */
|
|
ui_menu_draw(menuItem, total, menu->sel, NULL);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case kMenu_EditWatch:
|
|
cheat_menu_stack_push(edit_watch_menu, menu->return_handler, menu->pre_sel);
|
|
break;
|
|
|
|
case kMenu_DisableWatch:
|
|
entry->num_elements = 0;
|
|
break;
|
|
|
|
case kMenu_DisableAllWatch:
|
|
for(i = 0; i < watch_list_length; i++)
|
|
watch_list[i].num_elements = 0;
|
|
break;
|
|
|
|
case kMenu_ResetWatch:
|
|
reset_watch(entry);
|
|
break;
|
|
|
|
case kMenu_ResetAllWatch:
|
|
for(i = 0; i < watch_list_length; i++)
|
|
reset_watch(&watch_list[i]);
|
|
break;
|
|
|
|
case kMenu_AddAsCheatCode:
|
|
add_cheat_from_watch(machine, entry);
|
|
break;
|
|
|
|
case kMenu_AddAsWatchCode:
|
|
{
|
|
cheat_entry *new_entry = get_new_cheat();
|
|
|
|
add_cheat_from_watch_as_watch(machine, new_entry, entry);
|
|
|
|
/* when fails to add, delete this entry because it causes the crash */
|
|
if(message_type == CHEAT_MESSAGE_FAILED_TO_ADD)
|
|
{
|
|
delete_cheat_at(cheat_list_length - 1);
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_ADD);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kMenu_SaveAsCheatCode:
|
|
// underconstruction...
|
|
break;
|
|
|
|
case kMenu_SaveAsWatchCode:
|
|
{
|
|
cheat_entry temp_entry;
|
|
|
|
memset(&temp_entry, 0, sizeof(cheat_entry));
|
|
|
|
add_cheat_from_watch_as_watch(machine, &temp_entry, entry);
|
|
save_cheat_code(machine, &temp_entry);
|
|
dispose_cheat(&temp_entry);
|
|
}
|
|
break;
|
|
|
|
case kMenu_Return:
|
|
menu->sel = -1;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT))
|
|
{
|
|
reload_cheat_database(machine);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL) || input_ui_pressed(machine, IPT_UI_LEFT) || input_ui_pressed(machine, IPT_UI_RIGHT))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------
|
|
edit_watch_menu - management for watchpoint edit menu
|
|
--------------------------------------------------------*/
|
|
|
|
static int edit_watch_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
enum{
|
|
kMenu_Address = 0,
|
|
kMenu_CPU,
|
|
kMenu_NumElements,
|
|
kMenu_ElementSize,
|
|
kMenu_LabelType,
|
|
kMenu_TextLabel,
|
|
kMenu_DisplayType,
|
|
kMenu_XPosition,
|
|
kMenu_YPosition,
|
|
kMenu_Skip,
|
|
kMenu_ElementsPerLine,
|
|
kMenu_AddValue,
|
|
kMenu_AddressShift,
|
|
kMenu_DataShift,
|
|
kMenu_XOR,
|
|
|
|
kMenu_Return,
|
|
kMenu_Max };
|
|
|
|
UINT8 total = 0;
|
|
UINT32 increment = 1;
|
|
const char ** menuItem;
|
|
const char ** menuSubItem;
|
|
char ** buf;
|
|
char * flagBuf;
|
|
watch_info *entry = &watch_list[menu->pre_sel];
|
|
cpu_region_info *info = get_cpu_or_region_info(entry->cpu);
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
request_strings(kMenu_Max + 1, kMenu_Return, 0, 20);
|
|
menuItem = menu_strings.main_list;
|
|
menuSubItem = menu_strings.sub_list;
|
|
buf = menu_strings.sub_strings;
|
|
flagBuf = menu_strings.flag_list;
|
|
|
|
memset(flagBuf, 0, kMenu_Max + 1);
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### ADDRESS ##### */
|
|
sprintf(buf[total], "%.*X", info->address_chars_needed, entry->address >> entry->address_shift);
|
|
menuItem[total] = "Address";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### CPU/REGION ##### */
|
|
sprintf(buf[total], "%s", get_region_name(entry->cpu));
|
|
menuItem[total] = entry->cpu < REGION_INVALID ? "CPU" : "Region";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### LENGTH ##### */
|
|
sprintf(buf[total], "%d", entry->num_elements);
|
|
menuItem[total] = "Length";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### ELEMENT SIZE ##### */
|
|
menuItem[total] = "Element Size";
|
|
menuSubItem[total++] = kByteSizeStringList[entry->element_bytes];
|
|
|
|
/* ##### LABEL TYPE ##### */
|
|
menuItem[total] = "Label Type";
|
|
menuSubItem[total++] = kWatchLabelStringList[entry->label_type];
|
|
|
|
/* ##### TEXT LABEL ##### */
|
|
menuItem[total] = "Text Label";
|
|
if(entry->label[0])
|
|
menuSubItem[total++] = entry->label;
|
|
else
|
|
menuSubItem[total++] = "(none)";
|
|
|
|
/* ##### DISPLAY TYPE ##### */
|
|
menuItem[total] = "Display Type";
|
|
menuSubItem[total++] = kWatchDisplayTypeStringList[entry->display_type];
|
|
|
|
/* ##### X POSITION ##### */
|
|
sprintf(buf[total], "%f", entry->x);
|
|
menuItem[total] = "X";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### Y POSITION ##### */
|
|
sprintf(buf[total], "%f", entry->y);
|
|
menuItem[total] = "Y";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### SKIP BYTES ##### */
|
|
sprintf(buf[total], "%d", entry->skip);
|
|
menuItem[total] = "Skip Bytes";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### ELEMENTS PER LINE ##### */
|
|
sprintf(buf[total], "%d", entry->elements_per_line);
|
|
menuItem[total] = "Elements Per Line";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### ADD VALUE ##### */
|
|
menuItem[total] = "Add Value";
|
|
if(entry->add_value < 0)
|
|
sprintf(buf[total], "-%.2X", -entry->add_value);
|
|
else
|
|
sprintf(buf[total], "%.2X", entry->add_value);
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### ADDRESS SHIFT ##### */
|
|
sprintf(buf[total], "%d", entry->address_shift);
|
|
menuItem[total] = "Address Shift";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### DATA SHIFT ##### */
|
|
sprintf(buf[total], "%d", entry->data_shift);
|
|
menuItem[total] = "Data Shift";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### XOR ##### */
|
|
sprintf(buf[total], "%.*X", BYTE_DIGITS_TABLE[kWatchSizeConversionTable[entry->element_bytes]], entry->xor);
|
|
menuItem[total] = "XOR";
|
|
menuSubItem[total] = buf[total];
|
|
total++;
|
|
|
|
/* ##### RETURN ##### */
|
|
menuItem[total] = "Return to Prior Menu";
|
|
menuSubItem[total++] = NULL;
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menuItem[total] = NULL;
|
|
menuSubItem[total] = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* higlighted sub-item if edit mode */
|
|
if(edit_active)
|
|
flagBuf[menu->sel] = 1;
|
|
|
|
/* draw it */
|
|
old_style_menu(menuItem, menuSubItem, flagBuf, menu->sel, 0);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
// underconstruction...
|
|
}
|
|
else
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case kMenu_Address:
|
|
entry->address = do_shift(entry->address, entry->address_shift);
|
|
entry->address -= increment;
|
|
entry->address = do_shift(entry->address, -entry->address_shift);
|
|
|
|
if(entry->cpu < REGION_INVALID)
|
|
entry->address &= info->address_mask;
|
|
break;
|
|
|
|
case kMenu_CPU:
|
|
entry->cpu--;
|
|
|
|
if(entry->cpu >= cpu_gettotalcpu())
|
|
entry->cpu = cpu_gettotalcpu() - 1;
|
|
|
|
entry->address &= info->address_mask;
|
|
break;
|
|
|
|
case kMenu_NumElements:
|
|
if(entry->num_elements > 0)
|
|
entry->num_elements--;
|
|
else
|
|
entry->num_elements = 0;
|
|
break;
|
|
|
|
case kMenu_ElementSize:
|
|
if(entry->element_bytes > 0)
|
|
entry->element_bytes--;
|
|
else
|
|
entry->element_bytes = 0;
|
|
|
|
entry->xor &= BYTE_MASK_TABLE[kWatchSizeConversionTable[entry->element_bytes]];
|
|
break;
|
|
|
|
case kMenu_LabelType:
|
|
if(entry->label_type > 0)
|
|
entry->label_type--;
|
|
else
|
|
entry->label_type = 0;
|
|
break;
|
|
|
|
case kMenu_TextLabel:
|
|
break;
|
|
|
|
case kMenu_DisplayType:
|
|
if(entry->display_type > 0)
|
|
entry->display_type--;
|
|
else
|
|
entry->display_type = 0;
|
|
break;
|
|
|
|
case kMenu_XPosition:
|
|
entry->x -= 0.01f;
|
|
break;
|
|
|
|
case kMenu_YPosition:
|
|
entry->y -= 0.01f;
|
|
break;
|
|
|
|
case kMenu_Skip:
|
|
if(entry->skip > 0)
|
|
entry->skip--;
|
|
break;
|
|
|
|
case kMenu_ElementsPerLine:
|
|
if(entry->elements_per_line > 0)
|
|
entry->elements_per_line--;
|
|
break;
|
|
|
|
case kMenu_AddValue:
|
|
entry->add_value = (entry->add_value - 1) & 0xFF;
|
|
break;
|
|
|
|
case kMenu_AddressShift:
|
|
if(entry->address_shift > -31)
|
|
entry->address_shift--;
|
|
else
|
|
entry->address_shift = 31;
|
|
break;
|
|
|
|
case kMenu_DataShift:
|
|
if(entry->data_shift > -31)
|
|
entry->data_shift--;
|
|
else
|
|
entry->data_shift = 31;
|
|
break;
|
|
|
|
case kMenu_XOR:
|
|
entry->xor -= increment;
|
|
entry->xor &= BYTE_MASK_TABLE[kWatchSizeConversionTable[entry->element_bytes]];
|
|
}
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
if(edit_active)
|
|
{
|
|
// underconstruction...
|
|
}
|
|
else
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case kMenu_Address:
|
|
entry->address = do_shift(entry->address, entry->address_shift);
|
|
entry->address += increment;
|
|
entry->address = do_shift(entry->address, -entry->address_shift);
|
|
|
|
if(entry->cpu < REGION_INVALID)
|
|
entry->address &= info->address_mask;
|
|
break;
|
|
|
|
case kMenu_CPU:
|
|
entry->cpu++;
|
|
|
|
if(entry->cpu >= cpu_gettotalcpu())
|
|
entry->cpu = 0;
|
|
|
|
entry->address &= info->address_mask;
|
|
break;
|
|
|
|
case kMenu_NumElements:
|
|
entry->num_elements++;
|
|
break;
|
|
|
|
case kMenu_ElementSize:
|
|
if(entry->element_bytes < kSearchSize_32Bit)
|
|
entry->element_bytes++;
|
|
else
|
|
entry->element_bytes = kSearchSize_32Bit;
|
|
|
|
entry->xor &= BYTE_MASK_TABLE[kWatchSizeConversionTable[entry->element_bytes]];
|
|
break;
|
|
|
|
case kMenu_LabelType:
|
|
if(entry->label_type < kWatchLabel_MaxPlusOne - 1)
|
|
entry->label_type++;
|
|
else
|
|
entry->label_type = kWatchLabel_MaxPlusOne - 1;
|
|
break;
|
|
|
|
case kMenu_TextLabel:
|
|
break;
|
|
|
|
case kMenu_DisplayType:
|
|
if(entry->display_type < kWatchDisplayType_MaxPlusOne - 1)
|
|
entry->display_type++;
|
|
else
|
|
entry->display_type = kWatchDisplayType_MaxPlusOne - 1;
|
|
break;
|
|
|
|
case kMenu_XPosition:
|
|
entry->x += 0.01f;
|
|
break;
|
|
|
|
case kMenu_YPosition:
|
|
entry->y += 0.01f;
|
|
break;
|
|
|
|
case kMenu_Skip:
|
|
entry->skip++;
|
|
break;
|
|
|
|
case kMenu_ElementsPerLine:
|
|
entry->elements_per_line++;
|
|
break;
|
|
|
|
case kMenu_AddValue:
|
|
entry->add_value = (entry->add_value + 1) & 0xFF;
|
|
break;
|
|
|
|
case kMenu_AddressShift:
|
|
if(entry->address_shift < 31)
|
|
entry->address_shift++;
|
|
else
|
|
entry->address_shift = -31;
|
|
break;
|
|
|
|
case kMenu_DataShift:
|
|
if(entry->data_shift < 31)
|
|
entry->data_shift++;
|
|
else
|
|
entry->data_shift = -31;
|
|
break;
|
|
|
|
case kMenu_XOR:
|
|
entry->xor += increment;
|
|
entry->xor &= BYTE_MASK_TABLE[kWatchSizeConversionTable[entry->element_bytes]];
|
|
}
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(edit_active)
|
|
edit_active = 0;
|
|
else
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case kMenu_Address:
|
|
case kMenu_CPU:
|
|
case kMenu_NumElements:
|
|
case kMenu_TextLabel:
|
|
case kMenu_XPosition:
|
|
case kMenu_YPosition:
|
|
case kMenu_AddValue:
|
|
case kMenu_AddressShift:
|
|
case kMenu_DataShift:
|
|
case kMenu_XOR:
|
|
osd_readkey_unicode(1);
|
|
edit_active = 1;
|
|
break;
|
|
|
|
case kMenu_Return:
|
|
menu->sel = -1;
|
|
}
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CLEAR))
|
|
{
|
|
reset_watch(entry);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
if(edit_active)
|
|
edit_active = 0;
|
|
else
|
|
menu->sel = -1;
|
|
}
|
|
|
|
if(edit_active)
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case kMenu_Address:
|
|
entry->address = do_shift(entry->address, entry->address_shift);
|
|
entry->address = do_edit_hex_field(machine, entry->address);
|
|
entry->address = do_shift(entry->address, -entry->address_shift);
|
|
entry->address &= info->address_mask;
|
|
break;
|
|
|
|
case kMenu_CPU:
|
|
entry->cpu = do_edit_dec_field(entry->cpu, 0, cpu_gettotalcpu() - 1);
|
|
entry->address &= info->address_mask;
|
|
break;
|
|
|
|
case kMenu_NumElements:
|
|
entry->num_elements = do_edit_dec_field(entry->num_elements, 0, 99);
|
|
break;
|
|
|
|
case kMenu_TextLabel:
|
|
do_static_edit_text_field(entry->label, 255);
|
|
break;
|
|
|
|
case kMenu_XPosition:
|
|
entry->x = do_edit_dec_field(entry->x, -1000, 1000);
|
|
break;
|
|
|
|
case kMenu_YPosition:
|
|
entry->y = do_edit_dec_field(entry->y, -1000, 1000);
|
|
break;
|
|
|
|
case kMenu_AddValue:
|
|
entry->add_value = do_edit_hex_field_signed(entry->add_value, 0xFFFFFF80) & 0xFF;
|
|
break;
|
|
|
|
case kMenu_AddressShift:
|
|
entry->address_shift = do_edit_dec_field(entry->address_shift, -31, 31);
|
|
break;
|
|
|
|
case kMenu_DataShift:
|
|
entry->data_shift = do_edit_dec_field(entry->data_shift, -31, 31);
|
|
break;
|
|
|
|
case kMenu_XOR:
|
|
entry->xor = do_edit_hex_field(machine, entry->xor);
|
|
entry->xor &= BYTE_MASK_TABLE[kWatchSizeConversionTable[entry->element_bytes]];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT))
|
|
add_cheat_from_watch(machine, entry);
|
|
|
|
if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
entry->num_elements = 0;
|
|
|
|
if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT))
|
|
{
|
|
cheat_entry temp_entry;
|
|
|
|
memset(&temp_entry, 0, sizeof(cheat_entry));
|
|
|
|
add_cheat_from_watch_as_watch(machine, &temp_entry, entry);
|
|
save_cheat_code(machine, &temp_entry);
|
|
dispose_cheat(&temp_entry);
|
|
}
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*---------------------------------------------------
|
|
select_option_menu - management for options menu
|
|
---------------------------------------------------*/
|
|
|
|
static int select_option_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
#define ADD_OPTION_MENU_ITEMS(name, sub_name) \
|
|
do { menu_item[total] = name; menu_sub_item[total] = sub_name; total++; } while(0)
|
|
|
|
enum{
|
|
SELECT_OPTION_MENU_SELECT_SEARCH = 0,
|
|
SELECT_OPTION_MENU_LOAD_CHEAT_OPTIONS,
|
|
SELECT_OPTION_MENU_SAVE_CHEAT_OPTIONS,
|
|
SELECT_OPTION_MENU_RESET_CHEAT_OPTIONS,
|
|
SELECT_OPTION_MENU_SEPARATOR,
|
|
SELECT_OPTION_MENU_SEARCH_DIALOG_STYLE,
|
|
SELECT_OPTION_MENU_SHOW_SEARCH_LABELS,
|
|
SELECT_OPTION_MENU_AUTO_SAVE_CHEATS,
|
|
SELECT_OPTION_MENU_SHOW_ACTIVATION_KEY,
|
|
SELECT_OPTION_MENU_LOAD_NEW_CODE,
|
|
SELECT_OPTION_MENU_LOAD_STANDARD_CODE,
|
|
SELECT_OPTION_MENU_LOAD_OLD_CODE,
|
|
#ifdef MESS
|
|
SELECT_OPTION_MENU_SHARED_CODE,
|
|
#endif
|
|
SELECT_OPTION_MENU_VERTICAL_KEY_SPEED,
|
|
SELECT_OPTION_MENU_HORIZONTAL_KEY_SPEED,
|
|
|
|
SELECT_OPTION_MENU_RETURN,
|
|
|
|
SELECT_OPTION_MENU_MAX };
|
|
|
|
INT8 total = 0;
|
|
INT8 request_arrow = 0;
|
|
INT8 do_select = 0;
|
|
const char *menu_item[SELECT_OPTION_MENU_MAX + 1];
|
|
const char *menu_sub_item[SELECT_OPTION_MENU_MAX + 1];
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### SEARCH REGION ##### */
|
|
ADD_OPTION_MENU_ITEMS("Select Search", NULL);
|
|
|
|
/* ##### LOAD CHEAT OPTIONS ##### */
|
|
ADD_OPTION_MENU_ITEMS("Load Cheat Options", NULL);
|
|
|
|
/* ##### SAVE CHEAT OPTIONS ##### */
|
|
ADD_OPTION_MENU_ITEMS("Save Cheat Options", NULL);
|
|
|
|
/* ##### RESET CHEAT OPTIONS ##### */
|
|
ADD_OPTION_MENU_ITEMS("Reset Cheat Options", NULL);
|
|
|
|
/* ##### SEPARATOR ##### */
|
|
ADD_OPTION_MENU_ITEMS(MENU_SEPARATOR_ITEM, NULL);
|
|
|
|
/* ##### SEARCH MENU ##### */
|
|
menu_item[total] = "Search Dialog Style";
|
|
switch(EXTRACT_FIELD(cheat_options, SearchBox))
|
|
{
|
|
case SEARCH_BOX_MINIMUM:
|
|
menu_sub_item[total++] = "Minimum";
|
|
break;
|
|
|
|
case SEARCH_BOX_STANDARD:
|
|
menu_sub_item[total++] = "Standard";
|
|
break;
|
|
|
|
case SEARCH_BOX_ADVANCED:
|
|
menu_sub_item[total++] = "Advanced";
|
|
break;
|
|
|
|
default:
|
|
menu_sub_item[total++] = "<< No Search Box >>";
|
|
break;
|
|
}
|
|
|
|
/* ##### SEARCH LABEL ##### */
|
|
/* NOTE : reversed display */
|
|
ADD_OPTION_MENU_ITEMS("Show Search Labels", TEST_FIELD(cheat_options, DontPrintNewLabels) ? "Off" : "On");
|
|
|
|
/* ##### AUTO SAVE ##### */
|
|
ADD_OPTION_MENU_ITEMS("Auto Save Cheats", TEST_FIELD(cheat_options, AutoSaveEnabled) ? "On" : "Off");
|
|
|
|
/* ##### ACTIVATION KEY MESSAGE ##### */
|
|
ADD_OPTION_MENU_ITEMS("Show Activation Key Message", TEST_FIELD(cheat_options, ActivationKeyMessage) ? "On" : "Off");
|
|
|
|
/* ##### OLD FORMAT LOADING ##### */
|
|
ADD_OPTION_MENU_ITEMS("Load New Format Code", TEST_FIELD(cheat_options, LoadNewCode) ? "On" : "Off");
|
|
|
|
/* ##### OLD FORMAT LOADING ##### */
|
|
ADD_OPTION_MENU_ITEMS("Load Standard Format Code", TEST_FIELD(cheat_options, LoadStandardCode) ? "On" : "Off");
|
|
|
|
/* ##### OLD FORMAT LOADING ##### */
|
|
ADD_OPTION_MENU_ITEMS("Load Old Format Code", TEST_FIELD(cheat_options, LoadOldCode) ? "On" : "Off");
|
|
|
|
/* ##### VERTICAL KEY REPEAT SPEED ##### */
|
|
ADD_OPTION_MENU_ITEMS("Vertical Key Repeat Speed", kNumbersTable[EXTRACT_FIELD(cheat_options, VerticalKeyRepeatSpeed)]);
|
|
|
|
/* ##### HORIZONTAL KEY REPEAT SPEED ##### */
|
|
ADD_OPTION_MENU_ITEMS("Horizontal Key Repeat Speed", kNumbersTable[EXTRACT_FIELD(cheat_options, HorizontalKeyRepeatSpeed)]);
|
|
|
|
#ifdef MESS
|
|
/* ##### SHARED CODE ##### */
|
|
ADD_OPTION_MENU_ITEMS("Shared Code", TEST_FIELD(cheat_options, SharedCode) ? "On" : "Off");
|
|
#endif
|
|
|
|
/* ##### RETURN ##### */
|
|
ADD_OPTION_MENU_ITEMS("Return to Prior Menu", NULL);
|
|
|
|
/* ##### TERMINATOR ##### */
|
|
menu_item[total] = menu_sub_item[total] = NULL;
|
|
#undef ADD_OPTION_MENU_ITEMS
|
|
|
|
/* set left/right arrow for sub item */
|
|
if(menu->sel > SELECT_OPTION_MENU_SEPARATOR && menu->sel < SELECT_OPTION_MENU_RETURN)
|
|
request_arrow = MENU_FLAG_LEFT_ARROW | MENU_FLAG_RIGHT_ARROW;
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, menu_sub_item, NULL, menu->sel, request_arrow);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
|
|
if(menu->sel == SELECT_OPTION_MENU_SEPARATOR)
|
|
menu->sel--;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
|
|
if(menu->sel == SELECT_OPTION_MENU_SEPARATOR)
|
|
menu->sel++;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
do_select = -1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
do_select = 1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case SELECT_OPTION_MENU_SELECT_SEARCH:
|
|
cheat_menu_stack_push(select_search_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case SELECT_OPTION_MENU_LOAD_CHEAT_OPTIONS:
|
|
load_cheat_database(machine, LOAD_CHEAT_OPTIONS);
|
|
break;
|
|
|
|
case SELECT_OPTION_MENU_SAVE_CHEAT_OPTIONS:
|
|
save_cheat_options();
|
|
break;
|
|
|
|
case SELECT_OPTION_MENU_RESET_CHEAT_OPTIONS:
|
|
reset_cheat_options();
|
|
break;
|
|
|
|
case SELECT_OPTION_MENU_RETURN:
|
|
menu->sel = -1;
|
|
|
|
default:
|
|
do_select = 1;
|
|
break;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SAVE_CHEAT))
|
|
{
|
|
save_cheat_options();
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_RELOAD_CHEAT))
|
|
{
|
|
if(shift_key_pressed())
|
|
reset_cheat_options();
|
|
else
|
|
load_cheat_database(machine, LOAD_CHEAT_OPTIONS);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
if(do_select)
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case SELECT_OPTION_MENU_SEARCH_DIALOG_STYLE:
|
|
{
|
|
INT8 search_box = EXTRACT_FIELD(cheat_options, SearchBox) + do_select;
|
|
|
|
if(search_box < 0) search_box = SEARCH_BOX_ADVANCED;
|
|
if(search_box > SEARCH_BOX_ADVANCED) search_box = 0;
|
|
|
|
SET_FIELD(cheat_options, SearchBox, search_box);
|
|
init_search_box(get_current_search(), EXTRACT_FIELD(cheat_options, SearchBox));
|
|
}
|
|
break;
|
|
|
|
case SELECT_OPTION_MENU_SHOW_SEARCH_LABELS: TOGGLE_MASK_FIELD(cheat_options, DontPrintNewLabels); break;
|
|
case SELECT_OPTION_MENU_AUTO_SAVE_CHEATS: TOGGLE_MASK_FIELD(cheat_options, AutoSaveEnabled); break;
|
|
case SELECT_OPTION_MENU_SHOW_ACTIVATION_KEY: TOGGLE_MASK_FIELD(cheat_options, ActivationKeyMessage); break;
|
|
case SELECT_OPTION_MENU_LOAD_NEW_CODE: TOGGLE_MASK_FIELD(cheat_options, LoadNewCode); break;
|
|
case SELECT_OPTION_MENU_LOAD_STANDARD_CODE: TOGGLE_MASK_FIELD(cheat_options, LoadStandardCode); break;
|
|
case SELECT_OPTION_MENU_LOAD_OLD_CODE: TOGGLE_MASK_FIELD(cheat_options, LoadOldCode); break;
|
|
case SELECT_OPTION_MENU_VERTICAL_KEY_SPEED:
|
|
{
|
|
INT8 vertical_speed = (EXTRACT_FIELD(cheat_options, VerticalKeyRepeatSpeed) + do_select) & 0xF;
|
|
|
|
SET_FIELD(cheat_options, VerticalKeyRepeatSpeed, vertical_speed);
|
|
vertical_key_repeat_speed = vertical_speed;
|
|
}
|
|
break;
|
|
case SELECT_OPTION_MENU_HORIZONTAL_KEY_SPEED:
|
|
{
|
|
INT8 horizontal_speed = (EXTRACT_FIELD(cheat_options, HorizontalKeyRepeatSpeed) + do_select) & 0xF;
|
|
|
|
SET_FIELD(cheat_options, HorizontalKeyRepeatSpeed, horizontal_speed);
|
|
horizontal_key_repeat_speed = horizontal_speed;
|
|
}
|
|
break;
|
|
#ifdef MESS
|
|
case SELECT_OPTION_MENU_SHARED_CODE: TOGGLE_MASK_FIELD(cheat_options, SharedCode); break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------
|
|
select_search_menu - management for search selection menu
|
|
------------------------------------------------------------*/
|
|
|
|
static int select_search_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
int i;
|
|
int total = 0;
|
|
const char **menu_item;
|
|
char **buf;
|
|
|
|
/* required items = (total items + return + terminator) + (strings buf * total items) + 300 characters */
|
|
request_strings(search_list_length + 2, search_list_length, 300, 0);
|
|
|
|
menu_item = menu_strings.main_list;
|
|
buf = menu_strings.main_strings;
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
for(i = 0; i < search_list_length; i++)
|
|
{
|
|
search_info *info = &search_list[i];
|
|
|
|
if(i == current_search_idx)
|
|
{
|
|
if(info->name) sprintf(buf[total], "[ #%d: %s ]", i, info->name);
|
|
else sprintf(buf[total], "[ #%d ]", i);
|
|
}
|
|
else
|
|
{
|
|
if(info->name) sprintf(buf[total], "#%d: %s", i, info->name);
|
|
else sprintf(buf[total], "#%d", i);
|
|
}
|
|
|
|
menu_item[total] = buf[total];
|
|
total++;
|
|
}
|
|
|
|
/* ##### RETURN ##### */
|
|
menu_item[total++] = "Return to Prior Menu";
|
|
|
|
/* ##### TERMINATOR ##### */
|
|
menu_item[total] = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, NULL, NULL, menu->sel, 0);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_ADD_CHEAT))
|
|
{
|
|
add_search_before(menu->sel);
|
|
build_search_regions(machine, &search_list[menu->sel]);
|
|
allocate_search_regions(&search_list[menu->sel]);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_DELETE_CHEAT))
|
|
{
|
|
delete_search_at(menu->sel);
|
|
}
|
|
if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(menu->sel < total - 1) current_search_idx = menu->sel;
|
|
else menu->sel = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
command_cheat_menu - management for cheat general command menu
|
|
-----------------------------------------------------------------*/
|
|
|
|
static int command_cheat_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
enum{
|
|
MENU_RELOAD_CHEAT_CODE = 0,
|
|
MENU_SEPARATOR_1,
|
|
MENU_TOGGLE_CHEAT,
|
|
MENU_TOGGLE_WATCHPOINT,
|
|
MENU_SEPARATOR_2,
|
|
MENU_SAVE_DESCRIPTION,
|
|
MENU_SAVE_RAW_CODE,
|
|
MENU_SEPARATOR_3,
|
|
MENU_RETURN,
|
|
MENU_MAX };
|
|
|
|
int total = 0;
|
|
int toggle = 0;
|
|
ui_menu_item menu_item[MENU_MAX + 1];
|
|
|
|
memset(menu_item, 0 , sizeof(menu_item));
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/********** MENU CONSTRUCION **********/
|
|
menu_item[total++].text = "Reload Cheat Codes";
|
|
menu_item[total++].text = MENU_SEPARATOR_ITEM;
|
|
menu_item[total].text = "Cheat";
|
|
menu_item[total++].subtext = cheats_disabled ? "Off" : "On";
|
|
menu_item[total].text = "Watchpoints";
|
|
menu_item[total++].subtext = watches_disabled ? "Off" : "On";
|
|
menu_item[total++].text = MENU_SEPARATOR_ITEM;
|
|
menu_item[total++].text = "Save Description";
|
|
menu_item[total++].text = "Save Raw Code";
|
|
menu_item[total++].text = MENU_SEPARATOR_ITEM;
|
|
menu_item[total++].text = "Return to Prior Menu";
|
|
menu_item[total].text = NULL;
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* print it */
|
|
ui_menu_draw(menu_item, total, menu->sel, NULL);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
|
|
if(menu->sel == MENU_SEPARATOR_1 || menu->sel == MENU_SEPARATOR_2 || menu->sel == MENU_SEPARATOR_3)
|
|
menu->sel--;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
|
|
if(menu->sel == MENU_SEPARATOR_1 || menu->sel == MENU_SEPARATOR_2 || menu->sel == MENU_SEPARATOR_3)
|
|
menu->sel++;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
toggle = 1;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
toggle = 1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case MENU_RELOAD_CHEAT_CODE:
|
|
reload_cheat_database(machine);
|
|
break;
|
|
|
|
case MENU_TOGGLE_CHEAT:
|
|
case MENU_TOGGLE_WATCHPOINT:
|
|
toggle = 1;
|
|
break;
|
|
|
|
case MENU_SAVE_DESCRIPTION:
|
|
save_description(machine);
|
|
break;
|
|
|
|
case MENU_SAVE_RAW_CODE:
|
|
save_raw_code(machine);
|
|
break;
|
|
|
|
case MENU_RETURN:
|
|
menu->sel = -1;
|
|
break;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
if(toggle)
|
|
{
|
|
if(menu->sel == MENU_TOGGLE_CHEAT) cheats_disabled ^= 1;
|
|
else if(menu->sel == MENU_TOGGLE_WATCHPOINT) watches_disabled ^= 1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
#ifdef MAME_DEBUG
|
|
/*-----------------------------------------------------------------------
|
|
check_activation_key_code_menu - key code checker for activation key
|
|
-----------------------------------------------------------------------*/
|
|
|
|
static int check_activation_key_code_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
int code = input_code_poll_switches(FALSE);
|
|
static int index = INPUT_CODE_INVALID;
|
|
char stringsBuf[64];
|
|
char * buf = stringsBuf;
|
|
astring * keyIndex = astring_alloc();
|
|
|
|
if(code != INPUT_CODE_INVALID)
|
|
{
|
|
/* NOTE : if first, no action to prevent from wrong display */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
else
|
|
index = code;
|
|
}
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### HEADER ##### */
|
|
buf += sprintf(buf, "\tPress a key\n");
|
|
|
|
/* ##### KEY NAME / INDEX ##### */
|
|
if(index != INPUT_CODE_INVALID && input_code_pressed(index))
|
|
buf += sprintf(buf, "\t%s\n\t%X\n", astring_c(input_code_name(keyIndex, index)), index);
|
|
else
|
|
buf += sprintf(buf, "\n\n");
|
|
|
|
/* ##### RETURN ##### */
|
|
buf += sprintf(buf, "\t Return = Shift + Cancel ");
|
|
|
|
/* print it */
|
|
ui_draw_message_window(stringsBuf);
|
|
|
|
/* NOTE : shift + cancel is only key to return because normal cancel prevents from diplaying this key */
|
|
if(shift_key_pressed() && input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
index = INPUT_CODE_INVALID;
|
|
menu->sel = -1;
|
|
}
|
|
|
|
astring_free(keyIndex);
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------------------------
|
|
view_cpu_region_info_list_menu - view internal CPU or Region info list called from debug menu
|
|
------------------------------------------------------------------------------------------------*/
|
|
|
|
static int view_cpu_region_info_list_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
enum{
|
|
kMenu_Header = 0,
|
|
kMenu_Type,
|
|
kMenu_DataBits,
|
|
kMenu_AddressBites,
|
|
kMenu_AddressMask,
|
|
kMenu_Endianness,
|
|
kMenu_AddressShift,
|
|
kMenu_Return,
|
|
kMenu_Max };
|
|
|
|
UINT8 total = 0;
|
|
static INT8 index;
|
|
const char ** menuItem;
|
|
const char ** menuSubItem;
|
|
char * headerBuf;
|
|
char * regionNameBuf;
|
|
char * dataBitsBuf;
|
|
char * addressBitsBuf;
|
|
char * addressMaskBuf;
|
|
char * addressShiftBuf;
|
|
cpu_region_info *info;
|
|
|
|
/* required items = total items + (strings buf * 6) + 32 characters */
|
|
request_strings(kMenu_Max, kMenu_Max - 2, 32, 0);
|
|
menuItem = menu_strings.main_list;
|
|
menuSubItem = menu_strings.sub_list;
|
|
headerBuf = menu_strings.main_strings[0];
|
|
regionNameBuf = menu_strings.main_strings[1];
|
|
dataBitsBuf = menu_strings.main_strings[2];
|
|
addressBitsBuf = menu_strings.main_strings[3];
|
|
addressMaskBuf = menu_strings.main_strings[4];
|
|
addressShiftBuf = menu_strings.main_strings[5];
|
|
|
|
/* first setting : set index as 1st */
|
|
if(menu->first_time)
|
|
{
|
|
index = REGION_CPU1 - REGION_INVALID;
|
|
menu->first_time = 0;
|
|
}
|
|
|
|
info = get_region_info(index + REGION_INVALID);
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### HEADER ##### */
|
|
menuItem[total] = "Index";
|
|
sprintf(headerBuf, "%2.2d", index);
|
|
menuSubItem[total++] = headerBuf;
|
|
|
|
/* ##### CPU/REGION TYPE ##### */
|
|
menuItem[total] = "Region";
|
|
|
|
if(index < REGION_CPU8 - REGION_INVALID)
|
|
sprintf(regionNameBuf, "%s (%s)", kRegionNames[index], cputype_name(info->type));
|
|
else
|
|
sprintf(regionNameBuf, "%s (non-cpu)", kRegionNames[info->type - REGION_CPU1 + 1]);
|
|
menuSubItem[total++] = regionNameBuf;
|
|
|
|
/* ##### DATA BITS ##### */
|
|
menuItem[total] = "Data Bits";
|
|
sprintf(dataBitsBuf, "%d", info->data_bits);
|
|
menuSubItem[total++] = dataBitsBuf;
|
|
|
|
/* ##### ADDRESS BITS ##### */
|
|
menuItem[total] = "Address Bits";
|
|
sprintf(addressBitsBuf, "%d", info->address_bits);
|
|
menuSubItem[total++] = addressBitsBuf;
|
|
|
|
/* ##### ADDRESS MASK/LENGTH ##### */
|
|
menuItem[total] = "Address Mask";
|
|
sprintf(addressMaskBuf, "%X (%d)", info->address_mask, info->address_chars_needed);
|
|
menuSubItem[total++] = addressMaskBuf;
|
|
|
|
/* ##### ENDIANNESS ##### */
|
|
menuItem[total] = "Endianness";
|
|
menuSubItem[total++] = info->endianness ? "Big" : "Little";
|
|
|
|
/* ##### ADDRESS SHIFT ##### */
|
|
menuItem[total] = "AddressShift";
|
|
sprintf(addressShiftBuf, "%d", info->address_shift);
|
|
menuSubItem[total++] = addressShiftBuf;
|
|
|
|
/* ##### RETURN ##### */
|
|
menuItem[total] = "Return to Prior Menu";
|
|
menuSubItem[total++] = NULL;
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menuItem[total] = NULL;
|
|
menuSubItem[total] = NULL;
|
|
|
|
/* draw it */
|
|
old_style_menu(menuItem, menuSubItem, NULL, menu->sel, 0);
|
|
|
|
/* adjust current cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_RIGHT, horizontal_key_repeat_speed))
|
|
{
|
|
int i = index + 1;
|
|
|
|
/* search next valid info list */
|
|
while(1)
|
|
{
|
|
if(i >= REGION_LIST_LENGTH - 1)
|
|
{
|
|
i = 0;
|
|
continue;
|
|
}
|
|
|
|
if(region_info_list[i].type)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_LEFT, horizontal_key_repeat_speed))
|
|
{
|
|
int i = index - 1;
|
|
|
|
/* search previous valid info list */
|
|
while(1)
|
|
{
|
|
if(i < 0)
|
|
{
|
|
i = REGION_LIST_LENGTH - 1;
|
|
continue;
|
|
}
|
|
|
|
if(region_info_list[i].type)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
else
|
|
i--;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
if(menu->sel == kMenu_Return)
|
|
menu->sel = -1;
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------
|
|
debug_cheat_menu - view internal cheat engine data
|
|
-----------------------------------------------------*/
|
|
|
|
static int debug_cheat_menu(running_machine *machine, cheat_menu_stack *menu)
|
|
{
|
|
#define ADD_DEBUG_MENU_ITEMS(name, sub_name) \
|
|
do { menu_item[total] = name; menu_sub_item[total] = sub_name; total++; } while(0)
|
|
|
|
enum{
|
|
DEBUG_MENU_SOURCE = 0,
|
|
DEBUG_MENU_GAME_NAME,
|
|
#ifdef MESS
|
|
DEBUG_MENU_CRC,
|
|
#endif
|
|
DEBUG_MENU_DEFAULT_HEIGHT,
|
|
DEBUG_MENU_TOTAL_CODES,
|
|
DEBUG_MENU_SEPARATOR,
|
|
DEBUG_MENU_VIEW_CPU_REGION_INFO,
|
|
DEBUG_MENU_CHECK_KEY,
|
|
DEBUG_MENU_RETURN,
|
|
|
|
DEBUG_MENU_MAX };
|
|
|
|
int total = 0;
|
|
const char **menu_item;
|
|
const char **menu_sub_item;
|
|
char *buf_source;
|
|
#ifdef MESS
|
|
char *buf_crc;
|
|
#endif
|
|
char *buf_height;
|
|
char *buf_num_codes;
|
|
astring *source_name = astring_alloc();
|
|
|
|
/* first setting : NONE */
|
|
if(menu->first_time)
|
|
menu->first_time = 0;
|
|
|
|
/* required items = (total items + return + terminator) + (strings buf * total items) + 64 characters */
|
|
request_strings(DEBUG_MENU_MAX + 2, DEBUG_MENU_MAX, 64, 0);
|
|
menu_item = menu_strings.main_list;
|
|
menu_sub_item = menu_strings.sub_list;
|
|
buf_source = menu_strings.main_strings[0];
|
|
buf_height = menu_strings.main_strings[1];
|
|
buf_num_codes = menu_strings.main_strings[2];
|
|
#ifdef MESS
|
|
buf_crc = menu_strings.main_strings[3];
|
|
#endif
|
|
|
|
/********** MENU CONSTRUCTION **********/
|
|
/* ##### SOURCE ##### */
|
|
sprintf(buf_source, "%s", astring_c(core_filename_extract_base(source_name, machine->gamedrv->source_file, TRUE)));
|
|
ADD_DEBUG_MENU_ITEMS("Source", buf_source);
|
|
|
|
/* ##### MACHINE ##### */
|
|
#ifdef MESS
|
|
ADD_DEBUG_MENU_ITEMS("Machine", machine->gamedrv->name);
|
|
|
|
/* ##### CRC ##### */
|
|
sprintf(buf_crc, "%.8X", thisGameCRC);
|
|
ADD_DEBUG_MENU_ITEMS("CRC", buf_crc);
|
|
#else
|
|
/* ##### GAME ##### */
|
|
ADD_DEBUG_MENU_ITEMS("Game", machine->gamedrv->name);
|
|
#endif
|
|
|
|
/* ##### DEFAULT MENU HEIGHT ##### */
|
|
sprintf(buf_height, "%d", full_menu_page_height);
|
|
ADD_DEBUG_MENU_ITEMS("Default Menu Height", buf_height);
|
|
|
|
/* ##### CHEAT LIST LENGTH ##### */
|
|
sprintf(buf_num_codes, "%d", cheat_list_length);
|
|
ADD_DEBUG_MENU_ITEMS("Total Entry Codes", buf_num_codes);
|
|
|
|
/* ##### SEPARATOR ##### */
|
|
ADD_DEBUG_MENU_ITEMS(MENU_SEPARATOR_ITEM, NULL);
|
|
|
|
/* ##### CPU/REGION INFO ##### */
|
|
ADD_DEBUG_MENU_ITEMS("View CPU/Region Info", NULL);
|
|
|
|
/* ##### ACTIVATION KEY CODE CHEAKCER ##### */
|
|
ADD_DEBUG_MENU_ITEMS("Check Activation Key Index", NULL);
|
|
|
|
/* ##### RETURN ##### */
|
|
ADD_DEBUG_MENU_ITEMS("Return to Prior Menu", NULL);
|
|
|
|
/* ##### TERMINATE ARRAY ##### */
|
|
menu_item[total] = menu_sub_item[total] = NULL;
|
|
#undef ADD_DEBUG_MENU_ITEMS
|
|
|
|
/* adjust cursor position */
|
|
ADJUST_CURSOR(menu->sel, total);
|
|
|
|
/* draw it */
|
|
old_style_menu(menu_item, menu_sub_item, NULL, menu->sel, 0);
|
|
|
|
/********** KEY HANDLING **********/
|
|
if(ui_pressed_repeat_throttle(machine, IPT_UI_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_PREVIOUS(menu->sel, total);
|
|
|
|
if(menu->sel == DEBUG_MENU_SEPARATOR)
|
|
menu->sel--;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_TO_NEXT(menu->sel, total);
|
|
|
|
if(menu->sel == DEBUG_MENU_SEPARATOR)
|
|
menu->sel++;
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_UP, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_UP(menu->sel);
|
|
}
|
|
else if(ui_pressed_repeat_throttle(machine, IPT_UI_PAGE_DOWN, vertical_key_repeat_speed))
|
|
{
|
|
CURSOR_PAGE_DOWN(menu->sel, total);
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_SELECT))
|
|
{
|
|
switch(menu->sel)
|
|
{
|
|
case DEBUG_MENU_VIEW_CPU_REGION_INFO:
|
|
cheat_menu_stack_push(view_cpu_region_info_list_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case DEBUG_MENU_CHECK_KEY:
|
|
cheat_menu_stack_push(check_activation_key_code_menu, menu->handler, menu->sel);
|
|
break;
|
|
|
|
case DEBUG_MENU_RETURN:
|
|
menu->sel = -1;
|
|
break;
|
|
}
|
|
}
|
|
else if(input_ui_pressed(machine, IPT_UI_CANCEL))
|
|
{
|
|
menu->sel = -1;
|
|
}
|
|
|
|
astring_free(source_name);
|
|
|
|
return menu->sel + 1;
|
|
}
|
|
#endif
|
|
/*------------------
|
|
cheate_periodic
|
|
------------------*/
|
|
|
|
static TIMER_CALLBACK( cheat_periodic )
|
|
{
|
|
int i;
|
|
|
|
if(input_ui_pressed(machine, IPT_UI_TOGGLE_CHEAT))
|
|
{
|
|
if(shift_key_pressed())
|
|
{
|
|
/* ##### WATCHPOINT ##### */
|
|
watches_disabled ^= 1;
|
|
|
|
ui_popup_time(1, "Watchpoints %s", watches_disabled ? "Off" : "On");
|
|
}
|
|
else
|
|
{
|
|
/* ##### CHEAT ##### */
|
|
cheats_disabled ^= 1;
|
|
|
|
ui_popup_time(1, "Cheats %s", cheats_disabled ? "Off" : "On");
|
|
|
|
if(cheats_disabled)
|
|
{
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
temp_deactivate_cheat(machine, &cheat_list[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(cheats_disabled)
|
|
return;
|
|
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
{
|
|
cheat_entry *entry = &cheat_list[i];
|
|
|
|
if(entry->flags & kCheatFlag_OldFormat)
|
|
cheat_periodic_old_entry(machine, entry);
|
|
else
|
|
cheat_periodic_entry(machine, entry);
|
|
}
|
|
}
|
|
|
|
/*---------------
|
|
print_binary
|
|
---------------*/
|
|
|
|
static UINT32 print_binary(char *buf, UINT32 data, UINT32 mask)
|
|
{
|
|
UINT32 traverse = 0x80000000;
|
|
UINT32 written = 0;
|
|
|
|
while(traverse)
|
|
{
|
|
if(mask & traverse)
|
|
{
|
|
*buf++ = (data & traverse) ? '1' : '0';
|
|
written++;
|
|
}
|
|
|
|
traverse >>= 1;
|
|
}
|
|
|
|
*buf++ = 0;
|
|
|
|
return written;
|
|
}
|
|
|
|
/*--------------
|
|
print_ascii
|
|
--------------*/
|
|
|
|
static UINT32 print_ascii(char *buf, UINT32 data, UINT8 size)
|
|
{
|
|
switch(size)
|
|
{
|
|
case kSearchSize_8Bit:
|
|
case kSearchSize_1Bit:
|
|
default:
|
|
buf[0] = (data >> 0) & 0xFF;
|
|
buf[1] = 0;
|
|
|
|
return 1;
|
|
|
|
case kSearchSize_16Bit:
|
|
buf[0] = (data >> 8) & 0xFF;
|
|
buf[1] = (data >> 0) & 0xFF;
|
|
buf[2] = 0;
|
|
|
|
return 2;
|
|
|
|
case kSearchSize_24Bit:
|
|
buf[0] = (data >> 16)& 0xFF;
|
|
buf[1] = (data >> 8) & 0xFF;
|
|
buf[2] = (data >> 0) & 0xFF;
|
|
buf[3] = 0;
|
|
|
|
return 3;
|
|
|
|
case kSearchSize_32Bit:
|
|
buf[0] = (data >> 24) & 0xFF;
|
|
buf[1] = (data >> 16) & 0xFF;
|
|
buf[2] = (data >> 8) & 0xFF;
|
|
buf[3] = (data >> 0) & 0xFF;
|
|
buf[4] = 0;
|
|
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------
|
|
cheat_display_watches - display watchpoint
|
|
---------------------------------------------*/
|
|
|
|
void cheat_display_watches(running_machine *machine)
|
|
{
|
|
int i;
|
|
|
|
if(watches_disabled)
|
|
return;
|
|
|
|
for(i = 0; i < watch_list_length; i++)
|
|
{
|
|
watch_info *info = &watch_list[i];
|
|
int j;
|
|
int num_chars;
|
|
int x_offset = 0;
|
|
int y_offset = 0;
|
|
int line_elements = 0;
|
|
UINT8 *buf = NULL;
|
|
UINT32 address = info->address;
|
|
UINT32 data = 0;
|
|
char display_buf[1024] = { 0 };
|
|
|
|
if(info->num_elements)
|
|
{
|
|
/* ##### LABEL ##### */
|
|
switch(info->label_type)
|
|
{
|
|
case kWatchLabel_Address:
|
|
num_chars = sprintf(display_buf, "%.8X: ", info->address);
|
|
|
|
ui_draw_text(display_buf, x_offset * ui_get_char_width('0') + info->x, y_offset * ui_get_line_height() + info->y);
|
|
x_offset += num_chars;
|
|
break;
|
|
|
|
case kWatchLabel_String:
|
|
num_chars = sprintf(display_buf, "%s: ", info->label);
|
|
|
|
ui_draw_text(display_buf, x_offset * ui_get_char_width('0') + info->x, y_offset * ui_get_line_height() + info->y);
|
|
x_offset += num_chars;
|
|
break;
|
|
}
|
|
|
|
/* ##### VALUE ##### */
|
|
for(j = 0; j < info->num_elements; j++)
|
|
{
|
|
if(info->cpu < REGION_INVALID)
|
|
{
|
|
/* NOTE : do_cpu_read() conflicts with a watchpoint for debugger */
|
|
UINT8 cpu = EXTRACT_FIELD(info->cpu, CPUIndex);
|
|
|
|
buf = (UINT8 *)get_memory_region_base_pointer(cpu, EXTRACT_FIELD(info->cpu, AddressSpace), address);
|
|
if(buf)
|
|
data = do_memory_read(buf, address, BYTE_INCREMENT_TABLE[info->element_bytes], cpu_needs_swap(cpu) + info->add_value, get_cpu_info(cpu));
|
|
}
|
|
else
|
|
{
|
|
buf = memory_region(machine, info->cpu);
|
|
if(buf)
|
|
data = do_memory_read(buf, address, BYTE_INCREMENT_TABLE[info->element_bytes], region_needs_swap(info->cpu) + info->add_value, get_region_info(info->cpu));
|
|
}
|
|
|
|
if(buf == NULL)
|
|
{
|
|
ui_popup_time(1, "watchpoints (%d) memory read error", i);
|
|
return;
|
|
}
|
|
|
|
data &= BYTE_MASK_TABLE[info->element_bytes];
|
|
data = do_shift(data, info->data_shift);
|
|
data ^= info->xor;
|
|
|
|
if(line_elements >= info->elements_per_line && info->elements_per_line)
|
|
{
|
|
line_elements = 0;
|
|
x_offset = 0;
|
|
y_offset++;
|
|
}
|
|
|
|
switch(info->display_type)
|
|
{
|
|
case kWatchDisplayType_Hex:
|
|
num_chars = sprintf(display_buf, "%.*X", BYTE_DIGITS_TABLE[info->element_bytes], data);
|
|
|
|
ui_draw_text(display_buf, x_offset * ui_get_char_width('0') + info->x, y_offset * ui_get_line_height() + info->y);
|
|
x_offset += num_chars;
|
|
x_offset++;
|
|
break;
|
|
|
|
case kWatchDisplayType_Decimal:
|
|
num_chars = sprintf(display_buf, "%.*d", BYTE_DEC_DIGITS_TABLE[info->element_bytes], data);
|
|
|
|
ui_draw_text(display_buf, x_offset * ui_get_char_width('0') + info->x, y_offset * ui_get_line_height() + info->y);
|
|
x_offset += num_chars;
|
|
x_offset++;
|
|
break;
|
|
|
|
case kWatchDisplayType_Binary:
|
|
num_chars = print_binary(display_buf, data, BYTE_MASK_TABLE[info->element_bytes]);
|
|
|
|
ui_draw_text(display_buf, x_offset * ui_get_char_width('0') + info->x, y_offset * ui_get_line_height() + info->y);
|
|
x_offset += num_chars;
|
|
x_offset++;
|
|
break;
|
|
|
|
case kWatchDisplayType_ASCII:
|
|
num_chars = print_ascii(display_buf, data, info->element_bytes);
|
|
|
|
ui_draw_text(display_buf, x_offset * ui_get_char_width('0') + info->x, y_offset * ui_get_line_height() + info->y);
|
|
x_offset += num_chars;
|
|
break;
|
|
}
|
|
|
|
address += BYTE_INCREMENT_TABLE[info->element_bytes] + info->skip;
|
|
line_elements++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------
|
|
resize_cheat_list - memory allocation for cheat entry
|
|
--------------------------------------------------------*/
|
|
|
|
static void resize_cheat_list(UINT32 new_length, UINT8 dispose)
|
|
{
|
|
if(new_length != cheat_list_length)
|
|
{
|
|
/* ??? REQUEST_DISPOSE is only when INSERT right now so that it's meaningless ??? */
|
|
if(dispose == REQUEST_DISPOSE)
|
|
{
|
|
/* free cheat entry if delete */
|
|
if(new_length < cheat_list_length)
|
|
{
|
|
int i;
|
|
|
|
for(i = new_length; i < cheat_list_length; i++)
|
|
dispose_cheat(&cheat_list[i]);
|
|
}
|
|
}
|
|
|
|
/* reallocate cheat entry */
|
|
cheat_list = realloc(cheat_list, new_length * sizeof(cheat_entry));
|
|
|
|
if(cheat_list == NULL && new_length != 0)
|
|
{
|
|
fatalerror("cheat: [cheat entry] memory allocation error\n"
|
|
" length = %.8X\n"
|
|
" new_length = %.8X\n"
|
|
" cheat_list = %p\n",
|
|
cheat_list_length, new_length, cheat_list);
|
|
}
|
|
|
|
/* add new entry if insert */
|
|
if(new_length > cheat_list_length)
|
|
{
|
|
int i;
|
|
|
|
memset(&cheat_list[cheat_list_length], 0, (new_length - cheat_list_length) * sizeof(cheat_entry));
|
|
|
|
/* set dirty flag to inserted entry */
|
|
for(i = cheat_list_length; i < new_length; i++)
|
|
cheat_list[i].flags |= kCheatFlag_Dirty;
|
|
}
|
|
|
|
cheat_list_length = new_length;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
add_cheat_before - insert new cheat entry before selected code
|
|
-----------------------------------------------------------------*/
|
|
|
|
static void add_cheat_before(UINT32 idx)
|
|
{
|
|
/* insert new cheat entry */
|
|
resize_cheat_list(cheat_list_length + 1, REQUEST_DISPOSE);
|
|
|
|
/* pack later entry if inserting point is not last */
|
|
if(idx < cheat_list_length - 1)
|
|
memmove(&cheat_list[idx + 1], &cheat_list[idx], sizeof(cheat_entry) * (cheat_list_length - 1 - idx));
|
|
|
|
if(idx >= cheat_list_length)
|
|
idx = cheat_list_length - 1;
|
|
|
|
/* initialize inserted entry */
|
|
memset(&cheat_list[idx], 0, sizeof(cheat_entry));
|
|
|
|
/* set entry flags */
|
|
cheat_list[idx].flags |= kCheatFlag_Dirty;
|
|
|
|
/* insert new cheat action together */
|
|
resize_cheat_action_list(&cheat_list[idx], 1, REQUEST_DISPOSE);
|
|
|
|
/* set action parameters/flags */
|
|
cheat_list[idx].action_list[0].extend_data = ~0;
|
|
cheat_list[idx].action_list[0].last_value = NULL;
|
|
cheat_list[idx].action_list[0].flags |= kActionFlag_MemoryWrite;
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_ADD);
|
|
}
|
|
|
|
/*------------------------------------------------
|
|
delete_cheat_at - delete selected cheat entry
|
|
------------------------------------------------*/
|
|
|
|
static void delete_cheat_at(UINT32 idx)
|
|
{
|
|
/* if selected point is not cheat entry, no action */
|
|
if(idx >= cheat_list_length)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_DELETE);
|
|
return;
|
|
}
|
|
|
|
/* free selected cheat entry */
|
|
dispose_cheat(&cheat_list[idx]);
|
|
|
|
/* pack later cheat entry if selected point is not last */
|
|
if(idx < cheat_list_length - 1)
|
|
{
|
|
memmove(&cheat_list[idx], &cheat_list[idx + 1], sizeof(cheat_entry) * (cheat_list_length - 1 - idx));
|
|
}
|
|
|
|
/* realloc cheat entry */
|
|
resize_cheat_list(cheat_list_length - 1, NO_DISPOSE);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_DELETE);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
dispose_cheat - free selected cheat entry and all cheat actions in this entry
|
|
--------------------------------------------------------------------------------*/
|
|
|
|
static void dispose_cheat(cheat_entry *entry)
|
|
{
|
|
if(entry)
|
|
{
|
|
int i;
|
|
|
|
free(entry->name);
|
|
free(entry->comment);
|
|
free(entry->label_index);
|
|
|
|
/* free all cheat actions in selected entry */
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
dispose_action(&entry->action_list[i]);
|
|
|
|
free(entry->action_list);
|
|
|
|
memset(entry, 0, sizeof(cheat_entry));
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------------
|
|
get_new_cheat - return pointer to new cheat entry inserted at last position
|
|
-------------------------------------------------------------------------------*/
|
|
|
|
static cheat_entry *get_new_cheat(void)
|
|
{
|
|
/* insert new cheat entry at last position */
|
|
add_cheat_before(cheat_list_length);
|
|
|
|
return &cheat_list[cheat_list_length - 1];
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
resize_cheat_action_list - reallocate cheat action in selected entry
|
|
-----------------------------------------------------------------------*/
|
|
|
|
static void resize_cheat_action_list(cheat_entry *entry, UINT32 new_length, UINT8 dispose)
|
|
{
|
|
if(new_length != entry->action_list_length)
|
|
{
|
|
if(dispose == REQUEST_DISPOSE)
|
|
{
|
|
/* free cheat action if delete */
|
|
if(new_length < entry->action_list_length)
|
|
{
|
|
int i;
|
|
|
|
for(i = new_length; i < entry->action_list_length; i++)
|
|
dispose_action(&entry->action_list[i]);
|
|
}
|
|
}
|
|
|
|
/* reallocate cheat action */
|
|
entry->action_list = realloc(entry->action_list, new_length * sizeof(cheat_action));
|
|
|
|
if(entry->action_list == NULL && new_length != 0)
|
|
{
|
|
fatalerror("cheat: [cheat action] memory allocation error\n"
|
|
" length = %.8X\n"
|
|
" new_length = %.8X\n"
|
|
" action_list = %p\n",
|
|
entry->action_list_length, new_length, entry->action_list);
|
|
}
|
|
|
|
/* add new action if insert */
|
|
if(new_length > entry->action_list_length)
|
|
{
|
|
memset(&entry->action_list[entry->action_list_length], 0, (new_length - entry->action_list_length) * sizeof(cheat_action));
|
|
}
|
|
|
|
entry->action_list_length = new_length;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------
|
|
add_action_before - insert new cheat action
|
|
---------------------------------------------*/
|
|
|
|
static void add_action_before(cheat_entry *entry, UINT32 idx)
|
|
{
|
|
resize_cheat_action_list(entry, entry->action_list_length + 1, REQUEST_DISPOSE);
|
|
|
|
if(idx < (entry->action_list_length - 1))
|
|
memmove(&entry->action_list[idx + 1], &entry->action_list[idx], sizeof(cheat_action) * (entry->action_list_length - 1 - idx));
|
|
|
|
if(idx >= entry->action_list_length)
|
|
idx = entry->action_list_length - 1;
|
|
|
|
memset(&entry->action_list[idx], 0, sizeof(cheat_action));
|
|
|
|
cheat_list[idx].action_list[0].extend_data = ~0;
|
|
cheat_list[idx].action_list[0].last_value = NULL;
|
|
cheat_list[idx].action_list[0].flags |= kActionFlag_OldFormat;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
delete_action_at - delete selected cheat action
|
|
--------------------------------------------------*/
|
|
|
|
static void delete_action_at(cheat_entry *entry, UINT32 idx)
|
|
{
|
|
if(idx == 0 || idx >= entry->action_list_length)
|
|
{
|
|
/* NOTE : don't delete 1st cheat action due to crash */
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_DELETE);
|
|
return;
|
|
}
|
|
|
|
dispose_action(&entry->action_list[idx]);
|
|
|
|
if(idx < (entry->action_list_length - 1))
|
|
memmove(&entry->action_list[idx], &entry->action_list[idx + 1], sizeof(cheat_action) * (entry->action_list_length - 1 - idx));
|
|
|
|
resize_cheat_action_list(entry, entry->action_list_length - 1, NO_DISPOSE);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_DELETE);
|
|
}
|
|
/*----------------------------------------------
|
|
dispose_action - free selected cheat action
|
|
----------------------------------------------*/
|
|
|
|
static void dispose_action(cheat_action *action)
|
|
{
|
|
if(action != NULL)
|
|
{
|
|
free(action->optional_name);
|
|
free(action->last_value);
|
|
|
|
memset(action, 0, sizeof(cheat_action));
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------
|
|
init_watch - initialize a value for watchpoint
|
|
-------------------------------------------------*/
|
|
|
|
static void init_watch(watch_info *info, UINT32 idx)
|
|
{
|
|
|
|
/* NOTE : 1st watchpoint should be always Y = 0 */
|
|
if(idx > 0)
|
|
info->y = watch_list[idx - 1].y + ui_get_line_height();
|
|
else
|
|
info->y = 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------
|
|
resize_watch_list - reallocate watch list if different size
|
|
--------------------------------------------------------------*/
|
|
|
|
static void resize_watch_list(UINT32 new_length, UINT8 dispose)
|
|
{
|
|
if(new_length != watch_list_length)
|
|
{
|
|
/* NOTE : dispose flag is only set when called from delete_watch_at() */
|
|
if(dispose)
|
|
{
|
|
/* if delete, free deleted or later watch list */
|
|
if(new_length < watch_list_length)
|
|
{
|
|
int i;
|
|
|
|
for(i = new_length; i < watch_list_length; i++)
|
|
dispose_watch(&watch_list[i]);
|
|
}
|
|
}
|
|
|
|
/* reallocate watch list */
|
|
watch_list = realloc(watch_list, new_length * sizeof(watch_info));
|
|
|
|
if(watch_list == NULL && new_length != 0)
|
|
{
|
|
/* memory allocation error */
|
|
fatalerror( "cheat : [watch list] memory allocation error\n"
|
|
" length = %.8X\n"
|
|
" new_length = %.8X\n"
|
|
" watch_list = %p\n",
|
|
watch_list_length, new_length, watch_list);
|
|
}
|
|
|
|
/* if insert, move later watch list */
|
|
if(new_length > watch_list_length)
|
|
{
|
|
int i;
|
|
|
|
memset(&watch_list[watch_list_length], 0, (new_length - watch_list_length) * sizeof(watch_info));
|
|
|
|
for(i = watch_list_length; i < new_length; i++)
|
|
init_watch(&watch_list[i], i);
|
|
}
|
|
|
|
watch_list_length = new_length;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------
|
|
add_watch_before - insert new watch list
|
|
-------------------------------------------*/
|
|
|
|
static void add_watch_before(UINT32 idx)
|
|
{
|
|
/* reallocate watch list */
|
|
resize_watch_list(watch_list_length + 1, 0);
|
|
|
|
/* if insert position is not last, move later watch list */
|
|
if(idx < watch_list_length - 1)
|
|
memmove(&watch_list[idx + 1], &watch_list[idx], sizeof(watch_info) * (watch_list_length - 1 - idx));
|
|
else
|
|
idx = watch_list_length - 1;
|
|
|
|
/* memory initialize */
|
|
memset(&watch_list[idx], 0, sizeof(watch_info));
|
|
|
|
init_watch(&watch_list[idx], idx);
|
|
}
|
|
|
|
/*------------------------------------------------
|
|
delete_watch_at - delete selected watch point
|
|
------------------------------------------------*/
|
|
|
|
static void delete_watch_at(UINT32 idx)
|
|
{
|
|
/* if selected item is not watchpoint, no delete */
|
|
if(idx >= watch_list_length)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_DELETE);
|
|
return;
|
|
}
|
|
|
|
/* free selected watch list */
|
|
dispose_watch(&watch_list[idx]);
|
|
|
|
/* move later watch list */
|
|
memmove(&watch_list[idx], &watch_list[idx + 1], sizeof(watch_info) * (watch_list_length - 1 - idx));
|
|
|
|
/* reallocate watch list */
|
|
resize_watch_list(watch_list_length - 1, 1);
|
|
}
|
|
|
|
/*-------------------------------------------------
|
|
dispose_watch - initialize selected watch list
|
|
-------------------------------------------------*/
|
|
|
|
static void dispose_watch(watch_info *watch)
|
|
{
|
|
memset(watch, 0, sizeof(watch_info));
|
|
}
|
|
|
|
/*--------------------------------------------
|
|
get_unused_watch - find unused watchpoint
|
|
--------------------------------------------*/
|
|
|
|
static watch_info *get_unused_watch(void)
|
|
{
|
|
int i;
|
|
watch_info *info;
|
|
watch_info *the_watch = NULL;
|
|
|
|
/* search unused watchpoint */
|
|
for(i = 0; i < watch_list_length; i++)
|
|
{
|
|
info = &watch_list[i];
|
|
|
|
/* NOTE : "unused" means "undisplayed" */
|
|
if(info->num_elements == 0)
|
|
{
|
|
the_watch = info;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if all watchpoints are used, insert new watchpoint */
|
|
if(the_watch == NULL)
|
|
{
|
|
add_watch_before(watch_list_length);
|
|
|
|
the_watch = &watch_list[watch_list_length - 1];
|
|
}
|
|
|
|
return the_watch;
|
|
}
|
|
|
|
/*------------------------------------------------------------
|
|
add_cheat_from_watch - add new cheat code from watchpoint
|
|
------------------------------------------------------------*/
|
|
|
|
static void add_cheat_from_watch(running_machine *machine, watch_info *watch)
|
|
{
|
|
if(watch)
|
|
{
|
|
int temp_string_length;
|
|
char temp_string[1024];
|
|
cheat_entry *entry = get_new_cheat();
|
|
cheat_action *action = &entry->action_list[0];
|
|
|
|
/* set parameters */
|
|
action->region = watch->cpu;
|
|
action->address = watch->address;
|
|
action->original_address = watch->address;
|
|
action->extend_data = ~0;
|
|
action->last_value = NULL;
|
|
action->data = read_data(machine, action);
|
|
SET_FIELD(action->type, AddressSize, watch->element_bytes);
|
|
|
|
/* set name */
|
|
temp_string_length = sprintf(temp_string, "%.8X (%d) = %.*X", watch->address, watch->cpu, BYTE_DIGITS_TABLE[watch->element_bytes], action->data);
|
|
entry->name = create_string_copy(temp_string);
|
|
|
|
update_cheat_info(machine, entry, 0);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_ADD);
|
|
}
|
|
else
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_ADD);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
add_cheat_from_watch_as_watch - add new watchpoint cheat from watchpoint
|
|
---------------------------------------------------------------------------*/
|
|
|
|
static void add_cheat_from_watch_as_watch(running_machine *machine, cheat_entry *entry, watch_info *watch)
|
|
{
|
|
/* NOTE : don't add in case of undisplayed watchpoint */
|
|
if(watch && entry && watch->num_elements)
|
|
{
|
|
char temp_string[256];
|
|
cheat_action *action;
|
|
|
|
/* free then add new cheat entry */
|
|
dispose_cheat(entry);
|
|
resize_cheat_action_list(entry, 1, REQUEST_DISPOSE);
|
|
action = &entry->action_list[0];
|
|
|
|
/* set name and comments */
|
|
sprintf(temp_string, "Watch %.8X (%d)", watch->address, watch->cpu);
|
|
|
|
entry->name = create_string_copy(temp_string);
|
|
entry->comment = create_string_copy(watch->label);
|
|
|
|
/* set parameters */
|
|
action->region = watch->cpu;
|
|
action->address = watch->address;
|
|
action->original_address = watch->address;
|
|
action->original_data = action->data;
|
|
action->extend_data = ~0;
|
|
|
|
SET_FIELD(action->type, CodeType, kCodeType_Watch);
|
|
SET_FIELD(action->type, AddressSize, BYTE_INCREMENT_TABLE[watch->element_bytes] - 1);
|
|
SET_FIELD(action->data, WatchNumElements, watch->num_elements - 1);
|
|
SET_FIELD(action->data, WatchSkip, watch->skip);
|
|
SET_FIELD(action->data, WatchElementsPerLine, watch->elements_per_line);
|
|
SET_FIELD(action->data, WatchAddValue, watch->add_value);
|
|
|
|
update_cheat_info(machine, entry, 0);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_ADD);
|
|
}
|
|
else
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_ADD);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
reset_watch - clear data in selected watch list except the position
|
|
----------------------------------------------------------------------*/
|
|
|
|
static void reset_watch(watch_info *watch)
|
|
{
|
|
if(watch)
|
|
{
|
|
watch->address = 0;
|
|
watch->cpu = 0;
|
|
watch->num_elements = 0;
|
|
watch->element_bytes = kWatchSizeConversionTable[0];
|
|
watch->label_type = kWatchLabel_None;
|
|
watch->display_type = kWatchDisplayType_Hex;
|
|
watch->skip = 0;
|
|
watch->elements_per_line = 0;
|
|
watch->add_value = 0;
|
|
watch->address_shift = 0;
|
|
watch->data_shift = 0;
|
|
watch->xor = 0;
|
|
watch->linked_cheat = NULL;
|
|
watch->label[0] = 0;
|
|
}
|
|
else
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_DELETE);
|
|
}
|
|
|
|
/*------------------------------------------------------------------
|
|
resize_search_list - reallocate search list if different length
|
|
------------------------------------------------------------------*/
|
|
|
|
static void resize_search_list(UINT32 new_length, UINT8 dispose)
|
|
{
|
|
if(new_length != search_list_length)
|
|
{
|
|
/* free search list if delete */
|
|
if(dispose == REQUEST_DISPOSE)
|
|
{
|
|
if(new_length < search_list_length)
|
|
{
|
|
int i;
|
|
|
|
for(i = new_length; i < search_list_length; i++)
|
|
dispose_search(&search_list[i]);
|
|
}
|
|
}
|
|
|
|
/* reallocate search list */
|
|
search_list = realloc(search_list, new_length * sizeof(search_info));
|
|
|
|
if(search_list == NULL && new_length != 0)
|
|
{
|
|
fatalerror("cheat: [search info] memory allocation error\n"
|
|
" length = %.8X\n"
|
|
" new_length = %.8X\n"
|
|
" search_list = %p\n",
|
|
search_list_length, new_length, search_list);
|
|
}
|
|
|
|
/* add new search list if insert */
|
|
if(new_length > search_list_length)
|
|
memset(&search_list[search_list_length], 0, (new_length - search_list_length) * sizeof(search_info));
|
|
|
|
search_list_length = new_length;
|
|
}
|
|
}
|
|
|
|
/*--------------------
|
|
add_search_before
|
|
--------------------*/
|
|
|
|
static void add_search_before(UINT32 idx)
|
|
{
|
|
resize_search_list(search_list_length + 1, NO_DISPOSE);
|
|
|
|
if(idx < search_list_length - 1)
|
|
memmove(&search_list[idx + 1], &search_list[idx], sizeof(search_info) * (search_list_length - 1 - idx));
|
|
|
|
if(idx >= search_list_length)
|
|
idx = search_list_length - 1;
|
|
|
|
memset(&search_list[idx], 0, sizeof(search_info));
|
|
init_search(&search_list[idx]);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_ADD);
|
|
}
|
|
|
|
/*-------------------
|
|
delete_search_at
|
|
-------------------*/
|
|
|
|
static void delete_search_at(UINT32 idx)
|
|
{
|
|
if(idx < search_list_length && search_list_length > 1)
|
|
{
|
|
dispose_search(&search_list[idx]);
|
|
|
|
if(idx < (search_list_length - 1))
|
|
memmove(&search_list[idx], &search_list[idx + 1], sizeof(search_info) * (search_list_length - 1 - idx));
|
|
|
|
resize_search_list(search_list_length - 1, NO_DISPOSE);
|
|
|
|
if(current_search_idx > search_list_length - 1)
|
|
current_search_idx = search_list_length - 1;
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_DELETE);
|
|
}
|
|
else
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_DELETE);
|
|
}
|
|
|
|
/*---------------------------------------
|
|
init_search - initialize search info
|
|
---------------------------------------*/
|
|
|
|
static void init_search(search_info *info)
|
|
{
|
|
if(info)
|
|
info->search_speed = SEARCH_SPEED_MEDIUM;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------
|
|
init_search_box - initialize info of search menu
|
|
---------------------------------------------------*/
|
|
|
|
static void init_search_box(search_info *info, UINT8 mode)
|
|
{
|
|
if(info)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case SEARCH_BOX_MINIMUM:
|
|
info->lhs = kSearchOperand_Current;
|
|
info->rhs = kSearchOperand_Previous;
|
|
info->parameter = MINIMUM_ITEM_EQUAL;
|
|
break;
|
|
|
|
case SEARCH_BOX_STANDARD:
|
|
info->lhs = kSearchOperand_Current;
|
|
info->rhs = kSearchOperand_Previous;
|
|
info->comparison = kSearchComparison_EqualTo;
|
|
info->value = 0;
|
|
info->parameter = 0;
|
|
break;
|
|
|
|
case SEARCH_BOX_ADVANCED:
|
|
info->lhs = kSearchOperand_Current;
|
|
info->rhs = kSearchOperand_Previous;
|
|
info->comparison = kSearchComparison_EqualTo;
|
|
info->value = 0;
|
|
info->parameter = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
dispose_search_reigons - free all search regions in selected search info
|
|
---------------------------------------------------------------------------*/
|
|
|
|
static void dispose_search_reigons(search_info *info)
|
|
{
|
|
if(info->region_list)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < info->region_list_length; i++)
|
|
{
|
|
search_region *region = &info->region_list[i];
|
|
|
|
free(region->first);
|
|
free(region->last);
|
|
free(region->status);
|
|
free(region->backup_last);
|
|
free(region->backup_status);
|
|
}
|
|
|
|
free(info->region_list);
|
|
|
|
info->region_list = NULL;
|
|
}
|
|
|
|
info->region_list_length = 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
dispose_search - free selected search info and all search region in it
|
|
-------------------------------------------------------------------------*/
|
|
|
|
static void dispose_search(search_info *info)
|
|
{
|
|
dispose_search_reigons(info);
|
|
|
|
free(info->name);
|
|
|
|
info->name = NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
get_current_search - return working search info
|
|
--------------------------------------------------*/
|
|
|
|
static search_info *get_current_search(void)
|
|
{
|
|
if(current_search_idx >= search_list_length)
|
|
current_search_idx = search_list_length - 1;
|
|
|
|
if(current_search_idx < 0)
|
|
current_search_idx = 0;
|
|
|
|
return &search_list[current_search_idx];
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------
|
|
fill_buffer_from_region - fill selected search region with a value read from search address
|
|
----------------------------------------------------------------------------------------------*/
|
|
|
|
static void fill_buffer_from_region(search_region *region, UINT8 *buf)
|
|
{
|
|
UINT32 offset;
|
|
|
|
/* ##### optimize if needed ##### */
|
|
for(offset = 0; offset < region->length; offset++)
|
|
buf[offset] = read_region_data(region, offset, 1, 0);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
read_region_data - read a data from memory or search region in searching
|
|
---------------------------------------------------------------------------*/
|
|
|
|
static UINT32 read_region_data(search_region *region, UINT32 offset, UINT8 size, UINT8 swap)
|
|
{
|
|
UINT32 address = region->address + offset;
|
|
|
|
if(region->cached_pointer != NULL)
|
|
{
|
|
UINT8 *buf = (UINT8 *)region->cached_pointer;
|
|
|
|
if(buf)
|
|
// return do_memory_read(region->cached_pointer, address, size, swap, &raw_cpu_info);
|
|
return do_memory_read(buf, address, size, cpu_needs_swap(region->target_idx) ^ swap, get_cpu_info(region->target_idx));
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
if(region->target_type == kRegionType_CPU)
|
|
{
|
|
/* NOTE : it conflicts cpu_spinutil() and causes the crash... */
|
|
return do_cpu_read(region->target_idx, address, size, cpu_needs_swap(region->target_idx) ^ swap);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*------------------------------------------------
|
|
backup_search - back up current search region
|
|
------------------------------------------------*/
|
|
|
|
static void backup_search(search_info *info)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < info->region_list_length; i++)
|
|
backup_region(&info->region_list[i]);
|
|
|
|
info->old_num_results = info->num_results;
|
|
info->backup_valid = 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------
|
|
restore_search_backup - restore previous search region
|
|
---------------------------------------------------------*/
|
|
|
|
static void restore_search_backup(search_info *info)
|
|
{
|
|
int i;
|
|
|
|
if(info && info->backup_valid)
|
|
{
|
|
for(i = 0; i < info->region_list_length; i++)
|
|
restore_region_backup(&info->region_list[i]);
|
|
|
|
info->num_results = info->old_num_results;
|
|
info->backup_valid = 0;
|
|
|
|
#if 1
|
|
SET_MESSAGE(CHEAT_MESSAGE_RESTORE_VALUE);
|
|
#else
|
|
ui_popup_time(1, "values restored"); /* not displayed when ui is opend */
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if 1
|
|
SET_MESSAGE(CHEAT_MESSAGE_NO_OLD_VALUE);
|
|
#else
|
|
ui_popup_time(1, "there are no old values"); /* not displayed when ui is opend */
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------
|
|
backup_region - back up current search results
|
|
-------------------------------------------------*/
|
|
|
|
static void backup_region(search_region *region)
|
|
{
|
|
if(region->flags & kRegionFlag_Enabled)
|
|
{
|
|
memcpy(region->backup_last, region->last, region->length);
|
|
memcpy(region->backup_status, region->status, region->length);
|
|
|
|
region->old_num_results = region->num_results;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
restore_region_backup - restore previous search results
|
|
----------------------------------------------------------*/
|
|
|
|
static void restore_region_backup(search_region *region)
|
|
{
|
|
if(region->flags & kRegionFlag_Enabled)
|
|
{
|
|
memcpy(region->last, region->backup_last, region->length);
|
|
memcpy(region->status, region->backup_status, region->length);
|
|
|
|
region->num_results = region->old_num_results;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------
|
|
default_enable_region - get default regions to search
|
|
--------------------------------------------------------*/
|
|
|
|
static UINT8 default_enable_region(running_machine *machine, search_region *region, search_info *info)
|
|
{
|
|
write8_machine_func handler = region->write_handler->write.mhandler8;
|
|
FPTR handler_address = (FPTR)handler;
|
|
|
|
switch(info->search_speed)
|
|
{
|
|
case SEARCH_SPEED_FAST:
|
|
if(handler == SMH_RAM && region->write_handler->baseptr != NULL)
|
|
return 1;
|
|
|
|
case SEARCH_SPEED_MEDIUM:
|
|
if(handler_address >= (FPTR)SMH_BANK1 && handler_address <= (FPTR)SMH_BANK32)
|
|
return 1;
|
|
|
|
if(handler == SMH_RAM)
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
case SEARCH_SPEED_SLOW:
|
|
if(handler == SMH_NOP || handler == SMH_ROM)
|
|
return 0;
|
|
|
|
if(handler_address > STATIC_COUNT && region->write_handler->baseptr == NULL)
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
case SEARCH_SPEED_VERY_SLOW:
|
|
if(handler == SMH_NOP || handler == SMH_ROM)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------
|
|
set_search_region_default_name - set name of region to region list
|
|
---------------------------------------------------------------------*/
|
|
|
|
static void set_search_region_default_name(search_region *region)
|
|
{
|
|
switch(region->target_type)
|
|
{
|
|
case kRegionType_CPU:
|
|
{
|
|
char desc[16];
|
|
|
|
if(region->write_handler)
|
|
{
|
|
genf *handler = region->write_handler->write.generic;
|
|
FPTR handler_address = (FPTR)handler;
|
|
|
|
if(handler_address >= (FPTR)SMH_BANK1 && handler_address <= (FPTR)SMH_BANK32)
|
|
{
|
|
sprintf(desc, "BANK%.2d", (int)(handler_address - (FPTR)SMH_BANK1) + 1);
|
|
}
|
|
else
|
|
{
|
|
switch(handler_address)
|
|
{
|
|
case (FPTR)SMH_NOP: strcpy(desc, "NOP "); break;
|
|
case (FPTR)SMH_RAM: strcpy(desc, "RAM "); break;
|
|
case (FPTR)SMH_ROM: strcpy(desc, "ROM "); break;
|
|
default: strcpy(desc, "CUSTOM"); break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
sprintf(desc, "CPU%.2d ", region->target_idx);
|
|
|
|
sprintf(region->name, "%.*X-%.*X %s",
|
|
cpu_info_list[region->target_idx].address_chars_needed, region->address,
|
|
cpu_info_list[region->target_idx].address_chars_needed, region->address + region->length - 1,
|
|
desc);
|
|
}
|
|
break;
|
|
|
|
case kRegionType_Memory: /* unused? */
|
|
sprintf(region->name, "%.8X-%.8X MEMORY", region->address, region->address + region->length - 1);
|
|
break;
|
|
|
|
default:
|
|
sprintf(region->name, "UNKNOWN");
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------
|
|
is_search_region_in_range - check valid range for search region
|
|
------------------------------------------------------------------*/
|
|
|
|
static UINT8 is_search_region_in_range(UINT8 cpu, UINT32 length)
|
|
{
|
|
if(length > cpu_info_list[cpu].address_mask)
|
|
return 0;
|
|
|
|
/* all memory in 32-bit cpu causes zero length in several cases */
|
|
if(length == 0)
|
|
return 0;
|
|
|
|
if(length > SAFE_SEARCH_REGION_RANGE)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------
|
|
allocate_search_regions - memory allocation for search region
|
|
----------------------------------------------------------------*/
|
|
|
|
static void allocate_search_regions(search_info *info)
|
|
{
|
|
int i;
|
|
|
|
info->backup_valid = 0;
|
|
info->num_results = 0;
|
|
|
|
for(i = 0; i < info->region_list_length; i++)
|
|
{
|
|
search_region *region = &info->region_list[i];
|
|
|
|
region->num_results = 0;
|
|
|
|
free(region->first);
|
|
free(region->last);
|
|
free(region->status);
|
|
free(region->backup_last);
|
|
free(region->backup_status);
|
|
|
|
if(region->flags & kRegionFlag_Enabled)
|
|
{
|
|
region->first = malloc(region->length);
|
|
region->last = malloc(region->length);
|
|
region->status = malloc(region->length);
|
|
region->backup_last = malloc(region->length);
|
|
region->backup_status = malloc(region->length);
|
|
|
|
if(region->first == NULL || region->last == NULL || region->status == NULL || region->backup_last == NULL || region->backup_status == NULL)
|
|
{
|
|
/* NOTE : ignored memory allocation error but locked this region */
|
|
free(region->first);
|
|
free(region->last);
|
|
free(region->status);
|
|
free(region->backup_last);
|
|
free(region->backup_status);
|
|
|
|
region->first = NULL;
|
|
region->last = NULL;
|
|
region->status = NULL;
|
|
region->backup_last = NULL;
|
|
region->backup_status = NULL;
|
|
region->flags &= ~kRegionFlag_Enabled;
|
|
region->flags |= kRegionFlag_HasError;
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_ALLOCATE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
region->first = NULL;
|
|
region->last = NULL;
|
|
region->status = NULL;
|
|
region->backup_last = NULL;
|
|
region->backup_status = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------
|
|
build_search_regions - build serach regions from memory map
|
|
--------------------------------------------------------------*/
|
|
|
|
static void build_search_regions(running_machine *machine, search_info *info)
|
|
{
|
|
if(EXTRACT_FIELD(cheat_options, SearchBox) == SEARCH_BOX_MINIMUM)
|
|
info->comparison = MINIMUM_ITEM_EQUAL;
|
|
else
|
|
info->comparison = kSearchComparison_EqualTo;
|
|
|
|
/* 1st, free all search regions in current search_info */
|
|
dispose_search_reigons(info);
|
|
|
|
/* 2nd, set parameters from memory map */
|
|
switch(info->target_type)
|
|
{
|
|
case kRegionType_CPU:
|
|
{
|
|
if(info->search_speed == SEARCH_SPEED_ALL_MEMORY)
|
|
{
|
|
/* All Memory = 1 search region */
|
|
UINT32 length = cpu_info_list[info->target_idx].address_mask + 1;
|
|
search_region *region;
|
|
|
|
info->region_list = calloc(sizeof(search_region), 1);
|
|
info->region_list_length = 1;
|
|
|
|
region = info->region_list;
|
|
region->address = 0;
|
|
region->length = length;
|
|
region->target_idx = info->target_idx;
|
|
region->target_type = info->target_type;
|
|
region->write_handler = NULL;
|
|
region->first = NULL;
|
|
region->last = NULL;
|
|
region->status = NULL;
|
|
region->backup_last = NULL;
|
|
region->backup_status = NULL;
|
|
|
|
set_search_region_default_name(region);
|
|
|
|
if(is_search_region_in_range(info->target_idx, length) == 0)
|
|
{
|
|
region->flags &= ~kRegionFlag_Enabled;
|
|
region->flags |= kRegionFlag_HasError;
|
|
}
|
|
else
|
|
region->flags = kRegionFlag_Enabled;
|
|
}
|
|
else
|
|
{
|
|
if(VALID_CPU(info->target_idx))
|
|
{
|
|
int count = 0;
|
|
const address_map *map = NULL;
|
|
const address_map_entry *entry;
|
|
search_region *traverse;
|
|
|
|
map = memory_get_address_map(info->target_idx, ADDRESS_SPACE_PROGRAM);
|
|
|
|
/* calculate total search entries */
|
|
for(entry = map->entrylist; entry != NULL; entry = entry->next)
|
|
if(entry->write.generic)
|
|
count++;
|
|
|
|
info->region_list = calloc(sizeof(search_region), count);
|
|
info->region_list_length = count;
|
|
traverse = info->region_list;
|
|
|
|
for(entry = map->entrylist; entry != NULL; entry = entry->next)
|
|
{
|
|
if(entry->write.generic)
|
|
{
|
|
UINT32 length = (entry->addrend - entry->addrstart) + 1;
|
|
|
|
traverse->address = entry->addrstart;
|
|
traverse->length = length;
|
|
traverse->target_idx = info->target_idx;
|
|
traverse->target_type = info->target_type;
|
|
traverse->cached_pointer = get_memory_region_base_pointer(info->target_idx, kAddressSpace_DirectMemory, entry->addrstart);
|
|
traverse->write_handler = entry;
|
|
traverse->first = NULL;
|
|
traverse->last = NULL;
|
|
traverse->status = NULL;
|
|
traverse->backup_last = NULL;
|
|
traverse->backup_status = NULL;
|
|
|
|
if(is_search_region_in_range(info->target_idx, length) == 0)
|
|
{
|
|
traverse->flags &= ~kRegionFlag_Enabled;
|
|
traverse->flags |= kRegionFlag_HasError;
|
|
}
|
|
else
|
|
traverse->flags = default_enable_region(machine, traverse, info) ? kRegionFlag_Enabled : 0;
|
|
|
|
set_search_region_default_name(traverse);
|
|
|
|
traverse++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kRegionType_Memory: /* unused? */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
handle_local_command_tag - tag checker for command code
|
|
----------------------------------------------------------*/
|
|
|
|
static int handle_local_command_tag(char *tag)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
{
|
|
if(strcmp(tag, cheat_list[i].name) == 0)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------
|
|
handle_local_command_cheat - handle specified cheat command code
|
|
-------------------------------------------------------------------*/
|
|
|
|
static void handle_local_command_cheat(running_machine *machine, int cpu, int type, int address, int data, int extend_data, char *tag)
|
|
{
|
|
int command = 0;
|
|
int format = cpu ? LOAD_CHEAT_CODE_NEW : LOAD_CHEAT_CODE_OLD;
|
|
|
|
if(format != LOAD_CHEAT_CODE_NEW)
|
|
{
|
|
/* convert old format to new */
|
|
switch(EXTRACT_FIELD(type, LocationParameter))
|
|
{
|
|
case kCustomLocation_AssignActivationKey:
|
|
command = CUSTOM_CODE_ACTIVATION_KEY;
|
|
break;
|
|
|
|
case kCustomLocation_Enable:
|
|
command = CUSTOM_CODE_PRE_ENABLE;
|
|
break;
|
|
|
|
case kCustomLocation_Overclock:
|
|
command = CUSTOM_CODE_OVER_CLOCK;
|
|
break;
|
|
|
|
case kCustomLocation_RefreshRate:
|
|
command = CUSTOM_CODE_REFRESH_RATE;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
command = cpu;
|
|
|
|
switch(command)
|
|
{
|
|
case CUSTOM_CODE_ACTIVATION_KEY:
|
|
if(format == LOAD_CHEAT_CODE_NEW)
|
|
address = handle_local_command_tag(tag);
|
|
|
|
if(address < cheat_list_length)
|
|
{
|
|
cheat_entry *entry = &cheat_list[address];
|
|
|
|
if(cpu)
|
|
{
|
|
if(entry->flags & kCheatFlag_Select)
|
|
{
|
|
if(data)
|
|
entry->activation_key = data;
|
|
|
|
if(extend_data)
|
|
entry->activation_sub_key = extend_data;
|
|
}
|
|
else
|
|
entry->activation_key = data;
|
|
}
|
|
else
|
|
entry->activation_key = data;
|
|
}
|
|
break;
|
|
|
|
case CUSTOM_CODE_PRE_ENABLE:
|
|
if(format == LOAD_CHEAT_CODE_NEW)
|
|
address = handle_local_command_tag(tag);
|
|
|
|
if(address < cheat_list_length)
|
|
{
|
|
cheat_entry *entry = &cheat_list[address];
|
|
|
|
activate_cheat(machine, entry);
|
|
|
|
if(format == LOAD_CHEAT_CODE_NEW)
|
|
{
|
|
if(data && data < entry->action_list_length)
|
|
entry->selection = data;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CUSTOM_CODE_OVER_CLOCK:
|
|
if(VALID_CPU(address))
|
|
{
|
|
double over_clock = data / 65536.0;
|
|
|
|
cpunum_set_clockscale(machine, address, over_clock);
|
|
}
|
|
break;
|
|
|
|
case CUSTOM_CODE_REFRESH_RATE:
|
|
{
|
|
int width = video_screen_get_width(machine->primary_screen);
|
|
int height = video_screen_get_height(machine->primary_screen);
|
|
|
|
const rectangle *visarea = video_screen_get_visible_area(machine->primary_screen);
|
|
double refresh = data / 65536.0;
|
|
|
|
video_screen_configure(machine->primary_screen, width, height, visarea, HZ_TO_ATTOSECONDS(refresh));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------
|
|
open_cheat_database - open the cheat database in loading/saveing
|
|
-------------------------------------------------------------------*/
|
|
|
|
static UINT8 open_cheat_database(mame_file **the_file, char *file_name, UINT8 flag)
|
|
{
|
|
file_error filerr;
|
|
|
|
if(flag == DATABASE_LOAD)
|
|
{
|
|
/* load */
|
|
filerr = mame_fopen(SEARCHPATH_CHEAT, file_name, OPEN_FLAG_READ, the_file);
|
|
|
|
if(filerr != FILERR_NONE)
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* save */
|
|
filerr = mame_fopen(SEARCHPATH_CHEAT, file_name, OPEN_FLAG_WRITE, the_file);
|
|
|
|
if(the_file == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
else if(filerr != FILERR_NONE)
|
|
{
|
|
/* if the database is not found, create new database */
|
|
filerr = mame_fopen(SEARCHPATH_CHEAT, file_name, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, the_file);
|
|
|
|
if(filerr != FILERR_NONE)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------
|
|
load_cheat_options - load cheat option from database
|
|
-------------------------------------------------------*/
|
|
|
|
static void load_cheat_options(char *file_name)
|
|
{
|
|
static char buf[2048];
|
|
mame_file *the_file;
|
|
cheat_format *format = &cheat_format_table[0];
|
|
cheat_format_strings
|
|
*buffer = format_strings;
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, file_name, DATABASE_LOAD) == 0)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_LOAD_DATABASE);
|
|
return;
|
|
}
|
|
|
|
while(mame_fgets(buf, 2048, the_file))
|
|
{
|
|
if(sscanf(buf, format->format_string, buffer->name) == format->arguments_matched)
|
|
{
|
|
if(strlen(buffer->name) == format->type_matched)
|
|
{
|
|
if(sscanf(buffer->name, "%X", &cheat_options));
|
|
{
|
|
vertical_key_repeat_speed = EXTRACT_FIELD(cheat_options, VerticalKeyRepeatSpeed);
|
|
horizontal_key_repeat_speed = EXTRACT_FIELD(cheat_options, HorizontalKeyRepeatSpeed);
|
|
SET_MESSAGE(CHEAT_MESSAGE_RELOAD_CHEAT_OPTION);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* close the database */
|
|
mame_fclose(the_file);
|
|
}
|
|
|
|
/*-------------------------------------------------------------
|
|
load_cheat_code_new - load newest cheat code from database
|
|
-------------------------------------------------------------*/
|
|
|
|
static void load_cheat_code_new(running_machine *machine, char *file_name)
|
|
{
|
|
char buf[255];
|
|
mame_file *the_file;
|
|
cheat_format_strings
|
|
*buffer = format_strings;
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, file_name, DATABASE_LOAD) == 0) return;
|
|
found_database = 1;
|
|
/* get a line from database */
|
|
while(mame_fgets(buf, 255, the_file))
|
|
{
|
|
#ifdef MESS
|
|
int crc = 0;
|
|
#endif
|
|
int cpu = 0;
|
|
int type = 0;
|
|
int address = 0;
|
|
int data = 0;
|
|
int extend_data = 0;
|
|
int arguments_matched = 0;
|
|
int is_error = 0;
|
|
cheat_entry *entry;
|
|
cheat_action *action;
|
|
cheat_format *format = &cheat_format_table[LOAD_CHEAT_CODE_NEW];
|
|
|
|
/* scan and check format */
|
|
#ifdef MESS
|
|
arguments_matched = sscanf(buf, format->format_string, buffer->name, &crc, buffer->type, &address, buffer->data, buffer->extend_data, buffer->description, buffer->comment);
|
|
#else
|
|
arguments_matched = sscanf(buf, format->format_string, buffer->name, buffer->type, &address, buffer->data, buffer->extend_data, buffer->description, buffer->comment);
|
|
#endif
|
|
/* NOTE : description and comment are not always needed */
|
|
if(arguments_matched < format->arguments_matched) continue;
|
|
|
|
#ifdef MESS
|
|
/* check crc (MESS specified) */
|
|
if(MatchesCRCTable(crc) == 0) continue;
|
|
|
|
if(TEST_FIELD(cheat_options, SharedCode) && strcmp(machine->gamedrv->parent, "0"))
|
|
{
|
|
/* shared code (MESS specified) */
|
|
if(strcmp(buffer->name, machine->gamedrv->parent)) break;
|
|
else
|
|
#endif
|
|
/* check short game/machine name */
|
|
if(strcmp(buffer->name, machine->gamedrv->name)) break;
|
|
#ifdef MESS
|
|
}
|
|
#endif
|
|
/* check length */
|
|
if(strlen(buffer->type) != format->type_matched)
|
|
{
|
|
logerror("cheat: [load code] %s has invalid type field length (%X)\n", buffer->description, (int)strlen(buffer->type)); is_error++;
|
|
}
|
|
if(strlen(buffer->data) != format->data_matched)
|
|
{
|
|
logerror("cheat: [load code] %s has invalid data field length (%X)\n", buffer->description, (int)strlen(buffer->data)); is_error++;
|
|
}
|
|
if(strlen(buffer->extend_data) != format->data_matched)
|
|
{
|
|
logerror("cheat: [load code] %s has invalid extend data field length (%X)\n", buffer->description, (int)strlen(buffer->extend_data)); is_error++;
|
|
}
|
|
if(is_error)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_WRONG_CODE);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
/* matched! */
|
|
sscanf(buffer->type, "%2X%8X", &cpu, &type);
|
|
sscanf(buffer->data, "%X", &data);
|
|
sscanf(buffer->extend_data, "%X", &extend_data);
|
|
}
|
|
|
|
/* logerror("cheat: processing %s\n", buf); */
|
|
|
|
/* handle command code */
|
|
if(cpu >= CUSTOM_CODE_ACTIVATION_KEY)
|
|
{
|
|
handle_local_command_cheat(machine, cpu, type, address, data, extend_data, buffer->comment);
|
|
continue;
|
|
}
|
|
/* set entry */
|
|
if(EXTRACT_FIELD(type, Link) == LINK_MASTER)
|
|
{
|
|
/* 1st (master) code in an entry */
|
|
resize_cheat_list(cheat_list_length + 1, REQUEST_DISPOSE);
|
|
if(cheat_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] cheat list resize failed. bailing\n"); goto bail_new;
|
|
}
|
|
entry = &cheat_list[cheat_list_length - 1];
|
|
entry->name = create_string_copy(buffer->description);
|
|
if(arguments_matched == cheat_format_table[LOAD_CHEAT_CODE_NEW].comment_matched) entry->comment = create_string_copy(buffer->comment);
|
|
}
|
|
else
|
|
{
|
|
/* 2nd or later (link) code in an entry */
|
|
if(cheat_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] first cheat found was link cheat. bailing\n"); goto bail_new;
|
|
}
|
|
entry = &cheat_list[cheat_list_length - 1];
|
|
}
|
|
/* set action */
|
|
resize_cheat_action_list(&cheat_list[cheat_list_length - 1], entry->action_list_length + 1, REQUEST_DISPOSE);
|
|
if(entry->action_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] action list resize failed. bailing\n"); goto bail_new;
|
|
}
|
|
action = &entry->action_list[entry->action_list_length - 1];
|
|
action->flags = 0;
|
|
action->type = type;
|
|
action->region = cpu;
|
|
action->address = address;
|
|
action->original_address = address;
|
|
action->data = data;
|
|
action->original_data = data;
|
|
action->extend_data = extend_data;
|
|
action->optional_name = create_string_copy(buffer->description);
|
|
action->last_value = NULL;
|
|
}
|
|
bail_new:
|
|
mame_fclose(the_file);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
load_cheat_code_standard - load standard cheat code from database
|
|
--------------------------------------------------------------------*/
|
|
|
|
static void load_cheat_code_standard(running_machine *machine, char *file_name)
|
|
{
|
|
char buf[256];
|
|
mame_file *the_file;
|
|
cheat_format_strings
|
|
*buffer = format_strings;
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, file_name, DATABASE_LOAD) == 0) return;
|
|
found_database = 1;
|
|
/* get a line from database */
|
|
while(mame_fgets(buf, 2048, the_file))
|
|
{
|
|
#ifdef MESS
|
|
int crc = 0;
|
|
#endif
|
|
int type = 0;
|
|
int address = 0;
|
|
int data = 0;
|
|
int extend_data = 0;
|
|
int is_error = 0;
|
|
cheat_entry *entry;
|
|
cheat_action *action;
|
|
cheat_format *format = &cheat_format_table[LOAD_CHEAT_CODE_STANDARD];
|
|
|
|
/* scan and check format */
|
|
#ifdef MESS
|
|
if(sscanf( buf,
|
|
format->format_string, buffer->name, &crc, buffer->type, &address, buffer->data, buffer->extend_data, buffer->description, buffer->comment)
|
|
< format->arguments_matched) continue;
|
|
#else
|
|
if(sscanf( buf,
|
|
format->format_string, buffer->name, buffer->type, &address, buffer->data, buffer->extend_data, buffer->description, buffer->comment)
|
|
< format->arguments_matched) continue;
|
|
#endif
|
|
/* check short game nama */
|
|
if(strcmp(buffer->name, machine->gamedrv->name)) continue;
|
|
#ifdef MESS
|
|
/* check crc */
|
|
if(MatchesCRCTable(crc) == 0) continue;
|
|
#endif
|
|
/* check length */
|
|
if(strlen(buffer->type) != format->type_matched)
|
|
{
|
|
logerror("cheat: [load code] %s has invalid type field length (%X)\n", buffer->description, (int)strlen(buffer->type));
|
|
is_error++;
|
|
}
|
|
if(strlen(buffer->data) != format->data_matched)
|
|
{
|
|
logerror("cheat: [load code] %s has invalid data field length (%X)\n", buffer->description, (int)strlen(buffer->data));
|
|
is_error++;
|
|
}
|
|
if(strlen(buffer->extend_data) != format->data_matched)
|
|
{
|
|
logerror("cheat: [load code] %s has invalid extend data field length (%X)\n", buffer->description, (int)strlen(buffer->extend_data));
|
|
is_error++;
|
|
}
|
|
if(is_error)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_WRONG_CODE);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
/* scan type, data and extend data */
|
|
sscanf(buffer->type, "%X", &type); sscanf(buffer->data, "%X", &data); sscanf(buffer->extend_data, "%X", &extend_data);
|
|
}
|
|
/* check command code */
|
|
if(TEST_FIELD(type, RemoveFromList))
|
|
{
|
|
handle_local_command_cheat(machine, 0, type, address, data, 0, NULL); continue;
|
|
}
|
|
|
|
/* set entry */
|
|
if(TEST_FIELD(type, LinkEnable) == 0)
|
|
{
|
|
/* 1st (master) code in an entry */
|
|
resize_cheat_list(cheat_list_length + 1, REQUEST_DISPOSE);
|
|
if(cheat_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] cheat list resize failed. bailing\n"); goto bail_standard;
|
|
}
|
|
/* allocate entry and set code name */
|
|
entry = &cheat_list[cheat_list_length - 1];
|
|
entry->name = create_string_copy(buffer->description);
|
|
}
|
|
else
|
|
{
|
|
/* 2nd or later (link) code in an entry */
|
|
if(cheat_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] first cheat found was link cheat. bailing\n"); goto bail_standard;
|
|
}
|
|
/* set action to entry */
|
|
entry = &cheat_list[cheat_list_length - 1];
|
|
}
|
|
/* set action */
|
|
resize_cheat_action_list(&cheat_list[cheat_list_length - 1], entry->action_list_length + 1, REQUEST_DISPOSE);
|
|
if(entry->action_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] action list resize failed. bailing\n"); goto bail_standard;
|
|
}
|
|
action = &entry->action_list[entry->action_list_length - 1];
|
|
action->flags = 0;
|
|
action->flags |= kActionFlag_OldFormat;
|
|
action->type = type;
|
|
action->address = address;
|
|
action->data = data;
|
|
action->original_data = data;
|
|
action->extend_data = extend_data;
|
|
action->optional_name = create_string_copy(buffer->description);
|
|
action->last_value = NULL;
|
|
}
|
|
bail_standard:
|
|
mame_fclose(the_file);
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
load_cheat_code_old - load old cheat code from database
|
|
----------------------------------------------------------*/
|
|
|
|
static void load_cheat_code_old(running_machine *machine, char *file_name)
|
|
{
|
|
enum
|
|
{
|
|
CUSTOM_FIELD_NONE = 0,
|
|
CUSTOM_FIELD_DONT_APPLY_CPU_FIELD = 1 << 0,
|
|
CUSTOM_FIELD_SET_BIT = 1 << 1,
|
|
CUSTOM_FIELD_CLEAR_BIT = 1 << 2,
|
|
CUSTOM_FIELD_SUBTRACT_ONE = 1 << 3,
|
|
CUSTOM_FIELD_BIT_MASK = CUSTOM_FIELD_SET_BIT | CUSTOM_FIELD_CLEAR_BIT,
|
|
|
|
CUSTOM_FIELD_END = 0xFF
|
|
};
|
|
struct _conversion_table
|
|
{
|
|
int old_code;
|
|
UINT32 new_code;
|
|
UINT8 custom_field;
|
|
};
|
|
static const struct _conversion_table conversion_table[] =
|
|
{ /* old_code*/ /* new_code*/ /* custom_field */
|
|
{ 0, 0x00000000, CUSTOM_FIELD_NONE },
|
|
{ 1, 0x00000001, CUSTOM_FIELD_NONE },
|
|
{ 2, 0x00000020, CUSTOM_FIELD_NONE },
|
|
{ 3, 0x00000040, CUSTOM_FIELD_NONE },
|
|
{ 4, 0x000000A0, CUSTOM_FIELD_NONE },
|
|
{ 5, 0x00000022, CUSTOM_FIELD_NONE },
|
|
{ 6, 0x00000042, CUSTOM_FIELD_NONE },
|
|
{ 7, 0x000000A2, CUSTOM_FIELD_NONE },
|
|
{ 8, 0x00000024, CUSTOM_FIELD_NONE },
|
|
{ 9, 0x00000044, CUSTOM_FIELD_NONE },
|
|
{ 10, 0x00000064, CUSTOM_FIELD_NONE },
|
|
{ 11, 0x00000084, CUSTOM_FIELD_NONE },
|
|
{ 15, 0x00000023, CUSTOM_FIELD_NONE },
|
|
{ 16, 0x00000043, CUSTOM_FIELD_NONE },
|
|
{ 17, 0x000000A3, CUSTOM_FIELD_NONE },
|
|
{ 20, 0x00000000, CUSTOM_FIELD_SET_BIT },
|
|
{ 21, 0x00000001, CUSTOM_FIELD_SET_BIT },
|
|
{ 22, 0x00000020, CUSTOM_FIELD_SET_BIT },
|
|
{ 23, 0x00000040, CUSTOM_FIELD_SET_BIT },
|
|
{ 24, 0x000000A0, CUSTOM_FIELD_SET_BIT },
|
|
{ 40, 0x00000000, CUSTOM_FIELD_CLEAR_BIT },
|
|
{ 41, 0x00000001, CUSTOM_FIELD_CLEAR_BIT },
|
|
{ 42, 0x00000020, CUSTOM_FIELD_CLEAR_BIT },
|
|
{ 43, 0x00000040, CUSTOM_FIELD_CLEAR_BIT },
|
|
{ 44, 0x000000A0, CUSTOM_FIELD_CLEAR_BIT },
|
|
{ 60, 0x00000103, CUSTOM_FIELD_NONE },
|
|
{ 61, 0x00000303, CUSTOM_FIELD_NONE },
|
|
{ 62, 0x00000503, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 63, 0x00000903, CUSTOM_FIELD_NONE },
|
|
{ 64, 0x00000B03, CUSTOM_FIELD_NONE },
|
|
{ 65, 0x00000D03, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 70, 0x00000101, CUSTOM_FIELD_NONE },
|
|
{ 71, 0x00000301, CUSTOM_FIELD_NONE },
|
|
{ 72, 0x00000501, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 73, 0x00000901, CUSTOM_FIELD_NONE },
|
|
{ 74, 0x00000B01, CUSTOM_FIELD_NONE },
|
|
{ 75, 0x00000D01, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 80, 0x00000102, CUSTOM_FIELD_NONE },
|
|
{ 81, 0x00000302, CUSTOM_FIELD_NONE },
|
|
{ 82, 0x00000502, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 83, 0x00000902, CUSTOM_FIELD_NONE },
|
|
{ 84, 0x00000B02, CUSTOM_FIELD_NONE },
|
|
{ 85, 0x00000D02, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 90, 0x00000100, CUSTOM_FIELD_NONE },
|
|
{ 91, 0x00000300, CUSTOM_FIELD_NONE },
|
|
{ 92, 0x00000500, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 93, 0x00000900, CUSTOM_FIELD_NONE },
|
|
{ 94, 0x00000B00, CUSTOM_FIELD_NONE },
|
|
{ 95, 0x00000D00, CUSTOM_FIELD_SUBTRACT_ONE },
|
|
{ 100, 0x20800000, CUSTOM_FIELD_NONE },
|
|
{ 101, 0x20800001, CUSTOM_FIELD_NONE },
|
|
{ 102, 0x20800000, CUSTOM_FIELD_NONE },
|
|
{ 103, 0x20800001, CUSTOM_FIELD_NONE },
|
|
{ 110, 0x40800000, CUSTOM_FIELD_NONE },
|
|
{ 111, 0x40800001, CUSTOM_FIELD_NONE },
|
|
{ 112, 0x40800000, CUSTOM_FIELD_NONE },
|
|
{ 113, 0x40800001, CUSTOM_FIELD_NONE },
|
|
{ 120, 0x63000001, CUSTOM_FIELD_NONE },
|
|
{ 121, 0x63000001, CUSTOM_FIELD_DONT_APPLY_CPU_FIELD | CUSTOM_FIELD_SET_BIT },
|
|
{ 122, 0x63000001, CUSTOM_FIELD_DONT_APPLY_CPU_FIELD | CUSTOM_FIELD_CLEAR_BIT },
|
|
{ 998, 0x00000006, CUSTOM_FIELD_NONE },
|
|
{ 999, 0x60000000, CUSTOM_FIELD_DONT_APPLY_CPU_FIELD },
|
|
/* end */
|
|
{ -1, 0x00000000, CUSTOM_FIELD_END }
|
|
};
|
|
const struct _conversion_table *traverse = conversion_table;
|
|
|
|
char buf[255];
|
|
mame_file *the_file;
|
|
cheat_format_strings
|
|
*buffer = format_strings;
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, file_name, DATABASE_LOAD) == 0) return;
|
|
found_database = 1;
|
|
/* get a line from database */
|
|
while(mame_fgets(buf, 255, the_file))
|
|
{
|
|
#ifdef MESS
|
|
int crc = 0;
|
|
#endif
|
|
int cpu = 0;
|
|
int address = 0;
|
|
int data = 0;
|
|
int code = 0;
|
|
int link_cheat = 0;
|
|
int type = 0;
|
|
int extend_data = 0;
|
|
cheat_entry *entry;
|
|
cheat_action *action;
|
|
cheat_format *format = &cheat_format_table[LOAD_CHEAT_CODE_OLD];
|
|
|
|
#ifdef MESS
|
|
if(sscanf(buf, format->format_string, &crc, buffer->name, &cpu, &address, &data, &code, buffer->description, buffer->comment) < format->aruguments_matched) continue;
|
|
#else
|
|
if(sscanf(buf, format->format_string, buffer->name, &cpu, &address, &data, &code, buffer->description, buffer->comment) < format->arguments_matched) continue;
|
|
#endif
|
|
/* check short game name */
|
|
if(strcmp(buffer->name, machine->gamedrv->name)) continue;
|
|
#ifdef MESS
|
|
/* check crc */
|
|
if(MatchesCRCTable(crc) == 0) continue;
|
|
#endif
|
|
/* convert link cheats */
|
|
if(code >= 500 && code <= 699)
|
|
{
|
|
link_cheat = 1;
|
|
type -= 500;
|
|
}
|
|
/* loop over old format table */
|
|
while(traverse->old_code >= 0)
|
|
{
|
|
if(type == traverse->old_code) goto found_code;
|
|
else traverse++;
|
|
}
|
|
/* not found */
|
|
logerror("cheat: [load_old_code] %d not found\n", code);
|
|
continue;
|
|
|
|
/* found */
|
|
found_code:
|
|
type = traverse->new_code;
|
|
/* add in the CPU field */
|
|
if((traverse->custom_field & CUSTOM_FIELD_DONT_APPLY_CPU_FIELD) == 0)
|
|
type = (type & ~0x1F000000) | ((cpu << 24) & 0x1F000000);
|
|
/* hack-ish, subtract one from data field for x5 user select */
|
|
if(traverse->custom_field & CUSTOM_FIELD_SUBTRACT_ONE) data--;
|
|
/* set up the extend data */
|
|
if(traverse->custom_field & CUSTOM_FIELD_BIT_MASK) extend_data = data;
|
|
else extend_data = ~0;
|
|
if(traverse->custom_field & CUSTOM_FIELD_CLEAR_BIT) data = 0;
|
|
if(link_cheat) SET_MASK_FIELD(type, LinkEnable);
|
|
|
|
/* set entry */
|
|
if(TEST_FIELD(type, LinkEnable))
|
|
{
|
|
/* 1st (master) code in an entry */
|
|
resize_cheat_list(cheat_list_length + 1, REQUEST_DISPOSE);
|
|
if(cheat_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] cheat list resize failed. bailing\n"); goto bail_old;
|
|
}
|
|
entry = &cheat_list[cheat_list_length - 1];
|
|
entry->name = create_string_copy(buffer->description);
|
|
}
|
|
else
|
|
{
|
|
/* 2nd or later (link) code in an entry */
|
|
if(cheat_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] first cheat found was link cheat. bailing\n"); goto bail_old;
|
|
}
|
|
entry = &cheat_list[cheat_list_length - 1];
|
|
}
|
|
|
|
/* set action */
|
|
resize_cheat_action_list(&cheat_list[cheat_list_length - 1], entry->action_list_length + 1, REQUEST_DISPOSE);
|
|
if(entry->action_list_length == 0)
|
|
{
|
|
logerror("cheat: [load code] action list resize failed. bailing\n"); goto bail_old;
|
|
}
|
|
action = &entry->action_list[entry->action_list_length - 1];
|
|
action->flags = 0;
|
|
action->flags |= kActionFlag_OldFormat;
|
|
action->type = type;
|
|
action->region = cpu;
|
|
action->address = address;
|
|
action->original_address = address;
|
|
action->data = data;
|
|
action->original_data = data;
|
|
action->extend_data = extend_data;
|
|
action->optional_name = create_string_copy(buffer->description);
|
|
action->last_value = NULL;
|
|
}
|
|
bail_old:
|
|
mame_fclose(the_file);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
load_user_defined_search_region - load user region code and rebuild search region
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
static void load_user_defined_search_region(running_machine *machine, char *file_name)
|
|
{
|
|
int count = 0;
|
|
char buf[2048];
|
|
|
|
search_info *info = get_current_search();
|
|
mame_file *the_file;
|
|
cheat_format *format = &cheat_format_table[4];
|
|
cheat_format_strings
|
|
*buffer = format_strings;
|
|
|
|
/* 1st, free all search regions in current search_info */
|
|
dispose_search_reigons(info);
|
|
|
|
/* 2nd, attempt to open the memorymap file */
|
|
if(open_cheat_database(&the_file, file_name, DATABASE_LOAD) == 0)
|
|
{
|
|
info->region_list_length = 0;
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_LOAD_DATABASE);
|
|
return;
|
|
}
|
|
|
|
/* 3rd, scan parameters from the file */
|
|
while(mame_fgets(buf, 2048, the_file))
|
|
{
|
|
#ifdef MESS
|
|
int crc;
|
|
#endif
|
|
int cpu;
|
|
int space;
|
|
int start;
|
|
int end;
|
|
int status;
|
|
cpu_region_info *cpu_info;
|
|
search_region *region;
|
|
|
|
#ifdef MESS
|
|
if(sscanf(buf, format->format_string, buffer->name, &crc, &cpu, &space, &start, &end, &status, buffer->description) < format->arguments_matched)
|
|
#else
|
|
if(sscanf(buf, format->format_string, buffer->name, &cpu, &space, &start, &end, &status, buffer->description) < format->arguments_matched)
|
|
#endif
|
|
continue;
|
|
else
|
|
{
|
|
if(strcmp(buffer->name, machine->gamedrv->name)) continue;
|
|
#ifdef MESS
|
|
if(MatchesCRCTable(crc) == 0) continue;
|
|
#endif
|
|
if(cpu != info->target_idx) continue;
|
|
|
|
}
|
|
|
|
cpu_info = get_cpu_info(cpu);
|
|
|
|
/* check parameters */
|
|
switch(space)
|
|
{
|
|
case kAddressSpace_Program:
|
|
case kAddressSpace_DirectMemory:
|
|
/* check length */
|
|
if(start >= end)
|
|
{
|
|
logerror("cheat: [user region] invalid length (start : %.8X >= end : %.8X)\n", start, end);
|
|
continue;
|
|
}
|
|
|
|
/* check bound */
|
|
if(is_search_region_in_range(info->target_idx, start + end + 1) == 0)
|
|
{
|
|
logerror("cheat: [user region] invalid length (%.8X)\n", start - end);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case kAddressSpace_DataSpace:
|
|
case kAddressSpace_IOSpace:
|
|
/* underconstruction... */
|
|
break;
|
|
|
|
default:
|
|
logerror("cheat: [user region] %X is invalid space\n", space);
|
|
continue;
|
|
}
|
|
|
|
/* check status */
|
|
if(status > kRegionFlag_Enabled)
|
|
{
|
|
logerror("cheat: [user region] %X is invalid status\n", status);
|
|
continue;
|
|
}
|
|
|
|
/* allocate memory for new search region */
|
|
info->region_list = realloc(info->region_list, (count + 1) * sizeof(search_region));
|
|
|
|
if(info->region_list == NULL)
|
|
{
|
|
mame_fclose(the_file);
|
|
fatalerror( "cheat: [user region] memory allocation error\n"
|
|
" length = %.8X\n"
|
|
" region_list = %p\n",
|
|
count + 1, info->region_list);
|
|
}
|
|
|
|
region = &info->region_list[count];
|
|
|
|
/* 4th, set region parameters from scaned data */
|
|
region->address = start;
|
|
region->length = end - start + 1;
|
|
region->target_idx = cpu;
|
|
|
|
if(space == 0)
|
|
{
|
|
region->target_type = kRegionType_CPU;
|
|
region->cached_pointer = NULL;
|
|
}
|
|
else
|
|
{
|
|
region->target_type = kRegionType_Memory;
|
|
region->cached_pointer = get_memory_region_base_pointer(cpu, space, start);
|
|
|
|
//logerror("pointer for %s : %p\n", description, region->cachedPointer);
|
|
}
|
|
|
|
region->write_handler = NULL;
|
|
region->first = NULL;
|
|
region->last = NULL;
|
|
region->status = NULL;
|
|
region->backup_last = NULL;
|
|
region->backup_status = NULL;
|
|
region->flags = status;
|
|
|
|
sprintf(region->name, "%.*X-%.*X %s",
|
|
cpu_info->address_chars_needed, region->address,
|
|
cpu_info->address_chars_needed, region->address + region->length - 1,
|
|
buffer->description);
|
|
|
|
if(is_search_region_in_range(cpu, region->length) == 0)
|
|
{
|
|
region->flags &= ~kRegionFlag_Enabled;
|
|
region->flags |= kRegionFlag_HasError;
|
|
}
|
|
else
|
|
region->flags = status;
|
|
|
|
count++;
|
|
}
|
|
|
|
info->region_list_length = count;
|
|
|
|
if(info->region_list_length)
|
|
SET_MESSAGE(CHEAT_MESSAGE_RELOAD_USER_REGION);
|
|
|
|
mame_fclose(the_file);
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
load_cheat_database - get the database name then load it
|
|
-----------------------------------------------------------*/
|
|
|
|
static void load_cheat_database(running_machine *machine, UINT8 load_code)
|
|
{
|
|
UINT8 first = 1;
|
|
char buf[256] = { 0 };
|
|
char data;
|
|
const char *in_traverse;
|
|
char *out_traverse;
|
|
char *main_traverse;
|
|
|
|
cheat_file = options_get_string(mame_options(), OPTION_CHEAT_FILE);
|
|
|
|
if(cheat_file[0] == 0) cheat_file = "cheat.dat";
|
|
|
|
in_traverse = cheat_file;
|
|
out_traverse = buf;
|
|
main_traverse = main_database_name;
|
|
|
|
do
|
|
{
|
|
data = *in_traverse;
|
|
|
|
/* check separator or line-end */
|
|
if(data == ';' || data == 0)
|
|
{
|
|
*out_traverse++ = 0;
|
|
|
|
if(first) *main_traverse++ = 0;
|
|
|
|
if(buf[0])
|
|
{
|
|
/* load database based on the name we gotten */
|
|
switch(load_code)
|
|
{
|
|
case LOAD_CHEAT_OPTIONS: load_cheat_options(buf); break;
|
|
case LOAD_CHEAT_CODE_NEW: load_cheat_code_new(machine, buf); break;
|
|
case LOAD_CHEAT_CODE_STANDARD: load_cheat_code_standard(machine, buf); break;
|
|
case LOAD_CHEAT_CODE_OLD: load_cheat_code_old(machine, buf); break;
|
|
case LOAD_USER_REGION: load_user_defined_search_region(machine, buf); break;
|
|
}
|
|
/* reset character buffers */
|
|
out_traverse = buf;
|
|
buf[0] = 0;
|
|
first = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*out_traverse++ = data;
|
|
|
|
if(first) *main_traverse++ = data;
|
|
}
|
|
in_traverse++;
|
|
}
|
|
while(data);
|
|
|
|
if(load_code >= LOAD_CHEAT_CODE_NEW && load_code <= LOAD_CHEAT_CODE_OLD) update_all_cheat_info(machine);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
reload_cheat_database - reload cheat database directly on the cheat menu
|
|
---------------------------------------------------------------------------*/
|
|
|
|
static void reload_cheat_database(running_machine *machine)
|
|
{
|
|
dispose_cheat_database(machine);
|
|
if(TEST_FIELD(cheat_options, LoadNewCode)) load_cheat_database(machine, LOAD_CHEAT_CODE_NEW);
|
|
if(TEST_FIELD(cheat_options, LoadStandardCode)) load_cheat_database(machine, LOAD_CHEAT_CODE_STANDARD);
|
|
if(TEST_FIELD(cheat_options, LoadOldCode)) load_cheat_database(machine, LOAD_CHEAT_CODE_OLD);
|
|
SET_MESSAGE(found_database ? CHEAT_MESSAGE_RELOAD_CHEAT_CODE : CHEAT_MESSAGE_FAILED_TO_LOAD_DATABASE);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
dispose_cheat_database - free all cheat entries
|
|
--------------------------------------------------*/
|
|
|
|
static void dispose_cheat_database(running_machine *machine)
|
|
{
|
|
int i;
|
|
|
|
/* first, turn all cheats "OFF" */
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
temp_deactivate_cheat(machine, &cheat_list[i]);
|
|
|
|
/* next, free memory for all cheat entries */
|
|
if(cheat_list)
|
|
{
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
dispose_cheat(&cheat_list[i]);
|
|
|
|
free(cheat_list);
|
|
|
|
cheat_list = NULL;
|
|
cheat_list_length = 0;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------
|
|
save_cheat_code - save a cheat code into the database
|
|
--------------------------------------------------------*/
|
|
|
|
static void save_cheat_code(running_machine *machine, cheat_entry *entry)
|
|
{
|
|
int i;
|
|
char buf[4096];
|
|
mame_file *the_file;
|
|
|
|
/* check entry */
|
|
if(entry == NULL || entry->action_list == NULL)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
/* ##### fix me... ##### */
|
|
if(entry->flags & kCheatFlag_OldFormat)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_NO_SUPPORTED_OLD_FORMAT);
|
|
return;
|
|
}
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, main_database_name, DATABASE_SAVE) == 0)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
mame_fseek(the_file, 0, SEEK_END);
|
|
|
|
/* write the cheat code */
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
UINT8 address_length = 8;
|
|
char *name;
|
|
char *buf_strings = buf;
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
/* get name */
|
|
name = action->optional_name;
|
|
|
|
/* get address length of CPU/Region */
|
|
address_length = get_address_length(action->region);
|
|
|
|
/* print format */
|
|
#ifdef MESS
|
|
buf_strings += sprintf(buf_strings,":%s::%.8X::%.2X%.8X::%.*X::%.8X::%.8X",
|
|
machine->gamedrv->name, /* name */
|
|
thisGameCRC, /* CRC */
|
|
action->region, action->type, /* type */
|
|
address_length, action->original_address, /* address */
|
|
action->original_data, /* data */
|
|
action->extend_data); /* extend data */
|
|
#else /* MAME */
|
|
buf_strings += sprintf(buf_strings, ":%s::%.2X%.8X::%.*X::%.8X::%.8X",
|
|
machine->gamedrv->name, /* name */
|
|
action->region, action->type, /* type */
|
|
address_length, action->original_address, /* address */
|
|
action->original_data, /* data */
|
|
action->extend_data); /* extend data */
|
|
#endif
|
|
|
|
/* set description */
|
|
if(name)
|
|
buf_strings += sprintf(buf_strings, ":%s", name);
|
|
else
|
|
buf_strings += sprintf(buf_strings, ":(none)");
|
|
|
|
/* set comment */
|
|
if(i == 0 && entry->comment)
|
|
buf_strings += sprintf(buf_strings, ":%s", entry->comment);
|
|
|
|
buf_strings += sprintf(buf_strings, "\n");
|
|
|
|
/* write the cheat code */
|
|
mame_fwrite(the_file, buf, (UINT32)strlen(buf));
|
|
}
|
|
|
|
/* close the database */
|
|
mame_fclose(the_file);
|
|
|
|
/* clear dirty flag as "this entry has been saved" */
|
|
entry->flags &= ~kCheatFlag_Dirty;
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_SAVE);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
save_activation_key - save activation key code into the database
|
|
-----------------------------------------------------------------*/
|
|
|
|
static void save_activation_key(running_machine *machine, cheat_entry *entry, int entry_index)
|
|
{
|
|
int type = 0;
|
|
int key_1 = 0;
|
|
int key_2 = 0;
|
|
UINT8 region = CUSTOM_CODE_ACTIVATION_KEY;
|
|
INT8 address_length = 8;
|
|
char buf[256];
|
|
char *buf_strings = buf;
|
|
mame_file *the_file;
|
|
astring *name_1 = NULL;
|
|
astring *name_2 = NULL;
|
|
|
|
/* check activation keys */
|
|
if((entry->activation_key == 0 && entry->activation_sub_key == 0))
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_NO_ACTIVATION_KEY);
|
|
return;
|
|
}
|
|
|
|
/* check entry */
|
|
if(entry == NULL || entry->action_list == NULL)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, main_database_name, DATABASE_SAVE) == 0)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
mame_fseek(the_file, 0, SEEK_END);
|
|
|
|
/* get address length of CPU/Region */
|
|
address_length = get_address_length(entry->action_list[0].region);
|
|
|
|
/* detect activation key */
|
|
key_1 = entry->activation_key;
|
|
key_2 = entry->activation_sub_key;
|
|
|
|
/* set code */
|
|
#ifdef MESS
|
|
buf_strings += sprintf( buf_strings, ":%s::%.8X::%.2X%.8X::%.*X::%.8X::%.8X::Activation Key",
|
|
machine->gamedrv->name, /* name */
|
|
thisGameCRC, /* CRC */
|
|
region, type, /* type */
|
|
address_length, entry_index, /* address */
|
|
key_1, /* data */
|
|
key_2); /* extend data */
|
|
|
|
#else /* MAME */
|
|
buf_strings += sprintf( buf_strings, ":%s::%.2X%.8X::%.*X::%.8X::%.8X:Activation Key",
|
|
machine->gamedrv->name, /* name */
|
|
region, type, /* type */
|
|
address_length, entry_index, /* address */
|
|
key_1, /* data */
|
|
key_2); /* extend data */
|
|
#endif
|
|
|
|
/* set label of key */
|
|
if(entry->flags & kCheatFlag_Select)
|
|
{
|
|
if(entry->activation_key)
|
|
name_1 = input_code_name(astring_alloc(), entry->activation_key);
|
|
|
|
if(entry->activation_sub_key)
|
|
name_2 = input_code_name(astring_alloc(), entry->activation_sub_key);
|
|
|
|
buf_strings += sprintf(buf_strings, " (prev = %s / next = %s)", astring_c(name_1), astring_c(name_2));
|
|
}
|
|
else
|
|
{
|
|
name_1 = input_code_name(astring_alloc(), entry->activation_key);
|
|
buf_strings += sprintf(buf_strings, " (%s)", astring_c(name_1));
|
|
}
|
|
|
|
/* set tag */
|
|
if(entry->name && entry->name[0] != 0)
|
|
buf_strings += sprintf(buf_strings, ":%s\n", entry->name);
|
|
else
|
|
buf_strings += sprintf(buf_strings, ":(none)\n");
|
|
|
|
/* write the activation key code */
|
|
mame_fwrite(the_file, buf, (UINT32)strlen(buf));
|
|
|
|
if(name_1) astring_free(name_1);
|
|
if(name_2) astring_free(name_2);
|
|
|
|
/* close the database */
|
|
mame_fclose(the_file);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_ACTIVATION_KEY_SAVED);
|
|
}
|
|
|
|
/*-----------------------------------------------------------
|
|
save_pre_enable - save a pre-enable code into the database
|
|
-----------------------------------------------------------*/
|
|
|
|
static void save_pre_enable(running_machine *machine, cheat_entry *entry, int entry_index)
|
|
{
|
|
int type = 0;
|
|
UINT8 region = CUSTOM_CODE_PRE_ENABLE;
|
|
INT8 address_length = 8;
|
|
char buf[256];
|
|
char *buf_strings = buf;
|
|
mame_file *the_file;
|
|
|
|
/* if invalid cheat code, no action */
|
|
if(entry == NULL || entry->action_list == NULL)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, main_database_name, DATABASE_SAVE) == 0)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
mame_fseek(the_file, 0, SEEK_END);
|
|
|
|
/* get address length of CPU/Region */
|
|
address_length = get_address_length(entry->action_list[0].region);
|
|
|
|
#ifdef MESS
|
|
buf_strings += sprintf( buf_strings, ":%s::%.8X::%.2X%.8X::%.*X::%.8X:00000000:Pre-enable",
|
|
machine->gamedrv->name, /* name */
|
|
thisGameCRC, /* CRC */
|
|
region, type, /* type */
|
|
address_length, entry_index, /* address */
|
|
entry->selection); /* data */
|
|
#else /* MAME */
|
|
buf_strings += sprintf( buf_strings, ":%s::%.2X%.8X::%.*X::%.8X::00000000:Pre-enable",
|
|
machine->gamedrv->name, /* name */
|
|
region ,type, /* type */
|
|
address_length, entry_index, /* address */
|
|
entry->selection); /* data */
|
|
#endif
|
|
|
|
/* set label name */
|
|
if(entry->selection)
|
|
buf_strings += sprintf(buf_strings, " Label - %s", entry->action_list[entry->label_index[entry->selection]].optional_name);
|
|
|
|
/* set tag */
|
|
if(entry->name && entry->name[0] != 0)
|
|
buf_strings += sprintf(buf_strings, ":%s\n", entry->name);
|
|
else
|
|
buf_strings += sprintf(buf_strings, ":(none)\n");
|
|
|
|
/* write the pre-enable code */
|
|
mame_fwrite(the_file, buf, (UINT32)strlen(buf));
|
|
|
|
/* close the database */
|
|
mame_fclose(the_file);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_PRE_ENABLE_SAVED);
|
|
}
|
|
|
|
/*--------------------------------------------------------------
|
|
save_cheat_options - save cheat option code into the database
|
|
--------------------------------------------------------------*/
|
|
|
|
static void save_cheat_options(void)
|
|
{
|
|
char buf[256];
|
|
char *buf_strings = buf;
|
|
mame_file *the_file;
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, main_database_name, DATABASE_SAVE) == 0)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
mame_fseek(the_file, 0, SEEK_END);
|
|
|
|
/* set command code */
|
|
buf_strings += sprintf(buf_strings, ":_command:%.8X:", cheat_options);
|
|
|
|
/* set descriptions */
|
|
switch(EXTRACT_FIELD(cheat_options, SearchBox))
|
|
{
|
|
case SEARCH_BOX_MINIMUM:
|
|
buf_strings += sprintf(buf_strings, "Search Box = Minimum, ");
|
|
break;
|
|
|
|
case SEARCH_BOX_STANDARD:
|
|
buf_strings += sprintf(buf_strings, "Search Box = Standard, ");
|
|
break;
|
|
|
|
case SEARCH_BOX_ADVANCED:
|
|
buf_strings += sprintf(buf_strings, "Search Box = Minimum, ");
|
|
|
|
/* NOTE : new label option is only for advanced mode */
|
|
if(TEST_FIELD(cheat_options, DontPrintNewLabels))
|
|
buf_strings += sprintf(buf_strings, "Search Box Label = OFF, ");
|
|
else
|
|
buf_strings += sprintf(buf_strings, "Search Box Label = ON, ");
|
|
break;
|
|
}
|
|
if(TEST_FIELD(cheat_options, AutoSaveEnabled)) buf_strings += sprintf(buf_strings, "Auto Cheat Code Save, ");
|
|
if(TEST_FIELD(cheat_options, ActivationKeyMessage)) buf_strings += sprintf(buf_strings, "Activation Key Message, ");
|
|
if(TEST_FIELD(cheat_options, LoadNewCode)) buf_strings += sprintf(buf_strings, "Load New Format Code, ");
|
|
if(TEST_FIELD(cheat_options, LoadStandardCode)) buf_strings += sprintf(buf_strings, "Load Standard Format Code, ");
|
|
if(TEST_FIELD(cheat_options, LoadOldCode)) buf_strings += sprintf(buf_strings, "Load Old Format Code, ");
|
|
|
|
#ifdef MESS
|
|
if(TEST_FIELD(cheat_options, SharedCode))
|
|
buf_strings += sprintf(buf_strings, "Shared Code, ");
|
|
#endif
|
|
buf_strings += sprintf(buf_strings, "Vertical Key Speed = %d, ", EXTRACT_FIELD(cheat_options, VerticalKeyRepeatSpeed));
|
|
buf_strings += sprintf(buf_strings, "Horizontal Key Speed = %d\n", EXTRACT_FIELD(cheat_options, HorizontalKeyRepeatSpeed));
|
|
|
|
/* write the cheat option */
|
|
mame_fwrite(the_file, buf, (UINT32)strlen(buf));
|
|
|
|
/* close the database */
|
|
mame_fclose(the_file);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_SAVE);
|
|
}
|
|
|
|
/*------------------
|
|
save_description
|
|
------------------*/
|
|
|
|
static void save_description(running_machine *machine)
|
|
{
|
|
char buf[256];
|
|
mame_file *the_file;
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, main_database_name, DATABASE_SAVE) == 0)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
mame_fseek(the_file, 0, SEEK_END);
|
|
|
|
sprintf(buf, "; [ %s ]\n", machine->gamedrv->description);
|
|
|
|
/* write the description of game/machine */
|
|
mame_fwrite(the_file, buf, (UINT32)strlen(buf));
|
|
|
|
/* close the database */
|
|
mame_fclose(the_file);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_SAVE);
|
|
}
|
|
|
|
/*----------------
|
|
save_raw_code
|
|
----------------*/
|
|
|
|
static void save_raw_code(running_machine *machine)
|
|
{
|
|
int address_length = 8;
|
|
int address = 0;
|
|
char buf[256];
|
|
mame_file *the_file;
|
|
|
|
/* open the database */
|
|
if(open_cheat_database(&the_file, main_database_name, DATABASE_SAVE) == 0)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_SAVE);
|
|
return;
|
|
}
|
|
|
|
mame_fseek(the_file, 0, SEEK_END);
|
|
|
|
address_length = get_address_length(0);
|
|
|
|
#ifdef MESS
|
|
sprintf(buf, ":%s::%.8X::0000000000::%.*X::00000000::FFFFFFFF:Raw Code\n", machine->gamedrv->name, thisGameCRC, address_length, address);
|
|
#else /* MAME */
|
|
sprintf(buf, ":%s::0000000000::%.*X::00000000::FFFFFFFF:Raw Code\n", machine->gamedrv->name, address_length, address);
|
|
#endif
|
|
|
|
/* write the raw code */
|
|
mame_fwrite(the_file, buf, (UINT32)strlen(buf));
|
|
|
|
/* close the database */
|
|
mame_fclose(the_file);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_SAVE);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
do_auto_save_cheats - save normal code automatically when exit cheat system
|
|
------------------------------------------------------------------------------*/
|
|
|
|
static void do_auto_save_cheats(running_machine *machine)
|
|
{
|
|
int i;
|
|
int do_save = 0;
|
|
|
|
/* if the entry is not edited/added newly or has not been already saved, save it */
|
|
for(i = 0; i< cheat_list_length; i++)
|
|
{
|
|
if(cheat_list[i].flags & kCheatFlag_Dirty)
|
|
do_save = 1;
|
|
}
|
|
|
|
if(do_save)
|
|
{
|
|
save_description(machine);
|
|
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
{
|
|
cheat_entry *entry = &cheat_list[i];
|
|
|
|
if(entry->flags & kCheatFlag_Dirty)
|
|
save_cheat_code(machine, entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
add_cheat_from_result - add a code from result viewer to cheat list
|
|
----------------------------------------------------------------------*/
|
|
|
|
static void add_cheat_from_result(running_machine *machine, search_info *search, search_region *region, UINT32 address)
|
|
{
|
|
if(region->target_type == kRegionType_CPU || region->target_type == kRegionType_Memory)
|
|
{
|
|
int temp_string_length;
|
|
UINT32 data = read_search_operand(kSearchOperand_First, search, region, address);
|
|
char temp_string[1024];
|
|
cheat_entry *entry = get_new_cheat();
|
|
cheat_action *action = &entry->action_list[0];
|
|
|
|
temp_string_length = sprintf(temp_string, "%.8X (%d) = %.*X", address, region->target_idx, BYTE_DIGITS_TABLE[search->bytes], data);
|
|
|
|
entry->name = realloc(entry->name, temp_string_length + 1);
|
|
if(entry->name == NULL)
|
|
fatalerror( "cheat: [cheat entry] memory allocation error"
|
|
" temp_length = %.8X"
|
|
" entry->name = %p",
|
|
temp_string_length, entry->name);
|
|
|
|
memcpy(entry->name, temp_string, temp_string_length + 1);
|
|
action->region = region->target_idx;
|
|
action->address = address;
|
|
action->original_address = address;
|
|
action->data = data;
|
|
action->original_data = data;
|
|
action->extend_data = ~0;
|
|
action->last_value = NULL;
|
|
SET_FIELD(action->type, AddressSize, BYTE_INCREMENT_TABLE[search->bytes] - 1);
|
|
|
|
update_cheat_info(machine, entry, 0);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------------------------
|
|
add_cheat_from_first_result - add a code from search box to cheat list if found result is one
|
|
------------------------------------------------------------------------------------------------*/
|
|
|
|
static void add_cheat_from_first_result(running_machine *machine, search_info *search)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < search->region_list_length; i++)
|
|
{
|
|
search_region *region = &search->region_list[i];
|
|
|
|
if(region->num_results)
|
|
{
|
|
UINT32 traverse;
|
|
|
|
for(traverse = 0; traverse < region->length; traverse++)
|
|
{
|
|
UINT32 address = region->address + traverse;
|
|
|
|
if(is_region_offset_valid(search, region, traverse))
|
|
{
|
|
add_cheat_from_result(machine, search, region, address);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
add_watch_from_result - add a watchpoint from result viewer to cheat list
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static void add_watch_from_result(search_info *search, search_region *region, UINT32 address)
|
|
{
|
|
if(region->target_type == kRegionType_CPU || region->target_type == kRegionType_Memory)
|
|
{
|
|
watch_info *info = get_unused_watch();
|
|
|
|
info->address = address;
|
|
info->cpu = region->target_idx;
|
|
info->num_elements = 1;
|
|
info->element_bytes = kWatchSizeConversionTable[search->bytes];
|
|
info->label_type = kWatchLabel_None;
|
|
info->display_type = kWatchDisplayType_Hex;
|
|
info->skip = 0;
|
|
info->elements_per_line = 0;
|
|
info->add_value = 0;
|
|
info->linked_cheat = NULL;
|
|
info->label[0] = 0;
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_ADD);
|
|
}
|
|
else
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_ADD);
|
|
}
|
|
|
|
/*---------------------
|
|
search_sign_extend
|
|
---------------------*/
|
|
|
|
static UINT32 search_sign_extend(search_info *search, UINT32 value)
|
|
{
|
|
if(search->sign)
|
|
if(value & SEARCH_BYTE_SIGN_BIT_TABLE[search->bytes])
|
|
value |= ~SEARCH_BYTE_UNSIGNED_MASK_TABLE[search->bytes];
|
|
|
|
return value;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------
|
|
read_search_operand - read a data from search region and return it
|
|
---------------------------------------------------------------------*/
|
|
|
|
static UINT32 read_search_operand(UINT8 type, search_info *search, search_region *region, UINT32 address)
|
|
{
|
|
UINT32 value = 0;
|
|
|
|
switch(type)
|
|
{
|
|
case kSearchOperand_Current:
|
|
value = read_region_data(region, address - region->address, BYTE_INCREMENT_TABLE[search->bytes], search->swap);
|
|
break;
|
|
|
|
case kSearchOperand_Previous:
|
|
value = do_memory_read(region->last, address - region->address, BYTE_INCREMENT_TABLE[search->bytes], search->swap, NULL);
|
|
break;
|
|
|
|
case kSearchOperand_First:
|
|
value = do_memory_read(region->first, address - region->address, BYTE_INCREMENT_TABLE[search->bytes], search->swap, NULL);
|
|
break;
|
|
|
|
case kSearchOperand_Value:
|
|
value = search->value;
|
|
}
|
|
|
|
value = search_sign_extend(search, value);
|
|
|
|
return value;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------------------------
|
|
read_search_operand_bit - read a bit data from search region and return it when bit search
|
|
---------------------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 read_search_operand_bit(UINT8 type, search_info *search, search_region *region, UINT32 address)
|
|
{
|
|
UINT32 value = 0;
|
|
|
|
switch(type)
|
|
{
|
|
case kSearchOperand_Current:
|
|
value = read_region_data(region, address - region->address, BYTE_INCREMENT_TABLE[search->bytes], search->swap);
|
|
break;
|
|
|
|
case kSearchOperand_Previous:
|
|
value = do_memory_read(region->last, address - region->address, BYTE_INCREMENT_TABLE[search->bytes], search->swap, NULL);
|
|
break;
|
|
|
|
case kSearchOperand_First:
|
|
value = do_memory_read(region->first, address - region->address, BYTE_INCREMENT_TABLE[search->bytes], search->swap, NULL);
|
|
break;
|
|
|
|
case kSearchOperand_Value:
|
|
if(search->value)
|
|
value = 0xFFFFFFFF;
|
|
else
|
|
value = 0x00000000;
|
|
}
|
|
|
|
value = search_sign_extend(search, value);
|
|
|
|
return value;
|
|
}
|
|
|
|
/*------------------------------------------------------------
|
|
do_search_comparison - compare data and return it matched
|
|
------------------------------------------------------------*/
|
|
|
|
static UINT8 do_search_comparison(search_info *search, UINT32 lhs, UINT32 rhs)
|
|
{
|
|
INT32 svalue;
|
|
|
|
if(search->sign)
|
|
{
|
|
/* signed */
|
|
INT32 slhs = lhs;
|
|
INT32 srhs = rhs;
|
|
|
|
switch(search->comparison)
|
|
{
|
|
case kSearchComparison_LessThan:
|
|
return slhs < srhs;
|
|
|
|
case kSearchComparison_GreaterThan:
|
|
return slhs > srhs;
|
|
|
|
case kSearchComparison_EqualTo:
|
|
return slhs == srhs;
|
|
|
|
case kSearchComparison_LessThanOrEqualTo:
|
|
return slhs <= srhs;
|
|
|
|
case kSearchComparison_GreaterThanOrEqualTo:
|
|
return slhs >= srhs;
|
|
|
|
case kSearchComparison_NotEqual:
|
|
return slhs != srhs;
|
|
|
|
case kSearchComparison_IncreasedBy:
|
|
svalue = search->value;
|
|
|
|
if(search->value & SEARCH_BYTE_SIGN_BIT_TABLE[search->bytes])
|
|
svalue |= ~SEARCH_BYTE_UNSIGNED_MASK_TABLE[search->bytes];
|
|
|
|
return slhs == (srhs + svalue);
|
|
|
|
case kSearchComparison_NearTo:
|
|
return (slhs == srhs) || ((slhs + 1) == srhs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* unsigned */
|
|
switch(search->comparison)
|
|
{
|
|
case kSearchComparison_LessThan:
|
|
return lhs < rhs;
|
|
|
|
case kSearchComparison_GreaterThan:
|
|
return lhs > rhs;
|
|
|
|
case kSearchComparison_EqualTo:
|
|
return lhs == rhs;
|
|
|
|
case kSearchComparison_LessThanOrEqualTo:
|
|
return lhs <= rhs;
|
|
|
|
case kSearchComparison_GreaterThanOrEqualTo:
|
|
return lhs >= rhs;
|
|
|
|
case kSearchComparison_NotEqual:
|
|
return lhs != rhs;
|
|
|
|
case kSearchComparison_IncreasedBy:
|
|
svalue = search->value;
|
|
|
|
if(search->value & SEARCH_BYTE_SIGN_BIT_TABLE[search->bytes])
|
|
svalue |= ~SEARCH_BYTE_UNSIGNED_MASK_TABLE[search->bytes];
|
|
|
|
return lhs == (rhs + svalue);
|
|
|
|
case kSearchComparison_NearTo:
|
|
return (lhs == rhs) || ((lhs + 1) == rhs);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
do_search_comparison_bit - compare bit data and return it matched
|
|
--------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_search_comparison_bit(search_info *search, UINT32 lhs, UINT32 rhs)
|
|
{
|
|
switch(search->comparison)
|
|
{
|
|
case kSearchComparison_LessThan:
|
|
case kSearchComparison_NotEqual:
|
|
case kSearchComparison_GreaterThan:
|
|
case kSearchComparison_LessThanOrEqualTo:
|
|
case kSearchComparison_GreaterThanOrEqualTo:
|
|
case kSearchComparison_IncreasedBy:
|
|
return lhs ^ rhs;
|
|
|
|
case kSearchComparison_EqualTo:
|
|
case kSearchComparison_NearTo:
|
|
return ~(lhs ^ rhs);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------
|
|
is_region_offset_valid - ????? unused ?????
|
|
----------------------------------------------*/
|
|
|
|
#if 0
|
|
static UINT8 is_region_offset_valid(search_info *search, search_region *region, UINT32 offset)
|
|
{
|
|
switch(BYTE_INCREMENT_TABLE[search->bytes])
|
|
{
|
|
case 1:
|
|
return *((UINT8 *)®ion->status[offset]) == 0xFF;
|
|
break;
|
|
|
|
case 2:
|
|
return *((UINT16 *)®ion->status[offset]) == 0xFFFF;
|
|
break;
|
|
|
|
case 4:
|
|
return *((UINT32 *)®ion->status[offset]) == 0xFFFFFFFF;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*-----------------------------------------------------
|
|
is_region_offset_valid_bit - check selected offset
|
|
-----------------------------------------------------*/
|
|
|
|
static UINT8 is_region_offset_valid_bit(search_info *search, search_region *region, UINT32 offset)
|
|
{
|
|
switch(SEARCH_BYTE_STEP[search->bytes])
|
|
{
|
|
case 1:
|
|
return *((UINT8 *)®ion->status[offset]) != 0;
|
|
break;
|
|
|
|
case 2:
|
|
return *((UINT16 *)®ion->status[offset]) != 0;
|
|
break;
|
|
|
|
case 3:
|
|
return ((*((UINT16 *)®ion->status[offset]) != 0) | (*((UINT8 *)®ion->status[offset+2]) != 0));
|
|
break;
|
|
|
|
case 4:
|
|
return *((UINT32 *)®ion->status[offset]) != 0;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------
|
|
invalidate_region_offset - remove unmatched offset after search
|
|
------------------------------------------------------------------*/
|
|
|
|
static void invalidate_region_offset(search_info *search, search_region *region, UINT32 offset)
|
|
{
|
|
switch(SEARCH_BYTE_STEP[search->bytes])
|
|
{
|
|
case 1:
|
|
*((UINT8 *)®ion->status[offset]) = 0;
|
|
break;
|
|
|
|
case 2:
|
|
*((UINT16 *)®ion->status[offset]) = 0;
|
|
break;
|
|
|
|
case 3:
|
|
*((UINT16 *)®ion->status[offset]) = 0;
|
|
*((UINT8 *)®ion->status[offset+2]) = 0;
|
|
break;
|
|
|
|
case 4:
|
|
*((UINT32 *)®ion->status[offset]) = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
invalidate_region_offset_bit - remove unmatched offset after bit search
|
|
--------------------------------------------------------------------------*/
|
|
|
|
static void invalidate_region_offset_bit(search_info *search, search_region *region, UINT32 offset, UINT32 invalidate)
|
|
{
|
|
switch(SEARCH_BYTE_STEP[search->bytes])
|
|
{
|
|
case 1:
|
|
*((UINT8 *)®ion->status[offset]) &= ~invalidate;
|
|
break;
|
|
|
|
case 2:
|
|
*((UINT16 *)®ion->status[offset]) &= ~invalidate;
|
|
break;
|
|
|
|
case 3:
|
|
*((UINT16 *)®ion->status[offset]) &= ~invalidate;
|
|
*((UINT8 *)®ion->status[offset+2]) &= ~invalidate;
|
|
break;
|
|
|
|
case 4:
|
|
*((UINT32 *)®ion->status[offset]) &= ~invalidate;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------
|
|
invalidate_entire_regions - invalidate selected search region
|
|
----------------------------------------------------------------*/
|
|
|
|
static void invalidate_entire_region(search_info *search, search_region *region)
|
|
{
|
|
memset(region->status, 0, region->length);
|
|
|
|
search->num_results -= region->num_results;
|
|
region->num_results = 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
init_new_search - initialize search region to start a search
|
|
---------------------------------------------------------------*/
|
|
|
|
static void init_new_search(search_info *search)
|
|
{
|
|
int i;
|
|
|
|
search->num_results = 0;
|
|
|
|
for(i = 0; i < search->region_list_length; i++)
|
|
{
|
|
search_region *region = &search->region_list[i];
|
|
|
|
if(region->flags & kRegionFlag_Enabled)
|
|
{
|
|
region->num_results = 0;
|
|
|
|
memset(region->status, 0xFF, region->length);
|
|
|
|
fill_buffer_from_region(region, region->first);
|
|
|
|
memcpy(region->last, region->first, region->length);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
update_search - update a data in search region after initialize or search
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static void update_search(search_info *search)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < search->region_list_length; i++)
|
|
{
|
|
search_region *region = &search->region_list[i];
|
|
|
|
if(region->flags & kRegionFlag_Enabled)
|
|
fill_buffer_from_region(region, region->last);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------
|
|
do_search - cheat engine search core
|
|
---------------------------------------*/
|
|
|
|
static void do_search(search_info *search)
|
|
{
|
|
int i, j;
|
|
|
|
search->num_results = 0;
|
|
|
|
if(search->bytes == kSearchSize_1Bit)
|
|
{
|
|
/* bit search */
|
|
for(i = 0; i < search->region_list_length; i++)
|
|
{
|
|
search_region *region = &search->region_list[i];
|
|
UINT32 lastAddress = region->length - BYTE_INCREMENT_TABLE[search->bytes] + 1;
|
|
UINT32 increment = SEARCH_BYTE_STEP[search->bytes];
|
|
|
|
region->num_results = 0;
|
|
|
|
if(region->length < BYTE_INCREMENT_TABLE[search->bytes] || (region->flags & kRegionFlag_Enabled) == 0)
|
|
continue;
|
|
|
|
for(j = 0; j < lastAddress; j += increment)
|
|
{
|
|
UINT32 address;
|
|
UINT32 lhs, rhs;
|
|
|
|
address = region->address + j;
|
|
|
|
if(is_region_offset_valid_bit(search, region, j))
|
|
{
|
|
UINT32 validBits;
|
|
|
|
lhs = read_search_operand_bit(search->lhs, search, region, address);
|
|
rhs = read_search_operand_bit(search->rhs, search, region, address);
|
|
|
|
/* do bit search */
|
|
validBits = do_search_comparison_bit(search, lhs, rhs);
|
|
|
|
invalidate_region_offset_bit(search, region, j, ~validBits);
|
|
|
|
if(is_region_offset_valid_bit(search, region, j))
|
|
{
|
|
search->num_results++;
|
|
region->num_results++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* normal search */
|
|
for(i = 0; i < search->region_list_length; i++)
|
|
{
|
|
search_region *region = &search->region_list[i];
|
|
UINT32 lastAddress = region->length - BYTE_INCREMENT_TABLE[search->bytes] + 1;
|
|
UINT32 increment = SEARCH_BYTE_STEP[search->bytes];
|
|
|
|
region->num_results = 0;
|
|
|
|
if(region->length < BYTE_INCREMENT_TABLE[search->bytes] || (region->flags & kRegionFlag_Enabled) == 0)
|
|
continue;
|
|
|
|
for(j = 0; j < lastAddress; j += increment)
|
|
{
|
|
UINT32 address;
|
|
UINT32 lhs, rhs;
|
|
|
|
address = region->address + j;
|
|
|
|
if(is_region_offset_valid(search, region, j))
|
|
{
|
|
lhs = read_search_operand(search->lhs, search, region, address);
|
|
rhs = read_search_operand(search->rhs, search, region, address);
|
|
|
|
/* do value search */
|
|
if(do_search_comparison(search, lhs, rhs) == 0)
|
|
{
|
|
/* unmatched */
|
|
invalidate_region_offset(search, region, j);
|
|
}
|
|
else
|
|
{
|
|
/* matched */
|
|
search->num_results++;
|
|
region->num_results++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
look_up_handler_memory - search specified write handler
|
|
----------------------------------------------------------*/
|
|
|
|
static UINT8 **look_up_handler_memory(UINT8 cpu, UINT32 address, UINT32 *out_relative_address)
|
|
{
|
|
const address_map *map = memory_get_address_map(cpu, ADDRESS_SPACE_PROGRAM);
|
|
const address_map_entry *entry;
|
|
|
|
for(entry = map->entrylist; entry != NULL; entry = entry->next)
|
|
{
|
|
if(entry->write.generic != NULL && address >= entry->addrstart && address <= entry->addrend)
|
|
{
|
|
if(out_relative_address)
|
|
{
|
|
*out_relative_address = address - entry->addrstart;
|
|
return (UINT8 **)entry->baseptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------------
|
|
get_memory_region_base_pointer - return base pointer to the base of RAM associated with given CPU and address
|
|
----------------------------------------------------------------------------------------------------------------*/
|
|
|
|
static UINT8 **get_memory_region_base_pointer(UINT8 cpu, UINT8 space, UINT32 address)
|
|
{
|
|
UINT8 *buf = NULL;
|
|
|
|
switch(space)
|
|
{
|
|
case kAddressSpace_Program:
|
|
case kAddressSpace_DirectMemory:
|
|
buf = memory_get_read_ptr(cpu, ADDRESS_SPACE_PROGRAM, address);
|
|
break;
|
|
|
|
case kAddressSpace_DataSpace:
|
|
buf = memory_get_read_ptr(cpu, ADDRESS_SPACE_DATA, address);
|
|
break;
|
|
|
|
case kAddressSpace_IOSpace:
|
|
buf = memory_get_read_ptr(cpu, ADDRESS_SPACE_IO, address);
|
|
break;
|
|
|
|
case kAddressSpace_OpcodeRAM:
|
|
buf = memory_get_op_ptr(cpu, address, 0);
|
|
break;
|
|
|
|
default:
|
|
logerror("invalid address space (%x)\n", space);
|
|
}
|
|
|
|
if(buf)
|
|
buf -= address;
|
|
|
|
//logerror("pointer (return) : %p\n", buf);
|
|
|
|
return (UINT8 **)buf;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------------------
|
|
do_cpu_read - read a data from standard CPU region
|
|
NOTE : if a driver has cpu_spinutil(), reading a data via cpunum_read_byte may conflict with it
|
|
----------------------------------------------------------------------------------------------------------------*/
|
|
|
|
static UINT32 do_cpu_read(UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap)
|
|
{
|
|
cpu_region_info *info = get_cpu_info(cpu);
|
|
|
|
address = do_shift(address, info->address_shift);
|
|
|
|
switch(bytes)
|
|
{
|
|
case 1:
|
|
return (cpunum_read_byte(cpu, address + 0) << 0);
|
|
|
|
case 2:
|
|
if(swap)
|
|
return (cpunum_read_byte(cpu, address + 0) << 0) | (cpunum_read_byte(cpu, address + 1) << 8);
|
|
else
|
|
return (cpunum_read_byte(cpu, address + 0) << 8) | (cpunum_read_byte(cpu, address + 1) << 0);
|
|
break;
|
|
|
|
case 3:
|
|
if(swap)
|
|
return (cpunum_read_byte(cpu, address + 0) << 0) | (cpunum_read_byte(cpu, address + 1) << 8) |
|
|
(cpunum_read_byte(cpu, address + 2) << 16);
|
|
else
|
|
return (cpunum_read_byte(cpu, address + 0) << 16) | (cpunum_read_byte(cpu, address + 1) << 8) |
|
|
(cpunum_read_byte(cpu, address + 2) << 0);
|
|
break;
|
|
|
|
case 4:
|
|
if(swap)
|
|
return (cpunum_read_byte(cpu, address + 0) << 0) | (cpunum_read_byte(cpu, address + 1) << 8) |
|
|
(cpunum_read_byte(cpu, address + 2) << 16) | (cpunum_read_byte(cpu, address + 3) << 24);
|
|
else
|
|
return (cpunum_read_byte(cpu, address + 0) << 24) | (cpunum_read_byte(cpu, address + 1) << 16) |
|
|
(cpunum_read_byte(cpu, address + 2) << 8) | (cpunum_read_byte(cpu, address + 3) << 0);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------
|
|
do_memory_read - read a data from memory directly
|
|
----------------------------------------------------*/
|
|
|
|
static UINT32 do_memory_read(UINT8 *buf, UINT32 address, UINT8 bytes, UINT8 swap, cpu_region_info *info)
|
|
{
|
|
int i;
|
|
int data = 0;
|
|
|
|
if(info)
|
|
address = do_shift(address, info->address_shift);
|
|
|
|
if(info == NULL)
|
|
{
|
|
switch(bytes)
|
|
{
|
|
case 1:
|
|
data = buf[address];
|
|
break;
|
|
|
|
case 2:
|
|
data = *((UINT16 *)&buf[address]);
|
|
|
|
if(swap)
|
|
data = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
|
|
break;
|
|
|
|
case 4:
|
|
data = *((UINT32 *)&buf[address]);
|
|
|
|
if(swap)
|
|
data = ((data >> 24) & 0x000000FF) | ((data >> 8) & 0x0000FF00) |
|
|
((data << 8) & 0x00FF0000) | ((data << 24) & 0xFF000000);
|
|
break;
|
|
|
|
default:
|
|
info = &raw_cpu_info;
|
|
goto generic;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
generic:
|
|
|
|
for(i = 0; i < bytes; i++)
|
|
data |= swap ? buf[swap_address(address + i, bytes, info)] << (i * 8) :
|
|
buf[swap_address(address + i, bytes, info)] << ((bytes - i - 1) * 8);
|
|
|
|
return data;
|
|
}
|
|
|
|
/*-------------------------------------------------------
|
|
do_cpu_write - write a data into standard CPU region
|
|
-------------------------------------------------------*/
|
|
|
|
static void do_cpu_write(UINT32 data, UINT8 cpu, UINT32 address, UINT8 bytes, UINT8 swap)
|
|
{
|
|
cpu_region_info *info = get_cpu_info(cpu);
|
|
|
|
address = do_shift(address, info->address_shift);
|
|
|
|
switch(bytes)
|
|
{
|
|
case 1:
|
|
cpunum_write_byte(cpu, address + 0, data & 0xFF);
|
|
break;
|
|
|
|
case 2:
|
|
if(swap)
|
|
{
|
|
cpunum_write_byte(cpu, address + 0, (data >> 0) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
cpunum_write_byte(cpu, address + 0, (data >> 8) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 1, (data >> 0) & 0xFF);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
if(swap)
|
|
{
|
|
cpunum_write_byte(cpu, address + 0, (data >> 0) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 2, (data >> 16) & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
cpunum_write_byte(cpu, address + 0, (data >> 16) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 2, (data >> 0) & 0xFF);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
if(swap)
|
|
{
|
|
cpunum_write_byte(cpu, address + 0, (data >> 0) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 1, (data >> 8) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 2, (data >> 16) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 3, (data >> 24) & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
cpunum_write_byte(cpu, address + 0, (data >> 24) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 1, (data >> 16) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 2, (data >> 8) & 0xFF);
|
|
cpunum_write_byte(cpu, address + 3, (data >> 0) & 0xFF);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
logerror("do_cpu_write: bad size (%d)\n", bytes);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------
|
|
do_memory_write - write a data into memory directly
|
|
------------------------------------------------------*/
|
|
|
|
static void do_memory_write(UINT32 data, UINT8 *buf, UINT32 address, UINT8 bytes, UINT8 swap, cpu_region_info *info)
|
|
{
|
|
UINT32 i;
|
|
|
|
if(info)
|
|
address = do_shift(address, info->address_shift);
|
|
|
|
if(info == NULL)
|
|
{
|
|
switch(bytes)
|
|
{
|
|
case 1:
|
|
buf[address] = data;
|
|
break;
|
|
|
|
case 2:
|
|
if(swap)
|
|
data = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
|
|
|
|
*((UINT16 *)&buf[address]) = data;
|
|
break;
|
|
|
|
case 4:
|
|
if(swap)
|
|
data = ((data >> 24) & 0x000000FF) | ((data >> 8) & 0x0000FF00) |
|
|
((data << 8) & 0x00FF0000) | ((data << 24) & 0xFF000000);
|
|
|
|
*((UINT32 *)&buf[address]) = data;
|
|
break;
|
|
|
|
default:
|
|
info = &raw_cpu_info;
|
|
goto generic;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
generic:
|
|
|
|
for(i = 0; i < bytes; i++)
|
|
{
|
|
if(swap) buf[swap_address(address + i, bytes, info)] = data >> (i * 8);
|
|
else buf[swap_address(address + i, bytes, info)] = data >> ((bytes - i - 1) * 8);
|
|
}
|
|
}
|
|
|
|
/*------------
|
|
read_data
|
|
------------*/
|
|
|
|
static UINT32 read_data(running_machine *machine, cheat_action *action)
|
|
{
|
|
UINT8 read_from = EXTRACT_FIELD(action->type, AddressRead);
|
|
UINT8 bytes = EXTRACT_FIELD(action->type, AddressSize);
|
|
|
|
if(read_from != kReadFrom_Variable)
|
|
{
|
|
/* read a data from memory */
|
|
int address = ~0;
|
|
UINT8 region = action->region < REGION_INVALID ? EXTRACT_FIELD(action->region, CPUIndex) : action->region;
|
|
|
|
/* set address */
|
|
if(read_from == kReadFrom_Address) address = action->address;
|
|
else if(read_from == kReadFrom_Index) address = cheat_variable[action->address];
|
|
|
|
/* NOTE : data size "+1" */
|
|
bytes++;
|
|
|
|
/* 1st, adjust address */
|
|
if(action->flags & kActionFlag_IndexAddress)
|
|
{
|
|
int index_address = 0;
|
|
cpu_region_info *info = get_cpu_info(region);
|
|
|
|
index_address = do_cpu_read(region, address, EXTRACT_FIELD(action->type, CodeParameterLower) + 1, cpu_needs_swap(region));
|
|
|
|
if(info)
|
|
index_address = do_shift(index_address, info->address_shift);
|
|
|
|
if(index_address)
|
|
address = index_address + action->extend_data;
|
|
}
|
|
else if(action->flags & kActionFlag_PDWWrite)
|
|
{
|
|
if(action->flags & kActionFlag_IsFirst)
|
|
{
|
|
address += bytes;
|
|
bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1;
|
|
action->flags &= ~kActionFlag_IsFirst;
|
|
}
|
|
else
|
|
action->flags |= kActionFlag_IsFirst;
|
|
}
|
|
|
|
/* 2nd, read a data from specified region */
|
|
if(action->region < REGION_INVALID)
|
|
{
|
|
/* CPU region */
|
|
switch(EXTRACT_FIELD(action->region, AddressSpace))
|
|
{
|
|
case kAddressSpace_Program:
|
|
return do_cpu_read(region, address, bytes, cpu_needs_swap(region));
|
|
|
|
case kAddressSpace_DataSpace:
|
|
case kAddressSpace_IOSpace:
|
|
case kAddressSpace_OpcodeRAM:
|
|
case kAddressSpace_DirectMemory:
|
|
{
|
|
UINT8 *buf;
|
|
|
|
action->cached_pointer = get_memory_region_base_pointer(region, EXTRACT_FIELD(action->type, AddressSpace), address);
|
|
buf = (UINT8 *)action->cached_pointer;
|
|
|
|
if(buf)
|
|
return do_memory_read(buf, address, bytes, cpu_needs_swap(region), get_cpu_info(region));
|
|
}
|
|
break;
|
|
|
|
case kAddressSpace_MappedMemory:
|
|
{
|
|
int relative_address;
|
|
UINT8 **buf;
|
|
|
|
action->cached_pointer = look_up_handler_memory(region, address, &action->cached_offset);
|
|
buf = action->cached_pointer;
|
|
relative_address = action->cached_offset;
|
|
|
|
if(buf && *buf)
|
|
return do_memory_read(*buf, relative_address, bytes, cpu_needs_swap(region), get_cpu_info(region));
|
|
}
|
|
break;
|
|
|
|
case kAddressSpace_EEPROM:
|
|
{
|
|
int length;
|
|
UINT8 *buf;
|
|
|
|
buf = eeprom_get_data_pointer(&length);
|
|
|
|
if(is_address_in_range(action, length))
|
|
return do_memory_read(buf, address, bytes, 0, &raw_cpu_info);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* non-CPU region */
|
|
UINT8 * buf = memory_region(machine, region);
|
|
|
|
if(buf)
|
|
{
|
|
if(is_address_in_range(action, memory_region_length(machine, region)))
|
|
return do_memory_read(buf, address, bytes, region_needs_swap(region), get_region_info(region));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* read a data from variable */
|
|
return (cheat_variable[action->address] & BYTE_MASK_TABLE[bytes]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------
|
|
write_data - write a data to memory
|
|
--------------------------------------*/
|
|
|
|
static void write_data(running_machine *machine, cheat_action *action, UINT32 data)
|
|
{
|
|
UINT8 read_from = EXTRACT_FIELD(action->type, AddressRead);
|
|
UINT8 bytes = EXTRACT_FIELD(action->type, AddressSize);
|
|
|
|
if(read_from != kReadFrom_Variable)
|
|
{
|
|
/* write a data to memory */
|
|
int address = ~0;
|
|
UINT8 region = action->region < REGION_INVALID ? EXTRACT_FIELD(action->region, CPUIndex) : action->region;
|
|
|
|
/* set address */
|
|
if(read_from == kReadFrom_Address) address = action->address;
|
|
else if(read_from == kReadFrom_Index) address = cheat_variable[action->address];
|
|
|
|
/* NOTE : data size "+1" */
|
|
bytes++;
|
|
|
|
/* 1st, adjust address */
|
|
if(action->flags & kActionFlag_IndexAddress)
|
|
{
|
|
int index_address = 0;
|
|
cpu_region_info *info = get_cpu_info(region);
|
|
|
|
index_address = do_cpu_read(region, address, EXTRACT_FIELD(action->type, CodeParameterLower) + 1, cpu_needs_swap(region));
|
|
|
|
if(info)
|
|
index_address = do_shift(index_address, info->address_shift);
|
|
|
|
if(index_address)
|
|
address = index_address + action->extend_data;
|
|
}
|
|
else if(action->flags & kActionFlag_PDWWrite)
|
|
{
|
|
if(action->flags & kActionFlag_IsFirst)
|
|
{
|
|
address += bytes;
|
|
bytes = EXTRACT_FIELD(action->type, CodeParameterLower) + 1;
|
|
action->flags &= ~kActionFlag_IsFirst;
|
|
}
|
|
else
|
|
action->flags |= kActionFlag_IsFirst;
|
|
}
|
|
|
|
/* 2nd, write a data to specified region */
|
|
if(action->region < REGION_INVALID)
|
|
{
|
|
/* CPU region */
|
|
switch(EXTRACT_FIELD(action->region, AddressSpace))
|
|
{
|
|
case kAddressSpace_Program:
|
|
do_cpu_write(data, region, address, bytes, cpu_needs_swap(region));
|
|
break;
|
|
|
|
case kAddressSpace_DataSpace:
|
|
case kAddressSpace_IOSpace:
|
|
case kAddressSpace_OpcodeRAM:
|
|
case kAddressSpace_DirectMemory:
|
|
{
|
|
UINT8 *buf;
|
|
|
|
action->cached_pointer = get_memory_region_base_pointer(region, EXTRACT_FIELD(action->type, AddressSpace), address);
|
|
buf = (UINT8 *)action->cached_pointer;
|
|
|
|
if(buf)
|
|
do_memory_write(data, buf, address, bytes, cpu_needs_swap(region), get_cpu_info(region));
|
|
}
|
|
break;
|
|
|
|
case kAddressSpace_MappedMemory:
|
|
{
|
|
int relative_address;
|
|
UINT8 **buf;
|
|
|
|
action->cached_pointer = look_up_handler_memory(region, address, &action->cached_offset);
|
|
buf = action->cached_pointer;
|
|
relative_address = action->cached_offset;
|
|
|
|
if(buf && *buf)
|
|
do_memory_write(data, *buf, relative_address, bytes, cpu_needs_swap(region), get_cpu_info(region));
|
|
}
|
|
break;
|
|
|
|
case kAddressSpace_EEPROM:
|
|
{
|
|
int length;
|
|
UINT8 *buf;
|
|
|
|
buf = eeprom_get_data_pointer(&length);
|
|
|
|
if(is_address_in_range(action, length))
|
|
do_memory_write(data, buf, address, bytes, 0, &raw_cpu_info);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* non-CPU region */
|
|
UINT8 * buf = memory_region(machine, region);
|
|
|
|
if(buf)
|
|
{
|
|
if(is_address_in_range(action, memory_region_length(machine, region)))
|
|
do_memory_write(data, buf, address, bytes, region_needs_swap(region), get_region_info(action->region));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* write a data to variable */
|
|
cheat_variable[action->address] = data & BYTE_MASK_TABLE[bytes];
|
|
}
|
|
}
|
|
|
|
/*---------------------
|
|
read_or_write_data
|
|
---------------------*/
|
|
|
|
static UINT32 read_or_write_data(running_machine *machine, cheat_action *action, UINT32 data, int read_or_write)
|
|
{
|
|
switch(EXTRACT_FIELD(action->type, LocationType))
|
|
{
|
|
case kLocation_Standard:
|
|
if(read_or_write)
|
|
do_cpu_write( data, EXTRACT_FIELD(action->type, LocationParameterCPU), action->address, 1,
|
|
cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
else
|
|
return do_cpu_read( EXTRACT_FIELD(action->type, LocationParameterCPU), action->address, 1,
|
|
cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
break;
|
|
case kLocation_MemoryRegion:
|
|
{
|
|
UINT8 *buf = memory_region(machine, EXTRACT_FIELD(action->type, LocationParameterCPU));
|
|
if(buf && is_address_in_range(action, memory_region_length(machine, EXTRACT_FIELD(action->type, LocationParameterCPU))));
|
|
{
|
|
if(read_or_write)
|
|
do_memory_write( data, buf, action->address, 1, region_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)),
|
|
get_region_info(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
else
|
|
return do_memory_read( buf, action->address, 1, region_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)),
|
|
get_region_info(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
}
|
|
break;
|
|
case kLocation_HandlerMemory:
|
|
{
|
|
UINT8 **buf;
|
|
action->cached_pointer = look_up_handler_memory(EXTRACT_FIELD(action->type, LocationParameterCPU), action->address, &action->cached_offset);
|
|
buf = action->cached_pointer;
|
|
if(buf && *buf)
|
|
{
|
|
if(read_or_write)
|
|
do_memory_write( data, *buf, action->cached_offset, 1, cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)),
|
|
get_region_info(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
else
|
|
return do_memory_read( *buf, action->cached_offset, 1, cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)),
|
|
get_cpu_info(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
}
|
|
}
|
|
break;
|
|
case kLocation_IndirectIndexed:
|
|
{
|
|
UINT32 address = do_cpu_read( EXTRACT_FIELD(action->type, LocationParameterCPU), action->address,
|
|
EXTRACT_FIELD(action->type, IndexBytesUsed), cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU))) +
|
|
action->extend_data;
|
|
if(read_or_write)
|
|
do_cpu_write( data, EXTRACT_FIELD(action->type, LocationParameterCPU), address, 1,
|
|
cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
else
|
|
return do_cpu_read( EXTRACT_FIELD(action->type, LocationParameterCPU), address, 1,
|
|
cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)));
|
|
}
|
|
break;
|
|
case kLocation_Custom:
|
|
if(EXTRACT_FIELD(action->type, LocationParameter) == kCustomLocation_EEPROM)
|
|
{
|
|
int length;
|
|
UINT8 *buf = eeprom_get_data_pointer(&length);
|
|
if(is_address_in_range(action, length))
|
|
{
|
|
if(read_or_write)
|
|
do_memory_write(data, buf, action->address, 1, cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)), &raw_cpu_info);
|
|
else
|
|
return do_memory_read(buf, action->address, 1, cpu_needs_swap(EXTRACT_FIELD(action->type, LocationParameterCPU)), &raw_cpu_info);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------------------
|
|
watch_cheat_entry - set watchpoint when watch value key is pressed in several menus
|
|
--------------------------------------------------------------------------------------*/
|
|
|
|
static void watch_cheat_entry(cheat_entry *entry, UINT8 associate)
|
|
{
|
|
int i, j;
|
|
cheat_entry *associate_entry = NULL;
|
|
|
|
/* NOTE : calling with associate doesn't exist right now */
|
|
if(associate)
|
|
associate_entry = entry;
|
|
|
|
if(entry == NULL)
|
|
{
|
|
SET_MESSAGE(CHEAT_MESSAGE_FAILED_TO_ADD);
|
|
return;
|
|
}
|
|
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
if((action->flags & kActionFlag_NoAction) == 0 && EXTRACT_FIELD(action->type, AddressRead) == kReadFrom_Address)
|
|
{
|
|
/* NOTE : unsupported the watchpoint for indirect index right now */
|
|
if(action->flags & kActionFlag_IndexAddress)
|
|
continue;
|
|
|
|
if(i == 0)
|
|
{
|
|
/* first cheat action */
|
|
add_action_watch(&entry->action_list[i], associate_entry);
|
|
}
|
|
else
|
|
{
|
|
/* 2nd or later cheat action */
|
|
UINT8 different_address = 1;
|
|
|
|
for(j = 0; j < i; j++)
|
|
{
|
|
/* if we find the same address cheat action, skip it */
|
|
if(entry->action_list[j].address == entry->action_list[i].address)
|
|
different_address = 0;
|
|
}
|
|
|
|
if(different_address)
|
|
add_action_watch(&entry->action_list[i], associate_entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_SUCCEEDED_TO_ADD);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
add_action_watch - set watchpoint parameters into watch info
|
|
called from watch_cheat_entry() when watch value key
|
|
or activate_cheat() via watchpoint code
|
|
--------------------------------------------------------------------------*/
|
|
|
|
static void add_action_watch(cheat_action *action, cheat_entry *entry)
|
|
{
|
|
switch(EXTRACT_FIELD(action->type, CodeType))
|
|
{
|
|
case kCodeType_Write:
|
|
case kCodeType_IWrite:
|
|
case kCodeType_RWrite:
|
|
case kCodeType_CWrite:
|
|
case kCodeType_CBit:
|
|
case kCodeType_PDWWrite:
|
|
case kCodeType_Move:
|
|
case kCodeType_Branch:
|
|
case kCodeType_Loop:
|
|
case kCodeType_Popup:
|
|
{
|
|
watch_info *info = get_unused_watch();
|
|
|
|
info->address = action->address;
|
|
info->cpu = action->region;
|
|
info->num_elements = EXTRACT_FIELD(action->type, AddressSize) + 1;
|
|
info->element_bytes = kSearchSize_8Bit;
|
|
info->label_type = kWatchLabel_None;
|
|
info->display_type = kWatchDisplayType_Hex;
|
|
info->skip = 0;
|
|
info->linked_cheat = entry;
|
|
info->label[0] = 0;
|
|
|
|
if(action->flags & kActionFlag_PDWWrite)
|
|
{
|
|
info->num_elements += (EXTRACT_FIELD(action->type, CodeParameterLower) + 1);
|
|
}
|
|
else if(action->flags & kActionFlag_Repeat)
|
|
{
|
|
info->num_elements = EXTRACT_FIELD(action->extend_data, LSB16);
|
|
info->skip = EXTRACT_FIELD(action->extend_data, MSB16) - 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kCodeType_Watch:
|
|
{
|
|
watch_info *info = get_unused_watch();
|
|
|
|
info->address = action->address;
|
|
info->cpu = action->region;
|
|
info->num_elements = EXTRACT_FIELD(action->data, WatchNumElements) + 1;
|
|
info->element_bytes = kByteConversionTable[EXTRACT_FIELD(action->type, AddressSize)];
|
|
info->display_type = EXTRACT_FIELD(action->type, WatchDisplayFormat);
|
|
info->skip = EXTRACT_FIELD(action->data, WatchSkip);
|
|
info->elements_per_line = EXTRACT_FIELD(action->data, WatchElementsPerLine);
|
|
info->add_value = EXTRACT_FIELD(action->data, WatchAddValue);
|
|
info->linked_cheat = entry;
|
|
info->label[0] = 0;
|
|
|
|
if(info->add_value & 0x80)
|
|
info->add_value |= ~0xFF;
|
|
|
|
if(action->extend_data != ~0)
|
|
{
|
|
/* ### fix me... ### */
|
|
info->x = (float)(EXTRACT_FIELD(action->extend_data, LSB16)) / 100;
|
|
info->y = (float)(EXTRACT_FIELD(action->extend_data, MSB16)) / 100;
|
|
}
|
|
|
|
if(TEST_FIELD(action->type, WatchShowLabel) && entry->comment && strlen(entry->comment) < 256)
|
|
{
|
|
info->label_type = kWatchLabel_String;
|
|
strcpy(info->label, entry->comment);
|
|
}
|
|
else
|
|
info->label_type = kWatchLabel_None;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------------
|
|
remove_associated_watches - delete watchpoints when watchpoint CODE is "OFF"
|
|
called from deactivate_cheat(machine, ).
|
|
-------------------------------------------------------------------------------*/
|
|
|
|
static void remove_associated_watches(cheat_entry *entry)
|
|
{
|
|
int i;
|
|
|
|
for(i = watch_list_length - 1; i >= 0; i--)
|
|
{
|
|
watch_info *info = &watch_list[i];
|
|
|
|
if(info->linked_cheat == entry)
|
|
delete_watch_at(i);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------
|
|
reset_action - back up data and set action flags
|
|
---------------------------------------------------*/
|
|
|
|
static void reset_action(running_machine *machine, cheat_action *action)
|
|
{
|
|
/* back up a value */
|
|
if(action->flags & kActionFlag_OldFormat)
|
|
{
|
|
if(action->last_value == NULL)
|
|
{
|
|
action->last_value = malloc(sizeof(action->last_value));
|
|
if(action->last_value == NULL) goto reset_action_error;
|
|
action->last_value[0] = read_or_write_data(machine, action, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(action->last_value == NULL)
|
|
{
|
|
if(action->flags & kActionFlag_MemoryWrite)
|
|
{
|
|
if((action->flags & kActionFlag_LastValueGood) == 0)
|
|
{
|
|
switch(EXTRACT_FIELD(action->type, CodeType))
|
|
{
|
|
default:
|
|
/* Write, IWrite, CWrite, CBit */
|
|
action->last_value = malloc(sizeof(action->last_value));
|
|
if(action->last_value == NULL) goto reset_action_error;
|
|
action->last_value[0] = read_data(machine, action);
|
|
break;
|
|
|
|
case kCodeType_PDWWrite:
|
|
action->last_value = malloc(sizeof(action->last_value) * 2);
|
|
if(action->last_value == NULL) goto reset_action_error;
|
|
action->flags &= ~kActionFlag_IsFirst;
|
|
action->last_value[0] = read_data(machine, action);
|
|
action->last_value[1] = read_data(machine, action);
|
|
break;
|
|
|
|
case kCodeType_RWrite:
|
|
{
|
|
int i;
|
|
|
|
action->last_value = malloc(sizeof(action->last_value) * EXTRACT_FIELD(action->extend_data, LSB16));
|
|
if(action->last_value == NULL) goto reset_action_error;
|
|
for(i = 0; i < EXTRACT_FIELD(action->extend_data, LSB16); i++)
|
|
{
|
|
action->last_value[i] = read_data(machine, action);
|
|
action->address += EXTRACT_FIELD(action->extend_data, MSB16) ?
|
|
EXTRACT_FIELD(action->extend_data, MSB16) :
|
|
BYTE_INCREMENT_TABLE[EXTRACT_FIELD(action->type, AddressSize)];
|
|
}
|
|
|
|
action->address = action->original_address;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
action->last_value = NULL;
|
|
}
|
|
}
|
|
|
|
action->frame_timer = 0;
|
|
action->flags &= ~kActionFlag_StateMask;
|
|
action->flags |= kActionFlag_LastValueGood;
|
|
|
|
if(action->flags & kActionFlag_CheckCondition)
|
|
{
|
|
if(EXTRACT_FIELD(action->type, CodeParameter) == kCondition_PreviousValue)
|
|
action->extend_data = read_data(machine, action);
|
|
}
|
|
|
|
return;
|
|
|
|
reset_action_error:
|
|
|
|
fatalerror("cheat:[last value] memory allocation error\n"
|
|
" ----- %s -----\n"
|
|
" type = %.8X\n"
|
|
" last_value = %p\n",
|
|
action->optional_name, action->type, action->last_value);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------------------
|
|
activate_cheat - reset action entry and set activate entry flag when turn CODE "ON"
|
|
--------------------------------------------------------------------------------------*/
|
|
|
|
static void activate_cheat(running_machine *machine, cheat_entry *entry)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
reset_action(machine, action);
|
|
|
|
/* if watchpoint code, add watchpoint */
|
|
if(EXTRACT_FIELD(action->type, CodeType) == kCodeType_Watch)
|
|
add_action_watch(action, entry);
|
|
}
|
|
|
|
/* set activate flag */
|
|
entry->flags |= kCheatFlag_Active;
|
|
}
|
|
|
|
/*--------------------------------------------------------
|
|
restore_last_value - restore previous value if needed
|
|
--------------------------------------------------------*/
|
|
|
|
static void restore_last_value(running_machine *machine, cheat_action *action)
|
|
{
|
|
if(action->flags & kActionFlag_MemoryWrite)
|
|
{
|
|
if(TEST_FIELD(action->type, RestoreValue))
|
|
{
|
|
switch(EXTRACT_FIELD(action->type, CodeType))
|
|
{
|
|
default:
|
|
/* Write, IWrite, CWrite, CBit */
|
|
write_data(machine, action, (UINT32)action->last_value[0]);
|
|
break;
|
|
|
|
case kCodeType_PDWWrite:
|
|
action->flags &= ~kActionFlag_IsFirst;
|
|
write_data(machine, action, (UINT32)action->last_value[0]);
|
|
write_data(machine, action, (UINT32)action->last_value[1]);
|
|
break;
|
|
|
|
case kCodeType_RWrite:
|
|
{
|
|
int j;
|
|
|
|
for(j = 0; j < EXTRACT_FIELD(action->extend_data, LSB16); j++)
|
|
{
|
|
write_data(machine, action, (UINT32)action->last_value[j]);
|
|
action->address += EXTRACT_FIELD(action->extend_data, MSB16) ?
|
|
EXTRACT_FIELD(action->extend_data, MSB16) :
|
|
BYTE_INCREMENT_TABLE[EXTRACT_FIELD(action->type, AddressSize)];
|
|
}
|
|
action->address = action->original_address;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
deactivate_cheat - deactivate selecte cheat entry when turn CODE "OFF"
|
|
-------------------------------------------------------------------------*/
|
|
|
|
static void deactivate_cheat(running_machine *machine, cheat_entry *entry)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
action->frame_timer = 0;
|
|
action->flags &= ~kActionFlag_OperationDone;
|
|
|
|
/* restore previous value if needed */
|
|
if(action->last_value)
|
|
{
|
|
restore_last_value(machine, action);
|
|
action->flags &= ~kActionFlag_LastValueGood;
|
|
free(action->last_value);
|
|
}
|
|
action->last_value = NULL;
|
|
}
|
|
|
|
/* remove watchpoint */
|
|
remove_associated_watches(entry);
|
|
|
|
/* clear active flag */
|
|
entry->flags &= ~kCheatFlag_StateMask;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------
|
|
temp_deactivate_cheat - deactivate cheat when turn CHEAT "OFF"
|
|
-----------------------------------------------------------------*/
|
|
|
|
static void temp_deactivate_cheat(running_machine *machine, cheat_entry *entry)
|
|
{
|
|
if(entry->flags & kCheatFlag_Active)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
action->frame_timer = 0;
|
|
action->flags &= ~kActionFlag_OperationDone;
|
|
|
|
/* restore previous value if needed */
|
|
if(action->last_value)
|
|
restore_last_value(machine, action);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------
|
|
cheat_periodic_operation - management for cheat operations
|
|
-------------------------------------------------------------*/
|
|
|
|
static void cheat_periodic_operation(running_machine *machine, cheat_action *action)
|
|
{
|
|
int data = TEST_FIELD(action->type, DataRead) ? cheat_variable[action->data] : action->data;
|
|
|
|
if(action->flags & kActionFlag_PDWWrite)
|
|
{
|
|
action->flags &= ~kActionFlag_IsFirst;
|
|
write_data(machine, action, data);
|
|
write_data(machine, action, action->extend_data);
|
|
}
|
|
else if(action->flags & kActionFlag_Repeat)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < EXTRACT_FIELD(action->extend_data, LSB16); i++)
|
|
{
|
|
write_data(machine, action, data);
|
|
action->address += EXTRACT_FIELD(action->extend_data, MSB16) ?
|
|
EXTRACT_FIELD(action->extend_data, MSB16) :
|
|
BYTE_INCREMENT_TABLE[EXTRACT_FIELD(action->type, AddressSize)];
|
|
}
|
|
action->address = action->original_address;
|
|
}
|
|
else
|
|
{
|
|
switch(EXTRACT_FIELD(action->type, CodeType))
|
|
{
|
|
case kCodeType_Write:
|
|
write_data(machine, action, (data & action->extend_data) | (read_data(machine, action) & ~action->extend_data));
|
|
break;
|
|
|
|
case kCodeType_IWrite:
|
|
switch(EXTRACT_FIELD(action->type, CodeParameter))
|
|
{
|
|
case IWRITE_WRITE:
|
|
write_data(machine, action, data);
|
|
break;
|
|
|
|
case IWRITE_BIT_SET:
|
|
write_data(machine, action, read_data(machine, action) | data);
|
|
break;
|
|
|
|
case IWRITE_BIT_CLEAR:
|
|
write_data(machine, action, read_data(machine, action) & ~data);
|
|
break;
|
|
|
|
case IWRITE_LIMITED_MASK:
|
|
write_data(machine, action, (EXTRACT_FIELD(data, MSB16) & EXTRACT_FIELD(data, LSB16)) | (read_data(machine, action) & ~EXTRACT_FIELD(data, LSB16)));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case kCodeType_CWrite:
|
|
write_data(machine, action, data);
|
|
break;
|
|
|
|
case kCodeType_CBit:
|
|
switch(EXTRACT_FIELD(action->type, CodeParameterUpper))
|
|
{
|
|
case CBIT_BIT_SET:
|
|
write_data(machine, action, read_data(machine, action) | data);
|
|
break;
|
|
|
|
case CBIT_BIT_CLEAR:
|
|
write_data(machine, action, read_data(machine, action) & ~data);
|
|
break;
|
|
|
|
case CBIT_LIMITED_MASK:
|
|
write_data(machine, action, (EXTRACT_FIELD(data, MSB16) & EXTRACT_FIELD(data, LSB16)) | (read_data(machine, action) & ~EXTRACT_FIELD(data, LSB16)));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case kCodeType_Move:
|
|
cheat_variable[EXTRACT_FIELD(action->type, CodeParameter)] = read_data(machine, action) + data;
|
|
break;
|
|
|
|
case kCodeType_Popup:
|
|
switch(EXTRACT_FIELD(action->type, PopupParameter))
|
|
{
|
|
case kPopup_Label:
|
|
ui_popup_time(1, "%s", action->optional_name);
|
|
break;
|
|
|
|
case kPopup_Value:
|
|
ui_popup_time(1, "%*.*X",
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)],
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)],
|
|
read_data(machine, action));
|
|
break;
|
|
|
|
case kPopup_LabelValue:
|
|
ui_popup_time(1, "%s %*.*X",
|
|
action->optional_name,
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)],
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)],
|
|
read_data(machine, action));
|
|
break;
|
|
|
|
case kPopup_ValueLabel:
|
|
ui_popup_time(1, "%*.*X %s",
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)],
|
|
BYTE_DIGITS_TABLE[EXTRACT_FIELD(action->type, AddressSize)],
|
|
read_data(machine, action),
|
|
action->optional_name);
|
|
break;
|
|
}
|
|
break;
|
|
#ifdef MAME_DEBUG
|
|
default:
|
|
ui_popup_time(1, "Invalid CodeType : %X", EXTRACT_FIELD(action->type, CodeType));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------
|
|
cheat_periodic_condition - management for cheat conditions
|
|
-------------------------------------------------------------*/
|
|
|
|
static UINT8 cheat_periodic_condition(running_machine *machine, cheat_action *action)
|
|
{
|
|
int data = read_data(machine, action);
|
|
int value = action->extend_data;
|
|
|
|
if(EXTRACT_FIELD(action->type, CodeType) != kCodeType_CBit)
|
|
{
|
|
/* CWrite, Branch, Popup */
|
|
switch(EXTRACT_FIELD(action->type, CodeParameter))
|
|
{
|
|
case kCondition_Equal:
|
|
return (data == value);
|
|
|
|
case kCondition_NotEqual:
|
|
return (data != value);
|
|
|
|
case kCondition_Less:
|
|
return (data < value);
|
|
|
|
case kCondition_LessOrEqual:
|
|
return (data <= value);
|
|
|
|
case kCondition_Greater:
|
|
return (data > value);
|
|
|
|
case kCondition_GreaterOrEqual:
|
|
return (data >= value);
|
|
|
|
case kCondition_BitSet:
|
|
return (data & value);
|
|
|
|
case kCondition_BitClear:
|
|
return (!(data & value));
|
|
|
|
case kCondition_PreviousValue:
|
|
if(data != value)
|
|
{
|
|
action->extend_data = data;
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
case kCondition_KeyPressedOnce:
|
|
return (input_code_pressed_once(value));
|
|
|
|
case kCondition_KeyPressedRepeat:
|
|
return (input_code_pressed(value));
|
|
|
|
case kCondition_True:
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* CBit */
|
|
switch(EXTRACT_FIELD(action->type, CodeParameterLower))
|
|
{
|
|
case CONDITION_CBIT_BIT_SET:
|
|
return (data & value);
|
|
|
|
case CONDITION_CBIT_BIT_CLEAR:
|
|
return (!(data & value));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------
|
|
cheat_periodic_action - management for cheat actions
|
|
-------------------------------------------------------*/
|
|
|
|
static int cheat_periodic_action(running_machine *machine, cheat_action *action, int selection)
|
|
{
|
|
UINT8 execute_operation = 0;
|
|
|
|
if(action->flags & kActionFlag_NoAction) return selection + 1;
|
|
if(action->flags & kActionFlag_OperationDone) return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1);
|
|
|
|
if(TEST_FIELD(action->type, PrefillEnable))
|
|
{
|
|
if((action->flags & kActionFlag_PrefillDone) == 0)
|
|
{
|
|
UINT8 prefillValue = kPrefillValueTable[EXTRACT_FIELD(action->type, PrefillEnable)];
|
|
|
|
if((action->flags & kActionFlag_PrefillWritten) == 0)
|
|
{
|
|
/* set prefill */
|
|
write_data(machine, action, prefillValue);
|
|
action->flags |= kActionFlag_PrefillWritten;
|
|
return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1);
|
|
}
|
|
else
|
|
{
|
|
/* do re-write */
|
|
if(read_data(machine, action) == prefillValue)
|
|
return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1);
|
|
|
|
action->flags |= kActionFlag_PrefillDone;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(EXTRACT_FIELD(action->type, DelayEnable))
|
|
{
|
|
if(TEST_FIELD(action->type, OneShot) && TEST_FIELD(action->type, RestoreValue))
|
|
{
|
|
/* Keep */
|
|
execute_operation = 1;
|
|
|
|
if(action->frame_timer++ >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds))
|
|
action->flags |= kActionFlag_OperationDone;
|
|
}
|
|
else
|
|
{
|
|
if(action->frame_timer++ >= EXTRACT_FIELD(action->type, DelayEnable) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds))
|
|
{
|
|
/* Delay */
|
|
execute_operation = 1;
|
|
action->frame_timer = 0;
|
|
|
|
if(TEST_FIELD(action->type, OneShot))
|
|
action->flags |= kActionFlag_OperationDone;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(action->frame_timer++ >= EXTRACT_FIELD(action->type, DelayEnable) + ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds))
|
|
return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1);
|
|
|
|
execute_operation = 1;
|
|
|
|
if(TEST_FIELD(action->type, OneShot))
|
|
action->flags |= kActionFlag_OperationDone;
|
|
}
|
|
|
|
if(action->flags & kActionFlag_CheckCondition)
|
|
{
|
|
if(cheat_periodic_condition(machine, action))
|
|
execute_operation = 1;
|
|
else
|
|
execute_operation = 0;
|
|
}
|
|
|
|
if(execute_operation)
|
|
{
|
|
/* do cheat operation */
|
|
switch(EXTRACT_FIELD(action->type, CodeType))
|
|
{
|
|
case kCodeType_Write:
|
|
case kCodeType_IWrite:
|
|
case kCodeType_RWrite:
|
|
case kCodeType_CWrite:
|
|
case kCodeType_CBit:
|
|
case kCodeType_PDWWrite:
|
|
case kCodeType_Move:
|
|
case kCodeType_Popup:
|
|
cheat_periodic_operation(machine, action);
|
|
break;
|
|
|
|
case kCodeType_Branch:
|
|
return action->data;
|
|
|
|
case kCodeType_Loop:
|
|
{
|
|
int counter = read_data(machine, action);
|
|
|
|
if(counter != 0)
|
|
{
|
|
write_data(machine, action, counter - 1);
|
|
|
|
return (TEST_FIELD(action->type, DataRead) ? cheat_variable[action->data] : action->data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (TEST_FIELD(action->type, Return) ? CHEAT_RETURN_VALUE : selection + 1);
|
|
}
|
|
|
|
/*------------------------------------------------------
|
|
cheat_periodic_entry - management for cheat entries
|
|
------------------------------------------------------*/
|
|
|
|
static void cheat_periodic_entry(running_machine *machine, cheat_entry *entry)
|
|
{
|
|
int i = 0;
|
|
UINT8 pressedKey = 0;
|
|
UINT8 isSelect = 0;
|
|
|
|
/* ***** 1st, handle activation key ***** */
|
|
|
|
if(ui_is_menu_active() == 0)
|
|
{
|
|
/* NOTE : activation key should be not checked in activating UI menu because it conflicts activation key checker */
|
|
if(entry->activation_key)
|
|
{
|
|
if(input_code_pressed_once(entry->activation_key))
|
|
pressedKey = 1;
|
|
}
|
|
else if(entry->activation_sub_key)
|
|
{
|
|
if(input_code_pressed_once(entry->activation_sub_key))
|
|
pressedKey = 2;
|
|
}
|
|
}
|
|
|
|
if(entry->flags & kCheatFlag_Select)
|
|
{
|
|
if(pressedKey)
|
|
{
|
|
if(pressedKey == 1)
|
|
{
|
|
if(--entry->selection < 0)
|
|
entry->selection = entry->label_index_length - 1;
|
|
}
|
|
else
|
|
{
|
|
if(++entry->selection >= entry->label_index_length)
|
|
entry->selection = 0;
|
|
}
|
|
|
|
/* NOTE : in handling activatio key, forced to activate a cheat even if one shot */
|
|
if(!(entry->flags & kCheatFlag_OneShot) && !(entry->label_index[entry->selection]))
|
|
deactivate_cheat(machine, entry);
|
|
else
|
|
activate_cheat(machine, entry);
|
|
|
|
if(TEST_FIELD(cheat_options, ActivationKeyMessage))
|
|
{
|
|
if(!entry->selection)
|
|
ui_popup_time(1,"%s disabled", entry->name);
|
|
else
|
|
ui_popup_time(1,"%s : %s selected", entry->name, entry->action_list[entry->label_index[entry->selection]].optional_name);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* NOTE : if value-selection has activatinon key, no handling -----*/
|
|
if(!(entry->flags & kCheatFlag_UserSelect) && pressedKey)
|
|
{
|
|
if(entry->flags & kCheatFlag_OneShot)
|
|
{
|
|
activate_cheat(machine, entry);
|
|
|
|
if(TEST_FIELD(cheat_options, ActivationKeyMessage))
|
|
ui_popup_time(1,"set %s", entry->name);
|
|
}
|
|
else if(entry->flags & kCheatFlag_Active)
|
|
{
|
|
deactivate_cheat(machine, entry);
|
|
|
|
if(TEST_FIELD(cheat_options, ActivationKeyMessage))
|
|
ui_popup_time(1,"%s disabled", entry->name);
|
|
}
|
|
else
|
|
{
|
|
activate_cheat(machine, entry);
|
|
|
|
if(TEST_FIELD(cheat_options, ActivationKeyMessage))
|
|
ui_popup_time(1,"%s enabled", entry->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ***** 2nd, do cheat actions ***** */
|
|
|
|
/* if "OFF", no action */
|
|
if(driverSpecifiedFlag != 0 || (entry->flags & kCheatFlag_Active) == 0)
|
|
return;
|
|
|
|
while(1)
|
|
{
|
|
if(entry->action_list[i].flags & kActionFlag_Custom)
|
|
{
|
|
if(entry->action_list[i].region == CUSTOM_CODE_LABEL_SELECT)
|
|
{
|
|
i = entry->label_index[entry->selection];
|
|
isSelect = 1;
|
|
continue;
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
else
|
|
i = cheat_periodic_action(machine, &entry->action_list[i], i);
|
|
|
|
if(i >= entry->action_list_length)
|
|
break;
|
|
|
|
if(isSelect && EXTRACT_FIELD(entry->action_list[i].type, Link) == LINK_LABEL_LINK)
|
|
break;
|
|
}
|
|
|
|
/* ***** 3rd, deactive a cheat if one shot ***** */
|
|
|
|
if(entry->flags & kCheatFlag_OneShot)
|
|
{
|
|
UINT8 done = 1;
|
|
|
|
i = 0;
|
|
isSelect = 0;
|
|
|
|
while(1)
|
|
{
|
|
if(entry->action_list[i].flags & kActionFlag_Custom)
|
|
{
|
|
if(entry->action_list[i].region == CUSTOM_CODE_LABEL_SELECT)
|
|
{
|
|
i = entry->label_index[entry->selection];
|
|
isSelect = 1;
|
|
continue;
|
|
}
|
|
}
|
|
else if(entry->action_list[i].flags & kActionFlag_MemoryWrite)
|
|
if((entry->action_list[i].flags & kActionFlag_OperationDone) == 0)
|
|
done = 0;
|
|
|
|
i++;
|
|
|
|
if(i >= entry->action_list_length)
|
|
break;
|
|
|
|
if(isSelect && EXTRACT_FIELD(entry->action_list[i].type, Link) != LINK_LABEL_LINK)
|
|
break;
|
|
}
|
|
|
|
if(done)
|
|
deactivate_cheat(machine, entry);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------
|
|
cheat_periodic_old_entry - management for old cheat entries
|
|
--------------------------------------------------------------*/
|
|
|
|
static void cheat_periodic_old_entry(running_machine *machine, cheat_entry *entry)
|
|
{
|
|
int i, do_action = 0, done = 1;
|
|
|
|
/* special handling for select cheats */
|
|
if(entry->flags & kCheatFlag_Select)
|
|
{
|
|
if(entry->activation_key)
|
|
{
|
|
if(input_code_pressed_once(entry->activation_key))
|
|
{
|
|
entry->selection++;
|
|
if(entry->flags & kCheatFlag_OneShot)
|
|
{
|
|
if(entry->selection >= entry->action_list_length)
|
|
{
|
|
entry->selection = 1;
|
|
if(entry->selection >= entry->action_list_length) entry->selection = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(entry->selection >= entry->action_list_length) { entry->selection = 0; deactivate_cheat(machine, entry); }
|
|
else { activate_cheat(machine, entry); }
|
|
}
|
|
}
|
|
}
|
|
/* if a subcheat is selected and it's a legal index, handle it */
|
|
if(entry->selection && (entry->selection < entry->action_list_length)) do_action = 1;
|
|
}
|
|
else
|
|
{
|
|
if((entry->flags & kCheatFlag_UserSelect) != 0)
|
|
{
|
|
if(input_code_pressed_once(entry->activation_key)) activate_cheat(machine, entry);
|
|
else
|
|
{
|
|
if(entry->flags & kCheatFlag_Active) deactivate_cheat(machine, entry);
|
|
else activate_cheat(machine, entry);
|
|
}
|
|
}
|
|
|
|
if((entry->flags & kCheatFlag_Active) == 0) return;
|
|
do_action = 1;
|
|
}
|
|
if(do_action)
|
|
{
|
|
|
|
for(i = entry->flags & kCheatFlag_Select ? entry->selection : 0; i < entry->action_list_length; i++)
|
|
{
|
|
int do_operation = 0;
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
if(action->flags & kActionFlag_OperationDone) break;
|
|
if(TEST_FIELD(action->type, Prefill) && ((action->flags & kActionFlag_PrefillDone) == 0))
|
|
{
|
|
if((action->flags & kActionFlag_PrefillWritten) == 0)
|
|
{
|
|
write_data(machine, action, kPrefillValueTable[EXTRACT_FIELD(action->type, Prefill)]);
|
|
action->flags |= kActionFlag_PrefillWritten;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if(read_or_write_data(machine, action, 0, 0) == kPrefillValueTable[EXTRACT_FIELD(action->type, Prefill)]) return;
|
|
action->flags |= kActionFlag_PrefillDone;
|
|
}
|
|
}
|
|
switch(EXTRACT_FIELD(action->type, Type))
|
|
{
|
|
case kType_NormalOrDelay:
|
|
if(action->frame_timer++ >= EXTRACT_FIELD(action->type, TypeParameter) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds))
|
|
do_operation = 1;
|
|
break;
|
|
case kType_WaitForModification:
|
|
if(action->flags & kActionFlag_WasModified)
|
|
{
|
|
if(action->frame_timer-- <= 0)
|
|
{
|
|
do_operation = 1;
|
|
action->flags &= ~kActionFlag_WasModified;
|
|
if(TEST_FIELD(action->type, OneShot))
|
|
action->flags |= kActionFlag_OperationDone;
|
|
}
|
|
action->last_value[0] = read_or_write_data(machine, action, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
if(read_or_write_data(machine, action, 0, 0) != action->last_value[0])
|
|
{
|
|
action->frame_timer = EXTRACT_FIELD(action->type, TypeParameter) * ATTOSECONDS_TO_HZ(video_screen_get_frame_period(machine->primary_screen).attoseconds);
|
|
action->flags |= kActionFlag_WasModified;
|
|
}
|
|
action->last_value[0] = read_or_write_data(machine, action, 0, 0);
|
|
}
|
|
break;
|
|
case kType_IgnoreIfDecrementing:
|
|
if(read_or_write_data(machine, action, 0, 0) != (action->last_value[0] - EXTRACT_FIELD(action->type, TypeParameter)))
|
|
do_operation = 1;
|
|
if(TEST_FIELD(action->type, OneShot))
|
|
action->flags |= kActionFlag_OperationDone;
|
|
action->last_value[0] = read_or_write_data(machine, action, 0, 0);
|
|
break;
|
|
case kType_Watch:
|
|
default:
|
|
break;
|
|
}
|
|
if(do_operation)
|
|
{
|
|
switch(EXTRACT_FIELD(action->type, Operation))
|
|
{
|
|
case kOperation_WriteMask:
|
|
read_or_write_data(machine, action, action->extend_data != ~0 ? ~action->data : action->data, 1);
|
|
break;
|
|
case kOperation_AddSubtract:
|
|
/* OperationParameter field stores add/subtract */
|
|
if(TEST_FIELD(action->type, OperationParameter))
|
|
{ /* subtract */
|
|
read_or_write_data(machine, action,
|
|
read_or_write_data(machine, action, 0, 0) > action->extend_data + action->data ?
|
|
read_or_write_data(machine, action, 0, 0) - (action->extend_data + action->data) :
|
|
read_or_write_data(machine, action, 0, 0),
|
|
1);
|
|
}
|
|
else
|
|
{ /* add */
|
|
read_or_write_data(machine, action,
|
|
read_or_write_data(machine, action, 0, 0) < action->extend_data + action->data ?
|
|
read_or_write_data(machine, action, 0, 0) + (action->extend_data + action->data) :
|
|
read_or_write_data(machine, action, 0, 0),
|
|
1);
|
|
}
|
|
break;
|
|
case kOperation_ForceRange:
|
|
if( read_or_write_data(machine, action, 0, 0) < EXTRACT_FIELD(action->extend_data, MSB16) ||
|
|
read_or_write_data(machine, action, 0, 0) > EXTRACT_FIELD(action->extend_data, LSB16))
|
|
read_or_write_data(machine, action, action->data, 0);
|
|
break;
|
|
case kOperation_SetOrClearBits:
|
|
read_or_write_data(machine, action,
|
|
EXTRACT_FIELD(action->type, OperationParameter) ?
|
|
read_or_write_data(machine, action, 0, 0) & ~action->data :
|
|
read_or_write_data(machine, action, 0, 0) | action->data,
|
|
1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if(entry->flags & kCheatFlag_Select) break;
|
|
}
|
|
/* if all actions are done, deactivate the cheat */
|
|
for(i = entry->flags & kCheatFlag_Select ? entry->selection : 0; i < entry->action_list_length && done; i++)
|
|
if((entry->action_list[i].flags & kActionFlag_OperationDone) == 0) done = 0;
|
|
if(done) deactivate_cheat(machine, entry);
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------------------
|
|
choose_label_index - select next or prevous label then activate/deactivate a cheat
|
|
-------------------------------------------------------------------------------------*/
|
|
|
|
static void choose_label_index(running_machine *machine, cheat_entry *entry, int next_or_previous)
|
|
{
|
|
cheat_action *action = NULL;
|
|
|
|
entry->selection += next_or_previous;
|
|
|
|
if(entry->flags & kCheatFlag_OldFormat)
|
|
{
|
|
if(entry->flags & kCheatFlag_OneShot)
|
|
{
|
|
if(entry->selection <= 0) entry->selection = entry->action_list_length - 1;
|
|
else if(entry->selection >= entry->action_list_length) entry->selection = 1;
|
|
}
|
|
else
|
|
{
|
|
if(entry->selection < 0) entry->selection = entry->action_list_length - 1;
|
|
else if(entry->selection >= entry->action_list_length) entry->selection = 0;
|
|
|
|
action = &entry->action_list[entry->selection];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(entry->flags & kCheatFlag_OneShot)
|
|
{
|
|
if(entry->selection <= 0) entry->selection = entry->label_index_length - 1;
|
|
else if(entry->selection >= entry->label_index_length) entry->selection = 1;
|
|
}
|
|
else
|
|
{
|
|
if(entry->selection < 0) entry->selection = entry->label_index_length - 1;
|
|
else if(entry->selection >= entry->label_index_length) entry->selection = 0;
|
|
|
|
action = &entry->action_list[entry->label_index[entry->selection]];
|
|
}
|
|
}
|
|
|
|
/* NOTE : one shot should not activate cheat if only selection */
|
|
if(action != NULL)
|
|
{
|
|
if(entry->selection) activate_cheat(machine, entry);
|
|
else deactivate_cheat(machine, entry);
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------
|
|
build_label_index_table - create index table for label-selection and calculate index table length
|
|
----------------------------------------------------------------------------------------------------*/
|
|
|
|
static void build_label_index_table(cheat_entry *entry)
|
|
{
|
|
int i, j, length = 0;
|
|
|
|
if(entry->flags & kCheatFlag_OldFormat) return;
|
|
if(entry->label_index != NULL) return;
|
|
|
|
entry->label_index_length = 0;
|
|
|
|
for(i = 0, j = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
if(action->region == CUSTOM_CODE_LABEL_SELECT)
|
|
{
|
|
/* label selection master code */
|
|
entry->label_index = malloc(sizeof(entry->label_index) * (++entry->label_index_length + 1));
|
|
|
|
if(entry->label_index == NULL) goto label_index_error;
|
|
|
|
entry->label_index[j++] = i;
|
|
length = action->data ? action->data + i : entry->action_list_length;
|
|
}
|
|
else if(EXTRACT_FIELD(action->type, Link) == LINK_LABEL_LINK)
|
|
{
|
|
/* link or sub-link code */
|
|
if(length)
|
|
{
|
|
entry->label_index = realloc(entry->label_index, sizeof(entry->label_index) * (++entry->label_index_length + 1));
|
|
|
|
if(entry->label_index == NULL) goto label_index_error;
|
|
|
|
entry->label_index[j++] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(entry->label_index_length <= 1)
|
|
{
|
|
logerror("cheat: [label index table] %s fails to build due to invalid or no link\n", entry->name); return;
|
|
}
|
|
else
|
|
/* set terminator */
|
|
entry->label_index[entry->label_index_length] = ~0;
|
|
|
|
if(entry->flags & kCheatFlag_OneShot)
|
|
entry->selection = 1;
|
|
|
|
/* logerror("Cheat - Finish building index table for %s (length = %x)\n", entry->name, entry->label_index_length); */
|
|
/* for(i = 0; i < entry->label_index_length; i++) */
|
|
/* logerror("IndexTable[%x] = %x\n",i,entry->label_index[i]); */
|
|
|
|
return;
|
|
|
|
label_index_error:
|
|
|
|
fatalerror("cheat:[label index table] memory allocation error\n"
|
|
" name = %s\n"
|
|
" label_index_length = %.8X\n"
|
|
" label_index_length = %p\n",
|
|
entry->name, entry->label_index_length, entry->label_index);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------
|
|
update_all_cheat_info - update all cheat info when database loaded
|
|
---------------------------------------------------------------------*/
|
|
|
|
static void update_all_cheat_info(running_machine *machine)
|
|
{
|
|
int i;
|
|
|
|
/* update flags for all cheat entry */
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
update_cheat_info(machine, &cheat_list[i], 1);
|
|
|
|
set_layer_index();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------------------------------
|
|
update_cheat_info - check several fields on cheat entry and cheat action then set flags
|
|
"is_load_time" parameter is set when called update_all_cheat_info() right now
|
|
----------------------------------------------------------------------------------------------------*/
|
|
|
|
static void update_cheat_info(running_machine *machine, cheat_entry *entry, UINT8 is_load_time)
|
|
{
|
|
int i;
|
|
int flags = 0;
|
|
UINT8 is_one_shot = 1;
|
|
UINT8 is_null = 1;
|
|
UINT8 is_separator = 1;
|
|
UINT8 is_new_format = 1;
|
|
|
|
flags = entry->flags & kCheatFlag_PersistentMask;
|
|
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
int action_flags = action->flags & kActionFlag_PersistentMask;
|
|
|
|
if(TEST_FIELD(action->type, OneShot) == 0)
|
|
is_one_shot = 0;
|
|
|
|
if(action_flags & kActionFlag_OldFormat)
|
|
{
|
|
if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_Custom) &&
|
|
(EXTRACT_FIELD(action->type, LocationParameter) == kCustomLocation_Select))
|
|
flags |= kCheatFlag_Select;
|
|
|
|
if(is_null && EXTRACT_FIELD(action->type, LocationType) != kLocation_Custom)
|
|
is_null = 0;
|
|
|
|
if(TEST_FIELD(action->type, UserSelectEnable))
|
|
flags |= kCheatFlag_UserSelect;
|
|
|
|
if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_Custom) &&
|
|
(EXTRACT_FIELD(action->type, LocationParameter) == kCustomLocation_Select))
|
|
action_flags |= kActionFlag_NoAction;
|
|
|
|
if( (EXTRACT_FIELD(action->type, LocationType) == kLocation_IndirectIndexed) ||
|
|
((EXTRACT_FIELD(action->type, LocationType) != kLocation_Custom) &&
|
|
((EXTRACT_FIELD(action->type, Operation) == 1))))
|
|
action_flags |= kActionFlag_IndexAddress;
|
|
|
|
if(i && entry->action_list[i-1].type == entry->action_list[i].type)
|
|
{
|
|
if( entry->action_list[i].address >= entry->action_list[i-1].address &&
|
|
entry->action_list[i].address <= entry->action_list[i-1].address + 3)
|
|
action_flags |= kActionFlag_NoAction;
|
|
}
|
|
|
|
is_new_format = 0;
|
|
}
|
|
else
|
|
{
|
|
if(action->region < CUSTOM_CODE)
|
|
{
|
|
switch(EXTRACT_FIELD(action->type, CodeType))
|
|
{
|
|
case kCodeType_Write:
|
|
action_flags |= kActionFlag_MemoryWrite;
|
|
break;
|
|
|
|
case kCodeType_IWrite:
|
|
action_flags |= kActionFlag_MemoryWrite;
|
|
if(action->extend_data != ~0)
|
|
{
|
|
action_flags |= kActionFlag_IndexAddress;
|
|
if(EXTRACT_FIELD(action->type, CodeParameterUpper) == IWRITE_LIMITED_MASK)
|
|
action_flags |= kActionFlag_LimitedMask;
|
|
}
|
|
break;
|
|
|
|
case kCodeType_RWrite:
|
|
action_flags |= kActionFlag_MemoryWrite;
|
|
action_flags |= kActionFlag_Repeat;
|
|
break;
|
|
|
|
case kCodeType_CWrite:
|
|
action_flags |= kActionFlag_MemoryWrite;
|
|
action_flags |= kActionFlag_CheckCondition;
|
|
break;
|
|
|
|
case kCodeType_CBit:
|
|
action_flags |= kActionFlag_MemoryWrite;
|
|
action_flags |= kActionFlag_CheckCondition;
|
|
if(EXTRACT_FIELD(action->type, CodeParameterUpper) == CBIT_LIMITED_MASK)
|
|
action_flags |= kActionFlag_LimitedMask;
|
|
break;
|
|
|
|
case kCodeType_PDWWrite:
|
|
action_flags |= kActionFlag_MemoryWrite;
|
|
action_flags |= kActionFlag_PDWWrite;
|
|
break;
|
|
|
|
case kCodeType_Move:
|
|
if(action->extend_data != ~0)
|
|
action_flags |= kActionFlag_IndexAddress;
|
|
break;
|
|
|
|
case kCodeType_Branch:
|
|
action_flags |= kActionFlag_CheckCondition;
|
|
break;
|
|
|
|
case kCodeType_Popup:
|
|
action_flags |= kActionFlag_CheckCondition;
|
|
break;
|
|
|
|
case kCodeType_Watch:
|
|
action_flags |= kActionFlag_NoAction;
|
|
break;
|
|
}
|
|
|
|
if(TEST_FIELD(action->type, ValueSelectEnable))
|
|
flags |= kCheatFlag_UserSelect;
|
|
|
|
if(EXTRACT_FIELD(action->type, Link) == LINK_LABEL_LINK)
|
|
action_flags |= kActionFlag_IsLabel;
|
|
else if(EXTRACT_FIELD(action->type, Link) == LINK_LABEL_SUB_LINK)
|
|
action_flags |= kActionFlag_IsSubLabel;
|
|
|
|
is_null = 0;
|
|
is_separator = 0;
|
|
}
|
|
else
|
|
{
|
|
/* is label-select? */
|
|
if(action->region == CUSTOM_CODE_LABEL_SELECT)
|
|
{
|
|
flags |= kCheatFlag_Select;
|
|
|
|
/* use label-selector? */
|
|
if(TEST_FIELD(action->type, LabelSelectUseSelector))
|
|
flags |= kCheatFlag_UseLabelSelector;
|
|
}
|
|
|
|
/* is comment? */
|
|
if(is_null && action->region != CUSTOM_CODE_COMMENT)
|
|
is_null = 0;
|
|
|
|
/* is separator? */
|
|
if(is_separator && action->region != CUSTOM_CODE_SEPARATOR)
|
|
is_separator = 0;
|
|
|
|
/* is layer index? */
|
|
if(action->region == CUSTOM_CODE_LAYER_TAG)
|
|
flags |= kCheatFlag_LayerIndex;
|
|
|
|
action_flags |= kActionFlag_NoAction;
|
|
action_flags |= kActionFlag_Custom;
|
|
}
|
|
}
|
|
|
|
action->flags = action_flags;
|
|
}
|
|
|
|
if(is_one_shot)
|
|
flags |= kCheatFlag_OneShot;
|
|
|
|
if(is_new_format == 0)
|
|
{
|
|
flags |= kCheatFlag_OldFormat;
|
|
|
|
if(is_null) flags |= kCheatFlag_Null;
|
|
}
|
|
else
|
|
{
|
|
if(is_null)
|
|
{
|
|
/* NOTE : auto detection if multi-comment code */
|
|
if(entry->action_list_length > 1) flags |= kCheatFlag_ExtendComment;
|
|
else flags |= kCheatFlag_Null;
|
|
}
|
|
if(is_separator)
|
|
{
|
|
flags |= kCheatFlag_Null;
|
|
flags |= kCheatFlag_Separator;
|
|
}
|
|
}
|
|
|
|
entry->flags = (flags & kCheatFlag_InfoMask) | (entry->flags & ~kCheatFlag_InfoMask);
|
|
|
|
/* clear dirty flag */
|
|
if(is_load_time)
|
|
entry->flags &= ~kCheatFlag_Dirty;
|
|
|
|
check_code_format(machine, entry);
|
|
|
|
/* build label index table if new format */
|
|
if((entry->flags & kCheatFlag_OldFormat) == 0 && (entry->flags & kCheatFlag_HasWrongCode) == 0 && entry->flags & kCheatFlag_Select)
|
|
build_label_index_table(entry);
|
|
}
|
|
|
|
/*----------------------
|
|
analyse_code_format
|
|
----------------------*/
|
|
|
|
static UINT32 analyse_code_format(running_machine *machine, cheat_entry *entry, cheat_action *action)
|
|
{
|
|
UINT32 errorFlag = 0;
|
|
|
|
/* check type field */
|
|
if(action->flags & kActionFlag_OldFormat)
|
|
{
|
|
UINT8 type = EXTRACT_FIELD(action->type, LocationType);
|
|
UINT8 parameter = EXTRACT_FIELD(action->type, LocationParameter);
|
|
UINT8 operation = EXTRACT_FIELD(action->type, Operation);
|
|
|
|
if(type >= kLocation_Unused5)
|
|
errorFlag |= kErrorFlag_InvalidLocationType;
|
|
|
|
if(type == kLocation_IndirectIndexed)
|
|
{
|
|
if(operation != kOperation_WriteMask && operation != kOperation_SetOrClearBits)
|
|
errorFlag |= kErrorFlag_ConflictedExtendField;
|
|
}
|
|
|
|
if(operation == kOperation_ForceRange)
|
|
{
|
|
if(EXTRACT_FIELD(action->type, MSB16) <= EXTRACT_FIELD(action->type, LSB16))
|
|
errorFlag |= kErrorFlag_InvalidRange;
|
|
}
|
|
|
|
if(type == kLocation_MemoryRegion)
|
|
{
|
|
if(!TEST_FIELD(action->type, RestorePreviousValue))
|
|
errorFlag |= kErrorFlag_NoRestorePreviousValue;
|
|
}
|
|
|
|
if((entry->flags & kCheatFlag_UserSelect) && (entry->flags & kCheatFlag_Select))
|
|
errorFlag |= kErrorFlag_ConflictedSelects;
|
|
|
|
if(TEST_FIELD(action->type, UserSelectEnable))
|
|
{
|
|
if(!action->original_data)
|
|
errorFlag |= kErrorFlag_NoSelectableValue;
|
|
}
|
|
|
|
if(type == kLocation_Custom && parameter == kCustomLocation_Select)
|
|
{
|
|
if(entry->action_list_length == 1)
|
|
errorFlag |= kErrorFlag_NoLabel;
|
|
|
|
if(action->original_data)
|
|
errorFlag |= kErrorFlag_InvalidDataField;
|
|
|
|
if(action->extend_data)
|
|
errorFlag |= kErrorFlag_InvalidExtendDataField;
|
|
}
|
|
|
|
if(operation == kOperation_WriteMask)
|
|
{
|
|
if(type == kLocation_Standard)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < 3; i++)
|
|
{
|
|
if(action->extend_data == 0 || action->extend_data == BYTE_MASK_TABLE[i])
|
|
{
|
|
errorFlag |= kErrorFlag_InvalidExtendDataField;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(type == kLocation_MemoryRegion)
|
|
{
|
|
if(action->extend_data != ~0)
|
|
errorFlag |= kErrorFlag_InvalidExtendDataField;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((action->flags & kActionFlag_Custom) == 0)
|
|
{
|
|
UINT8 codeType = EXTRACT_FIELD(action->type, CodeType);
|
|
UINT8 codeParameter = EXTRACT_FIELD(action->type, CodeParameter);
|
|
|
|
if(codeType >= kCodeType_Unused)
|
|
errorFlag |= kErrorFlag_InvalidCodeType;
|
|
|
|
if(action->flags & kActionFlag_CheckCondition)
|
|
{
|
|
if(codeParameter >= kCondition_Unused1 && codeParameter <= kCondition_Unused4)
|
|
errorFlag |= kErrorFlag_InvalidCondition;
|
|
}
|
|
|
|
if(codeType == kCodeType_PDWWrite)
|
|
{
|
|
if(EXTRACT_FIELD(action->type, AddressRead) == kReadFrom_Variable)
|
|
errorFlag |= kErrorFlag_ForbittenVariable;
|
|
}
|
|
|
|
if(action->region >= REGION_CPU1 || EXTRACT_FIELD(action->type, AddressSpace) == kAddressSpace_OpcodeRAM)
|
|
{
|
|
if(!TEST_FIELD(action->type, RestoreValue))
|
|
errorFlag |= kErrorFlag_NoRestorePreviousValue;
|
|
}
|
|
|
|
if(action->flags & kActionFlag_LimitedMask)
|
|
{
|
|
if(EXTRACT_FIELD(action->type, AddressSize) > kSearchSize_16Bit)
|
|
errorFlag |= kErrorFlag_InvalidLimitedMaskSize;
|
|
}
|
|
|
|
if(action->flags & kActionFlag_Repeat)
|
|
{
|
|
if(EXTRACT_FIELD(action->extend_data, LSB16) < 1)
|
|
errorFlag |= kErrorFlag_NoRepeatCount;
|
|
}
|
|
|
|
if(EXTRACT_FIELD(action->type, AddressRead))
|
|
{
|
|
if(EXTRACT_FIELD(action->type, AddressRead) > kReadFrom_Variable)
|
|
errorFlag |= kErrorFlag_UndefinedAddressRead;
|
|
|
|
if(action->address >= VARIABLE_MAX_ARRAY)
|
|
errorFlag |= kErrorFlag_AddressVariableOutRange;
|
|
}
|
|
|
|
if(TEST_FIELD(action->type, DataRead))
|
|
{
|
|
if(action->data >= VARIABLE_MAX_ARRAY)
|
|
errorFlag |= kErrorFlag_DataVariableOutRange;
|
|
}
|
|
|
|
if(codeType == kCodeType_Write)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < 3; i++)
|
|
{
|
|
if(action->extend_data == 0 || action->extend_data == BYTE_MASK_TABLE[i])
|
|
{
|
|
errorFlag |= kErrorFlag_InvalidExtendDataField;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if((action->flags & kActionFlag_Custom) == 0)
|
|
{
|
|
if(action->region < REGION_INVALID)
|
|
{
|
|
UINT8 cpu = EXTRACT_FIELD(action->region, CPUIndex);
|
|
|
|
if(VALID_CPU(cpu) == 0)
|
|
errorFlag |= kErrorFlag_OutOfCPURegion;
|
|
else if(cpu_info_list[cpu].type == 0)
|
|
errorFlag |= kErrorFlag_InvalidCPURegion;
|
|
|
|
if(EXTRACT_FIELD(action->type, AddressSpace) > kAddressSpace_EEPROM)
|
|
errorFlag |= kErrorFlag_InvalidAddressSpace;
|
|
}
|
|
else
|
|
{
|
|
UINT8 region = action->region - REGION_INVALID;
|
|
|
|
if(region >= REGION_MAX) errorFlag |= kErrorFlag_OutOfCPURegion;
|
|
else if(!region_info_list[region].type) errorFlag |= kErrorFlag_InvalidCPURegion;
|
|
else if(!is_address_in_range(action, memory_region_length(machine, action->region)))
|
|
errorFlag |= kErrorFlag_RegionOutOfRange;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(action->region >= CUSTOM_CODE_UNUSED_1)
|
|
errorFlag |= kErrorFlag_InvalidCustomCode;
|
|
}
|
|
}
|
|
|
|
return errorFlag;
|
|
}
|
|
|
|
/*------------------------------------------
|
|
check_code_format - code format checker
|
|
------------------------------------------*/
|
|
|
|
static void check_code_format(running_machine *machine, cheat_entry *entry)
|
|
{
|
|
int i;
|
|
UINT8 is_error = 0;
|
|
|
|
for(i = 0; i < entry->action_list_length; i++)
|
|
{
|
|
cheat_action *action = &entry->action_list[i];
|
|
|
|
if(analyse_code_format(machine, entry, action))
|
|
is_error = 1;
|
|
}
|
|
|
|
if(is_error)
|
|
{
|
|
entry->flags |= kCheatFlag_HasWrongCode;
|
|
SET_MESSAGE(CHEAT_MESSAGE_WRONG_CODE);
|
|
}
|
|
}
|
|
|
|
/*------------------
|
|
set_layer_index
|
|
------------------*/
|
|
|
|
static void set_layer_index(void)
|
|
{
|
|
int i, j;
|
|
|
|
for(i = 0; i < cheat_list_length; i++)
|
|
{
|
|
cheat_entry *entry = &cheat_list[i];
|
|
|
|
if(entry->flags & kCheatFlag_LayerIndex)
|
|
{
|
|
int length = entry->action_list[0].extend_data;
|
|
|
|
if(length < cheat_list_length && (i + length) <= cheat_list_length)
|
|
{
|
|
entry->layer_index = entry->action_list[0].address;
|
|
|
|
for(j = i + 1; j <= i + length; j++)
|
|
{
|
|
cheat_entry *traverse = &cheat_list[j];
|
|
|
|
if((traverse->flags & kCheatFlag_LayerIndex) == 0)
|
|
traverse->layer_index = entry->action_list[0].data;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
reset_cheat_options - reset cheat options as default and key repeat speed
|
|
----------------------------------------------------------------------------*/
|
|
|
|
static void reset_cheat_options(void)
|
|
{
|
|
cheat_options = DEFAULT_CHEAT_OPTIONS;
|
|
vertical_key_repeat_speed = EXTRACT_FIELD(cheat_options, VerticalKeyRepeatSpeed);
|
|
horizontal_key_repeat_speed = EXTRACT_FIELD(cheat_options, HorizontalKeyRepeatSpeed);
|
|
|
|
SET_MESSAGE(CHEAT_MESSAGE_RESET_OPTIONS);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------------------------
|
|
display_cheat_message - display cheat message via ui_draw_text_box instead of popup menu
|
|
-------------------------------------------------------------------------------------------*/
|
|
|
|
static void display_cheat_message(void)
|
|
{
|
|
char buf[64];
|
|
|
|
switch(message_type)
|
|
{
|
|
/* simple message */
|
|
default:
|
|
sprintf(buf, "%s", CHEAT_MESSAGE_TABLE[message_type]);
|
|
break;
|
|
|
|
/* message with data */
|
|
case CHEAT_MESSAGE_CHEAT_FOUND:
|
|
case CHEAT_MESSAGE_INVALIDATE_REGION:
|
|
{
|
|
search_info *search = get_current_search();
|
|
|
|
sprintf(buf, "%d %s", search->num_results, CHEAT_MESSAGE_TABLE[message_type]);
|
|
}
|
|
break;
|
|
|
|
case CHEAT_MESSAGE_ALL_CHEATS_SAVED:
|
|
sprintf(buf, "%d %s", cheat_list_length, CHEAT_MESSAGE_TABLE[message_type]);
|
|
break;
|
|
}
|
|
|
|
/* draw it */
|
|
switch(message_type)
|
|
{
|
|
default:
|
|
ui_draw_text_box(buf, JUSTIFY_CENTER, 0.5f, 0.9f, UI_FILLCOLOR);
|
|
break;
|
|
|
|
case CHEAT_MESSAGE_NONE:
|
|
case CHEAT_MESSAGE_FAILED_TO_LOAD_DATABASE:
|
|
case CHEAT_MESSAGE_FAILED_TO_SAVE:
|
|
case CHEAT_MESSAGE_NO_SUPPORTED_OLD_FORMAT:
|
|
case CHEAT_MESSAGE_NO_ACTIVATION_KEY:
|
|
case CHEAT_MESSAGE_FAILED_TO_ADD:
|
|
case CHEAT_MESSAGE_FAILED_TO_DELETE:
|
|
case CHEAT_MESSAGE_NO_SEARCH_REGION:
|
|
case CHEAT_MESSAGE_NO_OLD_VALUE:
|
|
case CHEAT_MESSAGE_FAILED_TO_ALLOCATE:
|
|
case CHEAT_MESSAGE_WRONG_CODE:
|
|
case CHEAT_MESSAGE_MAX:
|
|
/* warning message has red background color */
|
|
ui_draw_text_box(buf, JUSTIFY_CENTER, 0.5f, 0.9f, UI_REDCOLOR);
|
|
break;
|
|
}
|
|
|
|
/* decrement message timer */
|
|
if(--message_timer == 0)
|
|
message_type = 0;
|
|
}
|
|
|
|
/*---------------------
|
|
get_address_length
|
|
---------------------*/
|
|
|
|
static UINT8 get_address_length(UINT8 region)
|
|
{
|
|
if(region < CUSTOM_CODE)
|
|
{
|
|
cpu_region_info *info = get_cpu_or_region_info(region);
|
|
|
|
if(info && info->type)
|
|
return info->address_chars_needed;
|
|
}
|
|
|
|
return cpu_info_list[0].address_chars_needed;
|
|
}
|
|
|
|
/*------------------
|
|
get_region_name
|
|
------------------*/
|
|
|
|
static char *get_region_name(UINT8 region)
|
|
{
|
|
if(region < REGION_INVALID)
|
|
{
|
|
if(VALID_CPU(region))
|
|
return (char *)kRegionNames[EXTRACT_FIELD(region, CPUIndex) + 1];
|
|
}
|
|
else
|
|
{
|
|
if(region < REGION_MAX)
|
|
return (char *)kRegionNames[region - REGION_INVALID];
|
|
}
|
|
|
|
return (char *)kRegionNames[0];
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
build_cpu_region_info_list - get CPU and region info when initialize cheat system
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
static void build_cpu_region_info_list(running_machine *machine)
|
|
{
|
|
int i;
|
|
|
|
/* do regions */
|
|
{
|
|
const rom_entry *traverse = rom_first_region(machine->gamedrv);
|
|
|
|
memset(region_info_list, 0, sizeof(cpu_region_info) * REGION_LIST_LENGTH);
|
|
|
|
while(traverse)
|
|
{
|
|
if(ROMENTRY_ISREGION(traverse))
|
|
{
|
|
UINT8 region_type = ROMREGION_GETTYPE(traverse);
|
|
|
|
/* non-cpu region */
|
|
if(region_type >= REGION_GFX1 && region_type <= REGION_PLDS)
|
|
{
|
|
UINT8 bit_state = 0;
|
|
UINT32 length = memory_region_length(machine, region_type);
|
|
cpu_region_info *info = ®ion_info_list[region_type - REGION_INVALID];
|
|
|
|
info->type = region_type;
|
|
info->data_bits = ROMREGION_GETWIDTH(traverse);
|
|
info->address_bits = 0;
|
|
info->address_mask = length;
|
|
info->address_chars_needed = info->address_bits >> 2;
|
|
info->endianness = ROMREGION_ISBIGENDIAN(traverse);
|
|
|
|
if(info->address_bits & 3)
|
|
info->address_chars_needed++;
|
|
|
|
/* build address mask */
|
|
for(i = 0; i < 32; i++)
|
|
{
|
|
UINT32 mask = 1 << (31 - i);
|
|
|
|
if(bit_state)
|
|
info->address_mask |= mask;
|
|
else
|
|
{
|
|
if(info->address_mask & mask)
|
|
{
|
|
info->address_bits = 32 - i;
|
|
bit_state = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
traverse = rom_next_region(traverse);
|
|
}
|
|
}
|
|
|
|
/* do CPUs */
|
|
{
|
|
memset(cpu_info_list, 0, sizeof(cpu_region_info) * MAX_CPU);
|
|
|
|
for(i = 0; i < cpu_gettotalcpu(); i++)
|
|
{
|
|
cpu_region_info *cpu_info = &cpu_info_list[i];
|
|
cpu_region_info *region_info = ®ion_info_list[REGION_CPU1 + i - REGION_INVALID];
|
|
cpu_type type = machine->config->cpu[i].type;
|
|
|
|
cpu_info->type = type;
|
|
cpu_info->data_bits = cputype_databus_width(type, ADDRESS_SPACE_PROGRAM);
|
|
cpu_info->address_bits = cputype_addrbus_width(type, ADDRESS_SPACE_PROGRAM);
|
|
cpu_info->address_mask = 0xFFFFFFFF >> (32 - cpu_info->address_bits);
|
|
cpu_info->address_chars_needed = cpu_info->address_bits >> 2;
|
|
cpu_info->endianness = (cputype_endianness(type) == CPU_IS_BE);
|
|
cpu_info->address_shift = cputype_addrbus_shift(type, ADDRESS_SPACE_PROGRAM);
|
|
|
|
if(cpu_info->address_bits & 0x3)
|
|
cpu_info->address_chars_needed++;
|
|
|
|
/* copy CPU info to region info */
|
|
memcpy(region_info, cpu_info, sizeof(cpu_region_info));
|
|
}
|
|
}
|
|
}
|