update to rcheevos 11.3 (#16512)

This commit is contained in:
Jamiras 2024-05-11 17:57:36 -06:00 committed by GitHub
parent 76b5d40954
commit 2013370aa9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 279 additions and 52 deletions

View File

@ -339,8 +339,7 @@ static rcheevos_racheevo_t* rcheevos_find_cheevo(unsigned id)
static bool rcheevos_is_game_loaded(void)
{
#ifdef HAVE_RC_CLIENT
const rc_client_game_t* game = rc_client_get_game_info(rcheevos_locals.client);
return (game && game->id);
return rc_client_is_game_loaded(rcheevos_locals.client);
#else
return rcheevos_locals.loaded;
#endif
@ -1189,7 +1188,13 @@ void rcheevos_refresh_memory(void)
bool rcheevos_hardcore_active(void)
{
#ifdef HAVE_RC_CLIENT
return rcheevos_locals.client && rc_client_get_hardcore_enabled(rcheevos_locals.client);
/* normal hardcore check */
if (rcheevos_locals.client && rc_client_get_hardcore_enabled(rcheevos_locals.client))
return true;
/* if we're trying to enable hardcore, pretend it's on so the caller can decide to disable
* it (by calling rcheevos_pause_hardcore) before we actually turn it on. */
return rcheevos_locals.hardcore_allowed;
#else
return rcheevos_locals.hardcore_active;
#endif

View File

@ -251,6 +251,11 @@ enum {
RC_CLIENT_LOAD_GAME_STATE_ABORTED
};
/**
* Determines if a game was successfully identified and loaded.
*/
RC_EXPORT int RC_CCONV rc_client_is_game_loaded(const rc_client_t* client);
/**
* Unloads the current game.
*/
@ -266,6 +271,7 @@ typedef struct rc_client_game_t {
/**
* Get information about the current game. Returns NULL if no game is loaded.
* NOTE: returns a dummy game record if an unidentified game is loaded.
*/
RC_EXPORT const rc_client_game_t* RC_CCONV rc_client_get_game_info(const rc_client_t* client);

View File

@ -27,6 +27,14 @@ typedef struct rc_client_raintegration_menu_t {
uint32_t num_items;
} rc_client_raintegration_menu_t;
enum {
RC_CLIENT_RAINTEGRATION_ACHIEVEMENT_STATE_NONE = 0,
RC_CLIENT_RAINTEGRATION_ACHIEVEMENT_STATE_PUBLISHED = 1,
RC_CLIENT_RAINTEGRATION_ACHIEVEMENT_STATE_LOCAL = 2,
RC_CLIENT_RAINTEGRATION_ACHIEVEMENT_STATE_MODIFIED = 3,
RC_CLIENT_RAINTEGRATION_ACHIEVEMENT_STATE_INSECURE = 4,
};
enum {
RC_CLIENT_RAINTEGRATION_EVENT_TYPE_NONE = 0,
RC_CLIENT_RAINTEGRATION_EVENT_MENUITEM_CHECKED_CHANGED = 1, /* [menu_item] checked changed */
@ -77,11 +85,14 @@ RC_EXPORT int RC_CCONV rc_client_raintegration_activate_menu_item(const rc_clien
RC_EXPORT void RC_CCONV rc_client_raintegration_set_write_memory_function(rc_client_t* client, rc_client_raintegration_write_memory_func_t handler);
RC_EXPORT void RC_CCONV rc_client_raintegration_set_get_game_name_function(rc_client_t* client, rc_client_raintegration_get_game_name_func_t handler);
RC_EXPORT void RC_CCONV rc_client_raintegration_set_console_id(rc_client_t* client, uint32_t console_id);
RC_EXPORT int RC_CCONV rc_client_raintegration_has_modifications(const rc_client_t* client);
RC_EXPORT void RC_CCONV rc_client_raintegration_set_event_handler(rc_client_t* client,
rc_client_raintegration_event_handler_t handler);
RC_EXPORT int RC_CCONV rc_client_raintegration_get_achievement_state(const rc_client_t* client, uint32_t achievement_id);
#endif /* RC_CLIENT_SUPPORTS_RAINTEGRATION */
RC_END_C_DECLS

View File

@ -175,7 +175,8 @@ enum {
RC_OPERATOR_MULT,
RC_OPERATOR_DIV,
RC_OPERATOR_AND,
RC_OPERATOR_XOR
RC_OPERATOR_XOR,
RC_OPERATOR_MOD
};
typedef struct rc_condition_t rc_condition_t;

View File

@ -1947,13 +1947,13 @@ static void rc_client_fetch_game_data_callback(const rc_api_server_response_t* s
if (!subset->public_.title) {
const char* core_subset_title = rc_client_subset_extract_title(load_state->game, load_state->game->public_.title);
if (core_subset_title) {
rc_client_subset_info_t* scan = load_state->game->subsets;
for (; scan; scan = scan->next) {
if (scan->public_.title == load_state->game->public_.title) {
scan->public_.title = core_subset_title;
break;
}
}
scan = load_state->game->subsets;
for (; scan; scan = scan->next) {
if (scan->public_.title == load_state->game->public_.title) {
scan->public_.title = core_subset_title;
break;
}
}
}
subset->public_.title = rc_buffer_strcpy(&load_state->game->buffer, fetch_game_data_response.title);
@ -2058,8 +2058,15 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state)
#endif /* RC_CLIENT_SUPPORTS_HASH */
if (load_state->hash->game_id == 0) {
rc_client_subset_info_t* subset;
subset = (rc_client_subset_info_t*)rc_buffer_alloc(&load_state->game->buffer, sizeof(rc_client_subset_info_t));
memset(subset, 0, sizeof(*subset));
subset->public_.title = "";
load_state->game->public_.title = "Unknown Game";
load_state->game->public_.badge_name = "";
load_state->game->subsets = subset;
client->game = load_state->game;
load_state->game = NULL;
@ -2405,6 +2412,23 @@ int rc_client_get_load_game_state(const rc_client_t* client)
return state;
}
int rc_client_is_game_loaded(const rc_client_t* client)
{
const rc_client_game_t* game;
if (!client)
return 0;
#ifdef RC_CLIENT_SUPPORTS_EXTERNAL
if (client->state.external_client && client->state.external_client->get_game_info)
game = client->state.external_client->get_game_info();
else
#endif
game = client->game ? &client->game->public_ : NULL;
return (game && game->id != 0);
}
static void rc_client_game_mark_ui_to_be_hidden(rc_client_t* client, rc_client_game_info_t* game)
{
rc_client_achievement_info_t* achievement;

View File

@ -69,6 +69,7 @@ static void rc_client_raintegration_load_dll(rc_client_t* client,
raintegration->get_host_url = (rc_client_raintegration_get_string_func_t)GetProcAddress(hDLL, "_RA_HostUrl");
raintegration->init_client = (rc_client_raintegration_init_client_func_t)GetProcAddress(hDLL, "_RA_InitClient");
raintegration->init_client_offline = (rc_client_raintegration_init_client_func_t)GetProcAddress(hDLL, "_RA_InitOffline");
raintegration->set_console_id = (rc_client_raintegration_set_int_func_t)GetProcAddress(hDLL, "_RA_SetConsoleID");
raintegration->shutdown = (rc_client_raintegration_action_func_t)GetProcAddress(hDLL, "_RA_Shutdown");
raintegration->update_main_window_handle = (rc_client_raintegration_hwnd_action_func_t)GetProcAddress(hDLL, "_RA_UpdateHWnd");
@ -80,6 +81,7 @@ static void rc_client_raintegration_load_dll(rc_client_t* client,
raintegration->set_get_game_name_function = (rc_client_raintegration_set_get_game_name_func_t)GetProcAddress(hDLL, "_Rcheevos_SetRAIntegrationGetGameNameFunction");
raintegration->set_event_handler = (rc_client_raintegration_set_event_handler_func_t)GetProcAddress(hDLL, "_Rcheevos_SetRAIntegrationEventHandler");
raintegration->has_modifications = (rc_client_raintegration_get_int_func_t)GetProcAddress(hDLL, "_Rcheevos_HasModifications");
raintegration->get_achievement_state = (rc_client_raintegration_get_achievement_state_func_t)GetProcAddress(hDLL, "_Rcheevos_GetAchievementState");
if (!raintegration->get_version ||
!raintegration->init_client ||
@ -204,6 +206,7 @@ static void rc_client_init_raintegration(rc_client_t* client,
/* attach the external client and call the callback */
client->state.external_client = external_client;
client->state.raintegration->hMainWindow = version_validation_callback_data->main_window_handle;
client->state.raintegration->bIsInited = 1;
version_validation_callback_data->callback(RC_OK, NULL,
@ -352,12 +355,14 @@ rc_client_async_handle_t* rc_client_begin_load_raintegration(rc_client_t* client
void rc_client_raintegration_update_main_window_handle(rc_client_t* client, HWND main_window_handle)
{
if (client && client->state.raintegration &&
client->state.raintegration->bIsInited &&
client->state.raintegration->update_main_window_handle)
{
if (client && client->state.raintegration) {
client->state.raintegration->hMainWindow = main_window_handle;
if (client->state.raintegration->bIsInited &&
client->state.raintegration->update_main_window_handle) {
client->state.raintegration->update_main_window_handle(main_window_handle);
}
}
}
}
void rc_client_raintegration_set_write_memory_function(rc_client_t* client, rc_client_raintegration_write_memory_func_t handler)
@ -383,26 +388,41 @@ const rc_client_raintegration_menu_t* rc_client_raintegration_get_menu(const rc_
{
if (!client || !client->state.raintegration ||
!client->state.raintegration->bIsInited ||
!client->state.raintegration->get_menu)
{
!client->state.raintegration->get_menu) {
return NULL;
}
return client->state.raintegration->get_menu();
}
void rc_client_raintegration_set_console_id(rc_client_t* client, uint32_t console_id)
{
if (client && client->state.raintegration && client->state.raintegration->set_console_id)
client->state.raintegration->set_console_id(console_id);
}
int rc_client_raintegration_has_modifications(const rc_client_t* client)
{
if (!client || !client->state.raintegration ||
!client->state.raintegration->bIsInited ||
!client->state.raintegration->has_modifications)
{
!client->state.raintegration->bIsInited ||
!client->state.raintegration->has_modifications) {
return 0;
}
return client->state.raintegration->has_modifications();
}
int rc_client_raintegration_get_achievement_state(const rc_client_t* client, uint32_t achievement_id)
{
if (!client || !client->state.raintegration ||
!client->state.raintegration->bIsInited ||
!client->state.raintegration->get_achievement_state) {
return RC_CLIENT_RAINTEGRATION_ACHIEVEMENT_STATE_NONE;
}
return client->state.raintegration->get_achievement_state(achievement_id);
}
void rc_client_raintegration_rebuild_submenu(rc_client_t* client, HMENU hMenu)
{
HMENU hPopupMenu = NULL;
@ -464,6 +484,9 @@ void rc_client_raintegration_rebuild_submenu(rc_client_t* client, HMENU hMenu)
AppendMenuA(hMenu, flags, (UINT_PTR)hPopupMenu, menuText);
else
ModifyMenuA(hMenu, nIndex, flags | MF_BYPOSITION, (UINT_PTR)hPopupMenu, menuText);
if (client->state.raintegration->hMainWindow && GetMenu(client->state.raintegration->hMainWindow) == hMenu)
DrawMenuBar(client->state.raintegration->hMainWindow);
}
client->state.raintegration->hPopupMenu = hPopupMenu;

View File

@ -17,16 +17,19 @@ typedef const char* (RC_CCONV* rc_client_raintegration_get_string_func_t)(void);
typedef int (RC_CCONV* rc_client_raintegration_init_client_func_t)(HWND hMainWnd, const char* sClientName, const char* sClientVersion);
typedef int (RC_CCONV* rc_client_raintegration_get_external_client_func_t)(rc_client_external_t* pClient, int nVersion);
typedef void (RC_CCONV* rc_client_raintegration_hwnd_action_func_t)(HWND hWnd);
typedef int (RC_CCONV* rc_client_raintegration_get_achievement_state_func_t)(uint32_t nMenuItemId);
typedef const rc_client_raintegration_menu_t* (RC_CCONV* rc_client_raintegration_get_menu_func_t)(void);
typedef int (RC_CCONV* rc_client_raintegration_activate_menuitem_func_t)(uint32_t nMenuItemId);
typedef void (RC_CCONV* rc_client_raintegration_set_write_memory_func_t)(rc_client_t* pClient, rc_client_raintegration_write_memory_func_t handler);
typedef void (RC_CCONV* rc_client_raintegration_set_get_game_name_func_t)(rc_client_t* pClient, rc_client_raintegration_get_game_name_func_t handler);
typedef void (RC_CCONV* rc_client_raintegration_set_event_handler_func_t)(rc_client_t* pClient, rc_client_raintegration_event_handler_t handler);
typedef void (RC_CCONV* rc_client_raintegration_set_int_func_t)(int);
typedef int (RC_CCONV* rc_client_raintegration_get_int_func_t)(void);
typedef struct rc_client_raintegration_t
{
HINSTANCE hDLL;
HWND hMainWindow;
HMENU hPopupMenu;
uint8_t bIsInited;
@ -34,6 +37,7 @@ typedef struct rc_client_raintegration_t
rc_client_raintegration_get_string_func_t get_host_url;
rc_client_raintegration_init_client_func_t init_client;
rc_client_raintegration_init_client_func_t init_client_offline;
rc_client_raintegration_set_int_func_t set_console_id;
rc_client_raintegration_action_func_t shutdown;
rc_client_raintegration_hwnd_action_func_t update_main_window_handle;
@ -44,6 +48,7 @@ typedef struct rc_client_raintegration_t
rc_client_raintegration_get_menu_func_t get_menu;
rc_client_raintegration_activate_menuitem_func_t activate_menu_item;
rc_client_raintegration_get_int_func_t has_modifications;
rc_client_raintegration_get_achievement_state_func_t get_achievement_state;
rc_client_raintegration_get_external_client_func_t get_external_client;

View File

@ -139,6 +139,10 @@ static int rc_parse_operator(const char** memaddr) {
++(*memaddr);
return RC_OPERATOR_XOR;
case '%':
++(*memaddr);
return RC_OPERATOR_MOD;
case '\0':/* end of string */
case '_': /* next condition */
case 'S': /* next condset */
@ -226,6 +230,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
case RC_OPERATOR_DIV:
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_MOD:
/* modifying operators are only valid on modifying statements */
if (can_modify)
break;
@ -551,5 +556,9 @@ void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self,
rc_typed_value_convert(&amount, RC_VALUE_TYPE_UNSIGNED);
value->value.u32 ^= amount.value.u32;
break;
case RC_OPERATOR_MOD:
rc_typed_value_modulus(value, &amount);
break;
}
}

View File

@ -87,6 +87,7 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
case RC_OPERATOR_XOR:
case RC_OPERATOR_DIV:
case RC_OPERATOR_MULT:
case RC_OPERATOR_MOD:
case RC_OPERATOR_NONE:
/* measuring value. leave required_hits at 0 */
break;

View File

@ -418,7 +418,7 @@ static const rc_memory_region_t _rc_memory_regions_fairchild_channel_f[] = {
};
static const rc_memory_regions_t rc_memory_regions_fairchild_channel_f = { _rc_memory_regions_fairchild_channel_f, 4 };
/* ===== GameBoy / GameBoy Color ===== */
/* ===== GameBoy / MegaDuck ===== */
static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt vector" },
{ 0x000100U, 0x00014FU, 0x000100U, RC_MEMORY_TYPE_READONLY, "Cartridge header" },
@ -427,8 +427,37 @@ static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
{ 0x008000U, 0x0097FFU, 0x008000U, RC_MEMORY_TYPE_VIDEO_RAM, "Tile RAM" },
{ 0x009800U, 0x009BFFU, 0x009800U, RC_MEMORY_TYPE_VIDEO_RAM, "BG1 map data" },
{ 0x009C00U, 0x009FFFU, 0x009C00U, RC_MEMORY_TYPE_VIDEO_RAM, "BG2 map data" },
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM"},
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM (bank 0)"},
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (fixed)" },
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (fixed)" },
{ 0x00E000U, 0x00FDFFU, 0x00C000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Echo RAM" },
{ 0x00FE00U, 0x00FE9FU, 0x00FE00U, RC_MEMORY_TYPE_VIDEO_RAM, "Sprite RAM"},
{ 0x00FEA0U, 0x00FEFFU, 0x00FEA0U, RC_MEMORY_TYPE_UNUSED, ""},
{ 0x00FF00U, 0x00FF7FU, 0x00FF00U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Hardware I/O"},
{ 0x00FF80U, 0x00FFFEU, 0x00FF80U, RC_MEMORY_TYPE_SYSTEM_RAM, "Quick RAM"},
{ 0x00FFFFU, 0x00FFFFU, 0x00FFFFU, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt enable"},
/* GameBoy's cartridge RAM may have a total of up to 16 banks that can be paged through $A000-$BFFF.
* It is desirable to always have access to these extra banks. We do this by expecting the extra banks
* to be addressable at addresses not supported by the native system. 0x10000-0x16000 is reserved
* for the extra banks of system memory that are exclusive to the GameBoy Color. */
{ 0x010000U, 0x015FFFU, 0x010000U, RC_MEMORY_TYPE_UNUSED, "Unused (GameBoy Color exclusive)" },
{ 0x016000U, 0x033FFFU, 0x016000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM (banks 1-15)" },
};
static const rc_memory_regions_t rc_memory_regions_megaduck = { _rc_memory_regions_gameboy, 16 };
static const rc_memory_regions_t rc_memory_regions_gameboy = { _rc_memory_regions_gameboy, 18 };
/* ===== GameBoy Color ===== */
static const rc_memory_region_t _rc_memory_regions_gameboy_color[] = {
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt vector" },
{ 0x000100U, 0x00014FU, 0x000100U, RC_MEMORY_TYPE_READONLY, "Cartridge header" },
{ 0x000150U, 0x003FFFU, 0x000150U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM (fixed)" }, /* bank 0 */
{ 0x004000U, 0x007FFFU, 0x004000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM (paged)" }, /* bank 1-XX (switchable) */
{ 0x008000U, 0x0097FFU, 0x008000U, RC_MEMORY_TYPE_VIDEO_RAM, "Tile RAM" },
{ 0x009800U, 0x009BFFU, 0x009800U, RC_MEMORY_TYPE_VIDEO_RAM, "BG1 map data" },
{ 0x009C00U, 0x009FFFU, 0x009C00U, RC_MEMORY_TYPE_VIDEO_RAM, "BG2 map data" },
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM (bank 0)"},
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (bank 0)" },
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (bank 1)" },
{ 0x00E000U, 0x00FDFFU, 0x00C000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Echo RAM" },
{ 0x00FE00U, 0x00FE9FU, 0x00FE00U, RC_MEMORY_TYPE_VIDEO_RAM, "Sprite RAM"},
@ -437,14 +466,14 @@ static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
{ 0x00FF80U, 0x00FFFEU, 0x00FF80U, RC_MEMORY_TYPE_SYSTEM_RAM, "Quick RAM"},
{ 0x00FFFFU, 0x00FFFFU, 0x00FFFFU, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt enable"},
/* GameBoy Color provides six extra banks of memory that can be paged out through the $DXXX
* memory space, but the timing of that does not correspond with blanks, which is when achievements
* are processed. As such, it is desirable to always have access to these extra banks. We do this
* by expecting the extra banks to be addressable at addresses not supported by the native system. */
{ 0x010000U, 0x015FFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (banks 2-7, GBC only)" }
/* GameBoy Color provides 6 extra banks of system memory that can be paged out through the $D000-$DFFF,
* and the cartridge RAM may have a total of up to 16 banks page through $A000-$BFFF.
* It is desirable to always have access to these extra banks. We do this by expecting the extra banks
* to be addressable at addresses not supported by the native system. */
{ 0x010000U, 0x015FFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (banks 2-7)" },
{ 0x016000U, 0x033FFFU, 0x016000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM (banks 1-15)" },
};
static const rc_memory_regions_t rc_memory_regions_gameboy = { _rc_memory_regions_gameboy, 16 };
static const rc_memory_regions_t rc_memory_regions_gameboy_color = { _rc_memory_regions_gameboy, 17 };
static const rc_memory_regions_t rc_memory_regions_gameboy_color = { _rc_memory_regions_gameboy_color, 18 };
/* ===== GameBoy Advance ===== */
/* http://problemkaputt.de/gbatek-gba-memory-map.htm */
@ -463,11 +492,19 @@ static const rc_memory_region_t _rc_memory_regions_gamecube[] = {
static const rc_memory_regions_t rc_memory_regions_gamecube = { _rc_memory_regions_gamecube, 1 };
/* ===== Game Gear ===== */
/* http://www.smspower.org/Development/MemoryMap */
/* https://www.smspower.org/Development/MemoryMap */
/* https://www.smspower.org/Development/Mappers */
static const rc_memory_region_t _rc_memory_regions_game_gear[] = {
{ 0x000000U, 0x001FFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
{ 0x000000U, 0x001FFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
/* GG/SMS have various possible mappings for cartridge memory depending on the mapper used.
* However, these ultimately do not map all of their memory at once, typically requiring banking.
* Thus, the "real address" used is just a virtual address mapping all cartridge memory in one contiguous block.
* Note that this may possibly refer to non-battery backed "extended RAM" so this isn't strictly RC_MEMORY_TYPE_SAVE_RAM.
* libretro cores expose "extended RAM" as RETRO_MEMORY_SAVE_RAM regardless however.
*/
{ 0x002000U, 0x009FFFU, 0x010000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
};
static const rc_memory_regions_t rc_memory_regions_game_gear = { _rc_memory_regions_game_gear, 1 };
static const rc_memory_regions_t rc_memory_regions_game_gear = { _rc_memory_regions_game_gear, 2 };
/* ===== Intellivision ===== */
/* http://wiki.intellivision.us/index.php/Memory_Map */
@ -531,14 +568,22 @@ static const rc_memory_region_t _rc_memory_regions_magnavox_odyssey_2[] = {
static const rc_memory_regions_t rc_memory_regions_magnavox_odyssey_2 = { _rc_memory_regions_magnavox_odyssey_2, 2 };
/* ===== Master System ===== */
/* http://www.smspower.org/Development/MemoryMap */
/* https://www.smspower.org/Development/MemoryMap */
/* https://www.smspower.org/Development/Mappers */
static const rc_memory_region_t _rc_memory_regions_master_system[] = {
{ 0x000000U, 0x001FFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
{ 0x000000U, 0x001FFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
/* GG/SMS have various possible mappings for cartridge memory depending on the mapper used.
* However, these ultimately do not map all of their memory at once, typically requiring banking.
* Thus, the "real address" used is just a virtual address mapping all cartridge memory in one contiguous block.
* Note that this may possibly refer to non-battery backed "extended RAM" so this isn't strictly RC_MEMORY_TYPE_SAVE_RAM.
* libretro cores expose "extended RAM" as RETRO_MEMORY_SAVE_RAM regardless however.
*/
{ 0x002000U, 0x009FFFU, 0x010000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
};
static const rc_memory_regions_t rc_memory_regions_master_system = { _rc_memory_regions_master_system, 1 };
static const rc_memory_regions_t rc_memory_regions_master_system = { _rc_memory_regions_master_system, 2 };
/* ===== MegaDrive (Genesis) ===== */
/* http://www.smspower.org/Development/MemoryMap */
/* https://www.smspower.org/Development/MemoryMap */
static const rc_memory_region_t _rc_memory_regions_megadrive[] = {
{ 0x000000U, 0x00FFFFU, 0xFF0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x010000U, 0x01FFFFU, 0x000000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
@ -772,7 +817,7 @@ static const rc_memory_region_t _rc_memory_regions_saturn[] = {
static const rc_memory_regions_t rc_memory_regions_saturn = { _rc_memory_regions_saturn, 2 };
/* ===== SG-1000 ===== */
/* http://www.smspower.org/Development/MemoryMap */
/* https://www.smspower.org/Development/MemoryMap */
static const rc_memory_region_t _rc_memory_regions_sg1000[] = {
{ 0x000000U, 0x0003FFU, 0xC000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
/* https://github.com/libretro/FBNeo/blob/697801c6262be6ca91615cf905444d3e039bc06f/src/burn/drv/sg1000/d_sg1000.cpp#L210-L237 */
@ -957,8 +1002,7 @@ const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id)
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
return &rc_memory_regions_fairchild_channel_f;
case RC_CONSOLE_MEGADUCK:
case RC_CONSOLE_GAMEBOY:
return &rc_memory_regions_gameboy;
@ -989,6 +1033,9 @@ const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id)
case RC_CONSOLE_MEGA_DRIVE:
return &rc_memory_regions_megadrive;
case RC_CONSOLE_MEGADUCK:
return &rc_memory_regions_megaduck;
case RC_CONSOLE_SEGA_32X:
return &rc_memory_regions_megadrive_32x;

View File

@ -181,6 +181,7 @@ void rc_typed_value_convert(rc_typed_value_t* value, char new_type);
void rc_typed_value_add(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_multiply(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_divide(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amount);
void rc_typed_value_negate(rc_typed_value_t* value);
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper);
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref);

View File

@ -3,6 +3,7 @@
#include <string.h> /* memset */
#include <ctype.h> /* isdigit */
#include <float.h> /* FLT_EPSILON */
#include <math.h> /* fmod */
static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
rc_condset_t** next_clause;
@ -112,6 +113,7 @@ void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_stat
case RC_OPERATOR_DIV:
case RC_OPERATOR_AND:
case RC_OPERATOR_XOR:
case RC_OPERATOR_MOD:
case RC_OPERATOR_NONE:
break;
@ -628,6 +630,72 @@ void rc_typed_value_divide(rc_typed_value_t* value, const rc_typed_value_t* amou
value->value.f32 /= amount->value.f32;
}
void rc_typed_value_modulus(rc_typed_value_t* value, const rc_typed_value_t* amount) {
rc_typed_value_t converted;
switch (amount->type)
{
case RC_VALUE_TYPE_UNSIGNED:
if (amount->value.u32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= amount->value.u32;
return;
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= (int)amount->value.u32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_SIGNED:
if (amount->value.i32 == 0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
switch (value->type) {
case RC_VALUE_TYPE_SIGNED: /* integer math */
value->value.i32 %= amount->value.i32;
return;
case RC_VALUE_TYPE_UNSIGNED: /* integer math */
value->value.u32 %= (unsigned)amount->value.i32;
return;
case RC_VALUE_TYPE_FLOAT:
amount = rc_typed_value_convert_into(&converted, amount, RC_VALUE_TYPE_FLOAT);
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
break;
case RC_VALUE_TYPE_FLOAT:
break;
default:
value->type = RC_VALUE_TYPE_NONE;
return;
}
if (amount->value.f32 == 0.0) { /* divide by zero */
value->type = RC_VALUE_TYPE_NONE;
return;
}
rc_typed_value_convert(value, RC_VALUE_TYPE_FLOAT);
value->value.f32 = (float)fmod(value->value.f32, amount->value.f32);
}
static int rc_typed_value_compare_floats(float f1, float f2, char oper) {
if (f1 == f2) {
/* exactly equal */

View File

@ -11,6 +11,7 @@
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <share.h>
#endif
/* arbitrary limit to prevent allocating and hashing large files */
@ -53,9 +54,9 @@ static void rc_hash_verbose(const char* message)
static struct rc_hash_filereader filereader_funcs;
static struct rc_hash_filereader* filereader = NULL;
#if defined(WINVER) && WINVER >= 0x0500
static void* filereader_open(const char* path)
{
#if defined(WINVER) && WINVER >= 0x0500
/* Windows requires using wchar APIs for Unicode paths */
/* Note that MultiByteToWideChar will only be defined for >= Windows 2000 */
wchar_t* wpath;
@ -76,21 +77,34 @@ static void* filereader_open(const char* path)
free(wpath);
return NULL;
}
#if defined(__STDC_WANT_SECURE_LIB__)
_wfopen_s(&fp, wpath, L"rb");
#else
#if defined(__STDC_WANT_SECURE_LIB__)
/* have to use _SH_DENYNO because some cores lock the file while its loaded */
fp = _wfsopen(wpath, L"rb", _SH_DENYNO);
#else
fp = _wfopen(wpath, L"rb");
#endif
#endif
free(wpath);
return fp;
#elif defined(__STDC_WANT_SECURE_LIB__)
FILE* fp;
fopen_s(&fp, path, "rb");
return fp;
#else
return fopen(path, "rb");
#endif
}
#else /* !WINVER >= 0x0500 */
static void* filereader_open(const char* path)
{
#if defined(__STDC_WANT_SECURE_LIB__)
#if defined(WINVER)
/* have to use _SH_DENYNO because some cores lock the file while its loaded */
return _fsopen(path, "rb", _SH_DENYNO);
#else /* !WINVER */
FILE *fp;
fopen_s(&fp, path, "rb");
return fp;
#endif
#else /* !__STDC_WANT_SECURE_LIB__ */
return fopen(path, "rb");
#endif
}
#endif /* WINVER >= 0x0500 */
static void filereader_seek(void* file_handle, int64_t offset, int origin)
{
@ -2756,6 +2770,14 @@ static int rc_hash_psp(char hash[33], const char* path)
uint32_t size;
md5_state_t md5;
/* https://www.psdevwiki.com/psp/PBP
* A PBP file is an archive containing the PARAM.SFO, primary executable, and a bunch of metadata.
* While we could extract the PARAM.SFO and primary executable to mimic the normal PSP hashing logic,
* it's easier to just hash the entire file. This also helps alleviate issues where the primary
* executable is just a game engine and the only differentiating data would be the metadata. */
if (rc_path_compare_extension(path, "pbp"))
return rc_hash_whole_file(hash, path);
track_handle = rc_cd_open_track(path, 1);
if (!track_handle)
return rc_hash_error("Could not open track");
@ -3772,6 +3794,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
{
iterator->consoles[0] = RC_CONSOLE_PC_ENGINE;
}
else if (rc_path_compare_extension(ext, "pbp"))
{
iterator->consoles[0] = RC_CONSOLE_PSP;
}
else if (rc_path_compare_extension(ext, "pgm"))
{
iterator->consoles[0] = RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER;