upgrade to rcheevos 10.6 (#14911)
This commit is contained in:
parent
46cf1d795a
commit
5ecdc4c170
|
@ -672,6 +672,7 @@ bool rcheevos_unload(void)
|
||||||
|
|
||||||
if (rcheevos_locals.loaded)
|
if (rcheevos_locals.loaded)
|
||||||
{
|
{
|
||||||
|
unsigned count = 0;
|
||||||
#ifdef HAVE_MENU
|
#ifdef HAVE_MENU
|
||||||
rcheevos_menu_reset_badges();
|
rcheevos_menu_reset_badges();
|
||||||
|
|
||||||
|
@ -684,6 +685,45 @@ bool rcheevos_unload(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
count = rcheevos_locals.game.achievement_count;
|
||||||
|
rcheevos_locals.game.achievement_count = 0;
|
||||||
|
if (rcheevos_locals.game.achievements)
|
||||||
|
{
|
||||||
|
rcheevos_racheevo_t* achievement = rcheevos_locals.game.achievements;
|
||||||
|
rcheevos_racheevo_t* end = achievement + count;
|
||||||
|
while (achievement < end)
|
||||||
|
{
|
||||||
|
CHEEVOS_FREE(achievement->title);
|
||||||
|
CHEEVOS_FREE(achievement->description);
|
||||||
|
CHEEVOS_FREE(achievement->badge);
|
||||||
|
CHEEVOS_FREE(achievement->memaddr);
|
||||||
|
|
||||||
|
++achievement;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHEEVOS_FREE(rcheevos_locals.game.achievements);
|
||||||
|
rcheevos_locals.game.achievements = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = rcheevos_locals.game.leaderboard_count;
|
||||||
|
rcheevos_locals.game.leaderboard_count = 0;
|
||||||
|
if (rcheevos_locals.game.leaderboards)
|
||||||
|
{
|
||||||
|
rcheevos_ralboard_t* lboard = rcheevos_locals.game.leaderboards;
|
||||||
|
rcheevos_ralboard_t* end = lboard + count;
|
||||||
|
while (lboard < end)
|
||||||
|
{
|
||||||
|
CHEEVOS_FREE(lboard->title);
|
||||||
|
CHEEVOS_FREE(lboard->description);
|
||||||
|
CHEEVOS_FREE(lboard->mem);
|
||||||
|
|
||||||
|
++lboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHEEVOS_FREE(rcheevos_locals.game.leaderboards);
|
||||||
|
rcheevos_locals.game.leaderboards = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (rcheevos_locals.game.title)
|
if (rcheevos_locals.game.title)
|
||||||
{
|
{
|
||||||
CHEEVOS_FREE(rcheevos_locals.game.title);
|
CHEEVOS_FREE(rcheevos_locals.game.title);
|
||||||
|
@ -1535,6 +1575,9 @@ static void rcheevos_show_game_placard(void)
|
||||||
int number_of_core = 0;
|
int number_of_core = 0;
|
||||||
int mode = RCHEEVOS_ACTIVE_SOFTCORE;
|
int mode = RCHEEVOS_ACTIVE_SOFTCORE;
|
||||||
|
|
||||||
|
if (rcheevos_locals.game.id < 0) /* make sure there's actually a game loaded */
|
||||||
|
return;
|
||||||
|
|
||||||
if (rcheevos_locals.hardcore_active)
|
if (rcheevos_locals.hardcore_active)
|
||||||
mode = RCHEEVOS_ACTIVE_HARDCORE;
|
mode = RCHEEVOS_ACTIVE_HARDCORE;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,67 @@
|
||||||
|
# v10.6.0
|
||||||
|
* add RC_RUNTIME_EVENT_ACHIEVEMENT_PROGRESS_UPDATED
|
||||||
|
* use optimized comparators for most common condition logic
|
||||||
|
* fix game identification of psx ISOs that have extra slashes in their boot path
|
||||||
|
* fix game identification of ndd files
|
||||||
|
|
||||||
|
# v10.5.0
|
||||||
|
* add RC_MEMSIZE_MBF32_LE
|
||||||
|
* add RC_OPERATOR_XOR
|
||||||
|
* add RC_CONSOLE_ATARI_JAGUAR_CD and hash/memory map for Atari Jaguar CD
|
||||||
|
* add RC_CONSOLE_ARCADIA_2001 and hash/memory map for Arcadia 2001
|
||||||
|
* add RC_CONSOLE_INTERTON_VC_4000 and hash/memory map for Interton VC 4000
|
||||||
|
* add RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER and hash/memory map for Elektor TV Games Computer
|
||||||
|
* split RC_CONSOLE_PC_ENGINE_CD off of RC_CONSOLE_PC_ENGINE
|
||||||
|
* add hash/memory map for RC_CONSOLE_NEO_GEO_CD
|
||||||
|
* add additional 256KB of RAM to memory map for RC_CONSOLE_SEGA_32X
|
||||||
|
* validation: don't report redundancy between trigger and non-trigger conditions
|
||||||
|
* validation: don't report range validation errors for float comparisons
|
||||||
|
* change default image host to media.retroachievements.org
|
||||||
|
* fix decoding of denormalized floats
|
||||||
|
* fix full line comments in the middle of Display: section causing RC_MISSING_DISPLAY_STRING
|
||||||
|
|
||||||
|
# v10.4.0
|
||||||
|
* add rc_libretro_hash_set_t with support for #SAVEDISK: m3u extension
|
||||||
|
* add rc_libretro_is_system_allowed for finer-grain control over core support
|
||||||
|
* fix measured value from hitcount not resetting while paused
|
||||||
|
* add RC_CONSOLE_WASM and hash/memory map for WASM-4
|
||||||
|
* add scratchpad memory to RC_CONSOLE_PLAYSTATION_2 memory map
|
||||||
|
* add hash/memory map for RC_CONSOLE_FAIRCHILD_CHANNEL_F
|
||||||
|
* add hash/memory map for RC_CONSOLE_COMMODORE_64
|
||||||
|
* add memory map for RC_CONSOLE_AMIGA
|
||||||
|
|
||||||
|
# v10.3.3
|
||||||
|
* add RC_CONSOLE_ARDUBOY and hash/memory map for Arduboy
|
||||||
|
* add display_name to rc_api_login_response_t
|
||||||
|
* detect logical conflicts and redundancies in validator
|
||||||
|
* fix tab sequences in JSON responses being turned into t
|
||||||
|
* fix overflow when float value has more than 9 digits after the decimal
|
||||||
|
* fix libretro memory mapping when disconnect mask breaks a region into multiple blocks
|
||||||
|
* fix non-virtualized file system call when reading some iso files
|
||||||
|
|
||||||
|
# v10.3.2
|
||||||
|
* fix RC_OPERAND_PRIOR for bit sizes other than RC_MEMSIZE_BIT_0
|
||||||
|
* add memory map and hash for Amstrad CPC
|
||||||
|
* fix an issue where fetch_game_data and fetch_user_unlocks could return RC_MISSING_VALUE instead of acknowledging a server error
|
||||||
|
|
||||||
|
# v10.3.1
|
||||||
|
* allow empty description in rc_api_init_update_leaderboard_request
|
||||||
|
* fix buffered n64 hash when no filereader is registered
|
||||||
|
* add memory map and hash for Mega Duck
|
||||||
|
|
||||||
|
# v10.3.0
|
||||||
|
* support for floating point memory sizes and logic
|
||||||
|
* add built-in macros for rich presence: @Number, @Score, @Centisecs, @Seconds, @Minutes, @ASCIIChar, @UnicodeChar
|
||||||
|
* add rapi functions for fetch_code_notes, update_code_note, upload_achievement, update_leaderboard, fetch_badge_range, and add_game_hash
|
||||||
|
* add lower_is_better and hidden flags to leaderboards in rc_api_fetch_game_data_response_t
|
||||||
|
* add achievements_remaining to rc_api_award_achievement_response_t
|
||||||
|
* add console enums for PC6000, PICO, MEGADUCK and ZEEBO
|
||||||
|
* add memory map for Dreamcast
|
||||||
|
* capture leaderboard/rich presence state in rc_runtime_progress data
|
||||||
|
* support for hashing Dreamcast bin/cues
|
||||||
|
* support for hashing buffered NDS ROMs
|
||||||
|
* fix prior for sizes smaller than a byte sometimes returning current value
|
||||||
|
|
||||||
# v10.2.0
|
# v10.2.0
|
||||||
|
|
||||||
* add RC_MEMSIZE_16_BITS_BE, RC_MEMSIZE_24_BITS_BE, and RC_MEMSIZE_32_BITS_BE
|
* add RC_MEMSIZE_16_BITS_BE, RC_MEMSIZE_24_BITS_BE, and RC_MEMSIZE_32_BITS_BE
|
||||||
|
|
|
@ -200,6 +200,9 @@ struct rc_condition_t {
|
||||||
|
|
||||||
/* Whether or not the condition evaluated true on the last check */
|
/* Whether or not the condition evaluated true on the last check */
|
||||||
char is_true;
|
char is_true;
|
||||||
|
|
||||||
|
/* Unique identifier of optimized comparator to use */
|
||||||
|
char optimized_comparator;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
|
|
|
@ -1,6 +1,91 @@
|
||||||
#include "rc_internal.h"
|
#include "rc_internal.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
static int rc_test_condition_compare(unsigned value1, unsigned value2, char oper) {
|
||||||
|
switch (oper) {
|
||||||
|
case RC_OPERATOR_EQ: return value1 == value2;
|
||||||
|
case RC_OPERATOR_NE: return value1 != value2;
|
||||||
|
case RC_OPERATOR_LT: return value1 < value2;
|
||||||
|
case RC_OPERATOR_LE: return value1 <= value2;
|
||||||
|
case RC_OPERATOR_GT: return value1 > value2;
|
||||||
|
case RC_OPERATOR_GE: return value1 >= value2;
|
||||||
|
default: return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char rc_condition_determine_comparator(const rc_condition_t* self) {
|
||||||
|
switch (self->oper) {
|
||||||
|
case RC_OPERATOR_EQ:
|
||||||
|
case RC_OPERATOR_NE:
|
||||||
|
case RC_OPERATOR_LT:
|
||||||
|
case RC_OPERATOR_LE:
|
||||||
|
case RC_OPERATOR_GT:
|
||||||
|
case RC_OPERATOR_GE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* not a comparison. should not be getting compared. but if it is, legacy behavior was to return 1 */
|
||||||
|
return RC_PROCESSING_COMPARE_ALWAYS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((self->operand1.type == RC_OPERAND_ADDRESS || self->operand1.type == RC_OPERAND_DELTA) &&
|
||||||
|
!self->operand1.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand1)) {
|
||||||
|
/* left side is an integer memory reference */
|
||||||
|
int needs_translate = (self->operand1.size != self->operand1.value.memref->value.size);
|
||||||
|
|
||||||
|
if (self->operand2.type == RC_OPERAND_CONST) {
|
||||||
|
/* right side is a constant */
|
||||||
|
if (self->operand1.type == RC_OPERAND_ADDRESS)
|
||||||
|
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_CONST;
|
||||||
|
|
||||||
|
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_CONST;
|
||||||
|
}
|
||||||
|
else if ((self->operand2.type == RC_OPERAND_ADDRESS || self->operand2.type == RC_OPERAND_DELTA) &&
|
||||||
|
!self->operand2.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand2)) {
|
||||||
|
/* right side is an integer memory reference */
|
||||||
|
const int is_same_memref = (self->operand1.value.memref == self->operand2.value.memref);
|
||||||
|
needs_translate |= (self->operand2.size != self->operand2.value.memref->value.size);
|
||||||
|
|
||||||
|
if (self->operand1.type == RC_OPERAND_ADDRESS) {
|
||||||
|
if (self->operand2.type == RC_OPERAND_ADDRESS) {
|
||||||
|
if (is_same_memref && !needs_translate) {
|
||||||
|
/* comparing a memref to itself, will evaluate to a constant */
|
||||||
|
return rc_test_condition_compare(0, 0, self->oper) ? RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(self->operand2.type == RC_OPERAND_DELTA);
|
||||||
|
|
||||||
|
if (is_same_memref) {
|
||||||
|
/* delta comparison is optimized to compare with itself (for detecting change) */
|
||||||
|
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_DELTA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(self->operand1.type == RC_OPERAND_DELTA);
|
||||||
|
|
||||||
|
if (self->operand2.type == RC_OPERAND_ADDRESS) {
|
||||||
|
if (is_same_memref) {
|
||||||
|
/* delta comparison is optimized to compare with itself (for detecting change) */
|
||||||
|
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_MEMREF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->operand1.type == RC_OPERAND_CONST && self->operand2.type == RC_OPERAND_CONST) {
|
||||||
|
/* comparing constants will always generate a constant result */
|
||||||
|
return rc_test_condition_compare(self->operand1.value.num, self->operand2.value.num, self->oper) ?
|
||||||
|
RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RC_PROCESSING_COMPARE_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
static int rc_parse_operator(const char** memaddr) {
|
static int rc_parse_operator(const char** memaddr) {
|
||||||
const char* oper = *memaddr;
|
const char* oper = *memaddr;
|
||||||
|
@ -75,6 +160,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||||
self->current_hits = 0;
|
self->current_hits = 0;
|
||||||
self->is_true = 0;
|
self->is_true = 0;
|
||||||
self->pause = 0;
|
self->pause = 0;
|
||||||
|
self->optimized_comparator = RC_PROCESSING_COMPARE_DEFAULT;
|
||||||
|
|
||||||
if (*aux != 0 && aux[1] == ':') {
|
if (*aux != 0 && aux[1] == ':') {
|
||||||
switch (*aux) {
|
switch (*aux) {
|
||||||
|
@ -214,6 +300,9 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||||
self->required_hits = 0;
|
self->required_hits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parse->buffer != 0)
|
||||||
|
self->optimized_comparator = rc_condition_determine_comparator(self);
|
||||||
|
|
||||||
*memaddr = aux;
|
*memaddr = aux;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -233,12 +322,203 @@ int rc_condition_is_combining(const rc_condition_t* self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_memref_to_const(rc_condition_t* self) {
|
||||||
|
const unsigned value1 = self->operand1.value.memref->value.value;
|
||||||
|
const unsigned value2 = self->operand2.value.num;
|
||||||
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
|
return rc_test_condition_compare(value1, value2, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_delta_to_const(rc_condition_t* self) {
|
||||||
|
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
||||||
|
const unsigned value1 = (memref1->changed) ? memref1->prior : memref1->value;
|
||||||
|
const unsigned value2 = self->operand2.value.num;
|
||||||
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
|
return rc_test_condition_compare(value1, value2, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_memref_to_memref(rc_condition_t* self) {
|
||||||
|
const unsigned value1 = self->operand1.value.memref->value.value;
|
||||||
|
const unsigned value2 = self->operand2.value.memref->value.value;
|
||||||
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
|
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
||||||
|
return rc_test_condition_compare(value1, value2, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_memref_to_delta(rc_condition_t* self) {
|
||||||
|
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
||||||
|
assert(self->operand1.value.memref == self->operand2.value.memref);
|
||||||
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
|
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
||||||
|
|
||||||
|
if (memref->changed)
|
||||||
|
return rc_test_condition_compare(memref->value, memref->prior, self->oper);
|
||||||
|
|
||||||
|
switch (self->oper) {
|
||||||
|
case RC_OPERATOR_EQ:
|
||||||
|
case RC_OPERATOR_GE:
|
||||||
|
case RC_OPERATOR_LE:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_delta_to_memref(rc_condition_t* self) {
|
||||||
|
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
||||||
|
assert(self->operand1.value.memref == self->operand2.value.memref);
|
||||||
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
|
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
||||||
|
|
||||||
|
if (memref->changed)
|
||||||
|
return rc_test_condition_compare(memref->prior, memref->value, self->oper);
|
||||||
|
|
||||||
|
switch (self->oper) {
|
||||||
|
case RC_OPERATOR_EQ:
|
||||||
|
case RC_OPERATOR_GE:
|
||||||
|
case RC_OPERATOR_LE:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_memref_to_const_transformed(rc_condition_t* self) {
|
||||||
|
rc_typed_value_t value1;
|
||||||
|
const unsigned value2 = self->operand2.value.num;
|
||||||
|
|
||||||
|
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value1.value.u32 = self->operand1.value.memref->value.value;
|
||||||
|
rc_transform_memref_value(&value1, self->operand1.size);
|
||||||
|
|
||||||
|
return rc_test_condition_compare(value1.value.u32, value2, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_delta_to_const_transformed(rc_condition_t* self) {
|
||||||
|
rc_typed_value_t value1;
|
||||||
|
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
||||||
|
const unsigned value2 = self->operand2.value.num;
|
||||||
|
|
||||||
|
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value1.value.u32 = (memref1->changed) ? memref1->prior : memref1->value;
|
||||||
|
rc_transform_memref_value(&value1, self->operand1.size);
|
||||||
|
|
||||||
|
return rc_test_condition_compare(value1.value.u32, value2, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_memref_to_memref_transformed(rc_condition_t* self) {
|
||||||
|
rc_typed_value_t value1, value2;
|
||||||
|
|
||||||
|
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value1.value.u32 = self->operand1.value.memref->value.value;
|
||||||
|
rc_transform_memref_value(&value1, self->operand1.size);
|
||||||
|
|
||||||
|
value2.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value2.value.u32 = self->operand2.value.memref->value.value;
|
||||||
|
rc_transform_memref_value(&value2, self->operand2.size);
|
||||||
|
|
||||||
|
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_memref_to_delta_transformed(rc_condition_t* self) {
|
||||||
|
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
||||||
|
assert(self->operand1.value.memref == self->operand2.value.memref);
|
||||||
|
|
||||||
|
if (memref->changed) {
|
||||||
|
rc_typed_value_t value1, value2;
|
||||||
|
|
||||||
|
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value1.value.u32 = memref->value;
|
||||||
|
rc_transform_memref_value(&value1, self->operand1.size);
|
||||||
|
|
||||||
|
value2.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value2.value.u32 = memref->prior;
|
||||||
|
rc_transform_memref_value(&value2, self->operand2.size);
|
||||||
|
|
||||||
|
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (self->oper) {
|
||||||
|
case RC_OPERATOR_EQ:
|
||||||
|
case RC_OPERATOR_GE:
|
||||||
|
case RC_OPERATOR_LE:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_test_condition_compare_delta_to_memref_transformed(rc_condition_t* self) {
|
||||||
|
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
||||||
|
assert(self->operand1.value.memref == self->operand2.value.memref);
|
||||||
|
|
||||||
|
if (memref->changed) {
|
||||||
|
rc_typed_value_t value1, value2;
|
||||||
|
|
||||||
|
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value1.value.u32 = memref->prior;
|
||||||
|
rc_transform_memref_value(&value1, self->operand1.size);
|
||||||
|
|
||||||
|
value2.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
|
value2.value.u32 = memref->value;
|
||||||
|
rc_transform_memref_value(&value2, self->operand2.size);
|
||||||
|
|
||||||
|
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (self->oper) {
|
||||||
|
case RC_OPERATOR_EQ:
|
||||||
|
case RC_OPERATOR_GE:
|
||||||
|
case RC_OPERATOR_LE:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
|
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
|
||||||
rc_typed_value_t value1, value2;
|
rc_typed_value_t value1, value2;
|
||||||
|
|
||||||
rc_evaluate_operand(&value1, &self->operand1, eval_state);
|
if (eval_state->add_value.type != RC_VALUE_TYPE_NONE) {
|
||||||
if (eval_state->add_value.type != RC_VALUE_TYPE_NONE)
|
/* if there's an accumulator, we can't use the optimized comparators */
|
||||||
|
rc_evaluate_operand(&value1, &self->operand1, eval_state);
|
||||||
rc_typed_value_add(&value1, &eval_state->add_value);
|
rc_typed_value_add(&value1, &eval_state->add_value);
|
||||||
|
} else {
|
||||||
|
/* use an optimized comparator whenever possible */
|
||||||
|
switch (self->optimized_comparator) {
|
||||||
|
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST:
|
||||||
|
return rc_test_condition_compare_memref_to_const(self);
|
||||||
|
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA:
|
||||||
|
return rc_test_condition_compare_memref_to_delta(self);
|
||||||
|
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF:
|
||||||
|
return rc_test_condition_compare_memref_to_memref(self);
|
||||||
|
case RC_PROCESSING_COMPARE_DELTA_TO_CONST:
|
||||||
|
return rc_test_condition_compare_delta_to_const(self);
|
||||||
|
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF:
|
||||||
|
return rc_test_condition_compare_delta_to_memref(self);
|
||||||
|
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED:
|
||||||
|
return rc_test_condition_compare_memref_to_const_transformed(self);
|
||||||
|
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED:
|
||||||
|
return rc_test_condition_compare_memref_to_delta_transformed(self);
|
||||||
|
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED:
|
||||||
|
return rc_test_condition_compare_memref_to_memref_transformed(self);
|
||||||
|
case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED:
|
||||||
|
return rc_test_condition_compare_delta_to_const_transformed(self);
|
||||||
|
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED:
|
||||||
|
return rc_test_condition_compare_delta_to_memref_transformed(self);
|
||||||
|
case RC_PROCESSING_COMPARE_ALWAYS_TRUE:
|
||||||
|
return 1;
|
||||||
|
case RC_PROCESSING_COMPARE_ALWAYS_FALSE:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
rc_evaluate_operand(&value1, &self->operand1, eval_state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc_evaluate_operand(&value2, &self->operand2, eval_state);
|
rc_evaluate_operand(&value2, &self->operand2, eval_state);
|
||||||
|
|
||||||
|
|
|
@ -444,7 +444,7 @@ void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs)
|
||||||
*memrefs = 0;
|
*memrefs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type) {
|
static unsigned rc_get_memref_value_value(const rc_memref_value_t* memref, int operand_type) {
|
||||||
switch (operand_type)
|
switch (operand_type)
|
||||||
{
|
{
|
||||||
/* most common case explicitly first, even though it could be handled by default case.
|
/* most common case explicitly first, even though it could be handled by default case.
|
||||||
|
|
|
@ -146,6 +146,22 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
|
||||||
int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state);
|
int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state);
|
||||||
void rc_reset_condset(rc_condset_t* self);
|
void rc_reset_condset(rc_condset_t* self);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RC_PROCESSING_COMPARE_DEFAULT = 0,
|
||||||
|
RC_PROCESSING_COMPARE_MEMREF_TO_CONST,
|
||||||
|
RC_PROCESSING_COMPARE_MEMREF_TO_DELTA,
|
||||||
|
RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF,
|
||||||
|
RC_PROCESSING_COMPARE_DELTA_TO_MEMREF,
|
||||||
|
RC_PROCESSING_COMPARE_DELTA_TO_CONST,
|
||||||
|
RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED,
|
||||||
|
RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED,
|
||||||
|
RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED,
|
||||||
|
RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED,
|
||||||
|
RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED,
|
||||||
|
RC_PROCESSING_COMPARE_ALWAYS_TRUE,
|
||||||
|
RC_PROCESSING_COMPARE_ALWAYS_FALSE
|
||||||
|
};
|
||||||
|
|
||||||
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect);
|
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect);
|
||||||
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
|
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
|
||||||
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);
|
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);
|
||||||
|
|
|
@ -129,6 +129,12 @@ static const rc_disallowed_setting_t _rc_disallowed_snes9x_settings[] = {
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const rc_disallowed_setting_t _rc_disallowed_vice_settings[] = {
|
||||||
|
{ "vice_autostart", "disabled" }, /* autostart dictates initial load and reset from menu */
|
||||||
|
{ "vice_reset", "!autostart" }, /* reset dictates behavior when pressing reset button (END) */
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static const rc_disallowed_setting_t _rc_disallowed_virtual_jaguar_settings[] = {
|
static const rc_disallowed_setting_t _rc_disallowed_virtual_jaguar_settings[] = {
|
||||||
{ "virtualjaguar_pal", "enabled" },
|
{ "virtualjaguar_pal", "enabled" },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
|
@ -152,6 +158,7 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
|
||||||
{ "QUASI88", _rc_disallowed_quasi88_settings },
|
{ "QUASI88", _rc_disallowed_quasi88_settings },
|
||||||
{ "SMS Plus GX", _rc_disallowed_smsplus_settings },
|
{ "SMS Plus GX", _rc_disallowed_smsplus_settings },
|
||||||
{ "Snes9x", _rc_disallowed_snes9x_settings },
|
{ "Snes9x", _rc_disallowed_snes9x_settings },
|
||||||
|
{ "VICE x64", _rc_disallowed_vice_settings },
|
||||||
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings },
|
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
@ -613,7 +620,7 @@ void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set,
|
||||||
char image_path[1024];
|
char image_path[1024];
|
||||||
char* m3u_contents;
|
char* m3u_contents;
|
||||||
char* ptr;
|
char* ptr;
|
||||||
size_t file_len;
|
int64_t file_len;
|
||||||
void* file_handle;
|
void* file_handle;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
|
|
|
@ -197,14 +197,6 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||||
self->measured_value = eval_state.measured_value.value.u32;
|
self->measured_value = eval_state.measured_value.value.u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */
|
|
||||||
/* otherwise, if the state is WAITING, proceed to activating the trigger */
|
|
||||||
if (self->state == RC_TRIGGER_STATE_WAITING && ret) {
|
|
||||||
rc_reset_trigger(self);
|
|
||||||
self->has_hits = 0;
|
|
||||||
return RC_TRIGGER_STATE_WAITING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if any ResetIf condition was true, reset the hit counts */
|
/* if any ResetIf condition was true, reset the hit counts */
|
||||||
if (eval_state.was_reset) {
|
if (eval_state.was_reset) {
|
||||||
/* if the measured value came from a hit count, reset it. do this before calling
|
/* if the measured value came from a hit count, reset it. do this before calling
|
||||||
|
@ -247,6 +239,13 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||||
is_primed = 0;
|
is_primed = 0;
|
||||||
}
|
}
|
||||||
else if (ret) {
|
else if (ret) {
|
||||||
|
/* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */
|
||||||
|
if (self->state == RC_TRIGGER_STATE_WAITING) {
|
||||||
|
rc_reset_trigger(self);
|
||||||
|
self->has_hits = 0;
|
||||||
|
return RC_TRIGGER_STATE_WAITING;
|
||||||
|
}
|
||||||
|
|
||||||
/* trigger was triggered */
|
/* trigger was triggered */
|
||||||
self->state = RC_TRIGGER_STATE_TRIGGERED;
|
self->state = RC_TRIGGER_STATE_TRIGGERED;
|
||||||
return RC_TRIGGER_STATE_TRIGGERED;
|
return RC_TRIGGER_STATE_TRIGGERED;
|
||||||
|
|
|
@ -230,6 +230,10 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
|
||||||
if (!track_handle)
|
if (!track_handle)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* we start at the root. don't need to explicitly find it */
|
||||||
|
if (*path == '\\')
|
||||||
|
++path;
|
||||||
|
|
||||||
filename_length = strlen(path);
|
filename_length = strlen(path);
|
||||||
slash = strrchr(path, '\\');
|
slash = strrchr(path, '\\');
|
||||||
if (slash)
|
if (slash)
|
||||||
|
@ -966,6 +970,9 @@ static int rc_hash_n64(char hash[33], const char* path)
|
||||||
rc_hash_verbose("converting n64 to z64");
|
rc_hash_verbose("converting n64 to z64");
|
||||||
is_n64 = 1;
|
is_n64 = 1;
|
||||||
}
|
}
|
||||||
|
else if (buffer[0] == 0xE8 || buffer[0] == 0x22) /* ndd format (don't byteswap) */
|
||||||
|
{
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
@ -1469,7 +1476,7 @@ static int rc_hash_find_playstation_executable(void* track_handle, const char* b
|
||||||
|
|
||||||
if (strncmp(ptr, cdrom_prefix, cdrom_prefix_len) == 0)
|
if (strncmp(ptr, cdrom_prefix, cdrom_prefix_len) == 0)
|
||||||
ptr += cdrom_prefix_len;
|
ptr += cdrom_prefix_len;
|
||||||
if (*ptr == '\\')
|
while (*ptr == '\\')
|
||||||
++ptr;
|
++ptr;
|
||||||
|
|
||||||
start = ptr;
|
start = ptr;
|
||||||
|
|
Loading…
Reference in New Issue