mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-28 18:50:29 +00:00
Merge pull request #5156 from leiradel/master
Added support for N64 cheevos
This commit is contained in:
commit
913eab54ff
@ -170,6 +170,9 @@ enum
|
|||||||
CHEEVOS_COND_TYPE_STANDARD = 0,
|
CHEEVOS_COND_TYPE_STANDARD = 0,
|
||||||
CHEEVOS_COND_TYPE_PAUSE_IF,
|
CHEEVOS_COND_TYPE_PAUSE_IF,
|
||||||
CHEEVOS_COND_TYPE_RESET_IF,
|
CHEEVOS_COND_TYPE_RESET_IF,
|
||||||
|
CHEEVOS_COND_TYPE_ADD_SOURCE,
|
||||||
|
CHEEVOS_COND_TYPE_SUB_SOURCE,
|
||||||
|
CHEEVOS_COND_TYPE_ADD_HITS,
|
||||||
|
|
||||||
CHEEVOS_COND_TYPE_LAST
|
CHEEVOS_COND_TYPE_LAST
|
||||||
}; /* cheevos_cond_t.type */
|
}; /* cheevos_cond_t.type */
|
||||||
@ -321,6 +324,9 @@ typedef struct
|
|||||||
{
|
{
|
||||||
int console_id;
|
int console_id;
|
||||||
bool core_supports;
|
bool core_supports;
|
||||||
|
bool addrs_patched;
|
||||||
|
int add_buffer;
|
||||||
|
int add_hits;
|
||||||
|
|
||||||
cheevoset_t core;
|
cheevoset_t core;
|
||||||
cheevoset_t unofficial;
|
cheevoset_t unofficial;
|
||||||
@ -336,6 +342,9 @@ static cheevos_locals_t cheevos_locals =
|
|||||||
{
|
{
|
||||||
/* console_id */ 0,
|
/* console_id */ 0,
|
||||||
/* core_supports */ true,
|
/* core_supports */ true,
|
||||||
|
/* addrs_patched */ false,
|
||||||
|
/* add_buffer */ 0,
|
||||||
|
/* add_hits */ 0,
|
||||||
/* core */ {NULL, 0},
|
/* core */ {NULL, 0},
|
||||||
/* unofficial */ {NULL, 0},
|
/* unofficial */ {NULL, 0},
|
||||||
/* leaderboards */ NULL,
|
/* leaderboards */ NULL,
|
||||||
@ -505,6 +514,9 @@ static void cheevos_log_cond(const cheevos_cond_t* cond)
|
|||||||
cond->type == CHEEVOS_COND_TYPE_STANDARD ? "standard" :
|
cond->type == CHEEVOS_COND_TYPE_STANDARD ? "standard" :
|
||||||
cond->type == CHEEVOS_COND_TYPE_PAUSE_IF ? "pause" :
|
cond->type == CHEEVOS_COND_TYPE_PAUSE_IF ? "pause" :
|
||||||
cond->type == CHEEVOS_COND_TYPE_RESET_IF ? "reset" :
|
cond->type == CHEEVOS_COND_TYPE_RESET_IF ? "reset" :
|
||||||
|
cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE ? "add source" :
|
||||||
|
cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE ? "sub source" :
|
||||||
|
cond->type == CHEEVOS_COND_TYPE_ADD_HITS ? "add hits" :
|
||||||
"?"
|
"?"
|
||||||
);
|
);
|
||||||
RARCH_LOG("CHEEVOS req_hits: %u\n", cond->req_hits);
|
RARCH_LOG("CHEEVOS req_hits: %u\n", cond->req_hits);
|
||||||
@ -628,6 +640,12 @@ static void cheevos_build_memaddr(const cheevos_condition_t* condition,
|
|||||||
cheevos_add_string(&aux, &left, "R:");
|
cheevos_add_string(&aux, &left, "R:");
|
||||||
else if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF)
|
else if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF)
|
||||||
cheevos_add_string(&aux, &left, "P:");
|
cheevos_add_string(&aux, &left, "P:");
|
||||||
|
else if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE)
|
||||||
|
cheevos_add_string(&aux, &left, "A:");
|
||||||
|
else if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE)
|
||||||
|
cheevos_add_string(&aux, &left, "B:");
|
||||||
|
else if (cond->type == CHEEVOS_COND_TYPE_ADD_HITS)
|
||||||
|
cheevos_add_string(&aux, &left, "C:");
|
||||||
|
|
||||||
cheevos_add_var(&cond->source, &aux, &left);
|
cheevos_add_var(&cond->source, &aux, &left);
|
||||||
|
|
||||||
@ -1151,38 +1169,42 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
|
|||||||
|
|
||||||
var->value = (unsigned)strtol(str, &end, base);
|
var->value = (unsigned)strtol(str, &end, base);
|
||||||
*memaddr = end;
|
*memaddr = end;
|
||||||
|
|
||||||
switch (var->type)
|
|
||||||
{
|
|
||||||
case CHEEVOS_VAR_TYPE_ADDRESS:
|
|
||||||
case CHEEVOS_VAR_TYPE_DELTA_MEM:
|
|
||||||
cheevos_parse_guest_addr(var, var->value);
|
|
||||||
#ifdef CHEEVOS_DUMP_ADDRS
|
|
||||||
RARCH_LOG("CHEEVOS var %03d:%08X\n", var->bank_id + 1, var->value);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cheevos_parse_cond(cheevos_cond_t *cond, const char **memaddr)
|
static void cheevos_parse_cond(cheevos_cond_t *cond, const char **memaddr)
|
||||||
{
|
{
|
||||||
const char* str = *memaddr;
|
const char* str = *memaddr;
|
||||||
|
|
||||||
if (*str == 'R' && str[1] == ':')
|
|
||||||
{
|
|
||||||
cond->type = CHEEVOS_COND_TYPE_RESET_IF;
|
|
||||||
str += 2;
|
|
||||||
}
|
|
||||||
else if (*str == 'P' && str[1] == ':')
|
|
||||||
{
|
|
||||||
cond->type = CHEEVOS_COND_TYPE_PAUSE_IF;
|
|
||||||
str += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cond->type = CHEEVOS_COND_TYPE_STANDARD;
|
cond->type = CHEEVOS_COND_TYPE_STANDARD;
|
||||||
|
|
||||||
|
if (str[1] == ':')
|
||||||
|
{
|
||||||
|
int skip = 2;
|
||||||
|
|
||||||
|
switch (*str)
|
||||||
|
{
|
||||||
|
case 'R':
|
||||||
|
cond->type = CHEEVOS_COND_TYPE_RESET_IF;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
cond->type = CHEEVOS_COND_TYPE_PAUSE_IF;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
cond->type = CHEEVOS_COND_TYPE_ADD_SOURCE;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
cond->type = CHEEVOS_COND_TYPE_SUB_SOURCE;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
cond->type = CHEEVOS_COND_TYPE_ADD_HITS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
skip = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
str += skip;
|
||||||
|
}
|
||||||
|
|
||||||
cheevos_parse_var(&cond->source, &str);
|
cheevos_parse_var(&cond->source, &str);
|
||||||
cond->op = cheevos_parse_operator(&str);
|
cond->op = cheevos_parse_operator(&str);
|
||||||
cheevos_parse_var(&cond->target, &str);
|
cheevos_parse_var(&cond->target, &str);
|
||||||
@ -1836,7 +1858,7 @@ static unsigned cheevos_get_var_value(cheevos_var_t *var)
|
|||||||
|
|
||||||
static int cheevos_test_condition(cheevos_cond_t *cond)
|
static int cheevos_test_condition(cheevos_cond_t *cond)
|
||||||
{
|
{
|
||||||
unsigned sval = cheevos_get_var_value(&cond->source);
|
unsigned sval = cheevos_get_var_value(&cond->source) + cheevos_locals.add_buffer;
|
||||||
unsigned tval = cheevos_get_var_value(&cond->target);
|
unsigned tval = cheevos_get_var_value(&cond->target);
|
||||||
|
|
||||||
switch (cond->op)
|
switch (cond->op)
|
||||||
@ -1868,6 +1890,9 @@ static int cheevos_test_cond_set(const cheevos_condset_t *condset,
|
|||||||
const cheevos_cond_t *end = condset->conds + condset->count;
|
const cheevos_cond_t *end = condset->conds + condset->count;
|
||||||
cheevos_cond_t *cond = NULL;
|
cheevos_cond_t *cond = NULL;
|
||||||
|
|
||||||
|
cheevos_locals.add_buffer = 0;
|
||||||
|
cheevos_locals.add_hits = 0;
|
||||||
|
|
||||||
/* Now, read all Pause conditions, and if any are true,
|
/* Now, read all Pause conditions, and if any are true,
|
||||||
* do not process further (retain old state). */
|
* do not process further (retain old state). */
|
||||||
|
|
||||||
@ -1896,6 +1921,32 @@ static int cheevos_test_cond_set(const cheevos_condset_t *condset,
|
|||||||
if (cond->type != CHEEVOS_COND_TYPE_STANDARD)
|
if (cond->type != CHEEVOS_COND_TYPE_STANDARD)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE)
|
||||||
|
{
|
||||||
|
cheevos_locals.add_buffer += cheevos_get_var_value(&cond->source);
|
||||||
|
set_valid = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE)
|
||||||
|
{
|
||||||
|
cheevos_locals.add_buffer -= cheevos_get_var_value(&cond->source);
|
||||||
|
set_valid = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cond->type == CHEEVOS_COND_TYPE_ADD_HITS)
|
||||||
|
{
|
||||||
|
if (cheevos_test_condition(cond))
|
||||||
|
{
|
||||||
|
cond->curr_hits++;
|
||||||
|
*dirty_conds = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cheevos_locals.add_hits += cond->curr_hits;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (cond->req_hits != 0 && cond->curr_hits >= cond->req_hits)
|
if (cond->req_hits != 0 && cond->curr_hits >= cond->req_hits)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1909,13 +1960,16 @@ static int cheevos_test_cond_set(const cheevos_condset_t *condset,
|
|||||||
/* Process this logic, if this condition is true: */
|
/* Process this logic, if this condition is true: */
|
||||||
if (cond->req_hits == 0)
|
if (cond->req_hits == 0)
|
||||||
; /* Not a hit-based requirement: ignore any additional logic! */
|
; /* Not a hit-based requirement: ignore any additional logic! */
|
||||||
else if (cond->curr_hits < cond->req_hits)
|
else if ((cond->curr_hits + cheevos_locals.add_hits) < cond->req_hits)
|
||||||
cond_valid = 0; /* Not entirely valid yet! */
|
cond_valid = 0; /* Not entirely valid yet! */
|
||||||
|
|
||||||
if (match_any)
|
if (match_any)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cheevos_locals.add_buffer = 0;
|
||||||
|
cheevos_locals.add_hits = 0;
|
||||||
|
|
||||||
/* Sequential or non-sequential? */
|
/* Sequential or non-sequential? */
|
||||||
set_valid &= cond_valid;
|
set_valid &= cond_valid;
|
||||||
}
|
}
|
||||||
@ -2587,10 +2641,64 @@ bool cheevos_toggle_hardcore_mode(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cheevos_patch_addresses(cheevoset_t* set)
|
||||||
|
{
|
||||||
|
cheevo_t* cheevo = set->cheevos;
|
||||||
|
|
||||||
|
for (unsigned i = set->count; i != 0; i--, cheevo++)
|
||||||
|
{
|
||||||
|
cheevos_condset_t* condset = cheevo->condition.condsets;
|
||||||
|
|
||||||
|
for (unsigned j = cheevo->condition.count; j != 0; j--, condset++)
|
||||||
|
{
|
||||||
|
cheevos_cond_t* cond = condset->conds;
|
||||||
|
|
||||||
|
for (unsigned k = condset->count; k != 0; k--, cond++)
|
||||||
|
{
|
||||||
|
switch (cond->source.type)
|
||||||
|
{
|
||||||
|
case CHEEVOS_VAR_TYPE_ADDRESS:
|
||||||
|
case CHEEVOS_VAR_TYPE_DELTA_MEM:
|
||||||
|
cheevos_parse_guest_addr(&cond->source, cond->source.value);
|
||||||
|
#ifdef CHEEVOS_DUMP_ADDRS
|
||||||
|
RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->source.bank_id + 1, cond->source.value);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cond->target.type)
|
||||||
|
{
|
||||||
|
case CHEEVOS_VAR_TYPE_ADDRESS:
|
||||||
|
case CHEEVOS_VAR_TYPE_DELTA_MEM:
|
||||||
|
cheevos_parse_guest_addr(&cond->target, cond->target.value);
|
||||||
|
#ifdef CHEEVOS_DUMP_ADDRS
|
||||||
|
RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->target.bank_id + 1, cond->target.value);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cheevos_test(void)
|
void cheevos_test(void)
|
||||||
{
|
{
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
if (!cheevos_locals.addrs_patched)
|
||||||
|
{
|
||||||
|
cheevos_patch_addresses(&cheevos_locals.core);
|
||||||
|
cheevos_patch_addresses(&cheevos_locals.unofficial);
|
||||||
|
|
||||||
|
cheevos_locals.addrs_patched = true;
|
||||||
|
}
|
||||||
|
|
||||||
cheevos_test_cheevo_set(&cheevos_locals.core);
|
cheevos_test_cheevo_set(&cheevos_locals.core);
|
||||||
|
|
||||||
if (settings->bools.cheevos_test_unofficial)
|
if (settings->bools.cheevos_test_unofficial)
|
||||||
@ -2742,6 +2850,8 @@ static int cheevos_iterate(coro_t* coro)
|
|||||||
|
|
||||||
CORO_ENTER()
|
CORO_ENTER()
|
||||||
|
|
||||||
|
cheevos_locals.addrs_patched = false;
|
||||||
|
|
||||||
SETTINGS = config_get_ptr();
|
SETTINGS = config_get_ptr();
|
||||||
|
|
||||||
cheevos_locals.meminfo[0].id = RETRO_MEMORY_SYSTEM_RAM;
|
cheevos_locals.meminfo[0].id = RETRO_MEMORY_SYSTEM_RAM;
|
||||||
|
Loading…
Reference in New Issue
Block a user