mirror of
https://github.com/libretro/RetroArch
synced 2025-03-06 04:13:52 +00:00
update rcheevos to v8.1
This commit is contained in:
parent
d3ed02dd87
commit
9983976ddb
@ -110,7 +110,7 @@ typedef struct
|
||||
rc_lboard_t* lboard;
|
||||
const rcheevos_ralboard_t* info;
|
||||
bool active;
|
||||
unsigned last_value;
|
||||
int last_value;
|
||||
int format;
|
||||
} rcheevos_lboard_t;
|
||||
|
||||
@ -355,6 +355,13 @@ static const char* rcheevos_rc_error(int ret)
|
||||
case RC_MISSING_SUBMIT: return "Missing submit condition";
|
||||
case RC_MISSING_VALUE: return "Missing value expression";
|
||||
case RC_INVALID_LBOARD_FIELD: return "Invalid field in leaderboard";
|
||||
case RC_MISSING_DISPLAY_STRING: return "Missing display string";
|
||||
case RC_OUT_OF_MEMORY: return "Out of memory";
|
||||
case RC_INVALID_VALUE_FLAG: return "Invalid flag in value expression";
|
||||
case RC_MISSING_VALUE_MEASURED: return "Missing value (measured)";
|
||||
case RC_MULTIPLE_MEASURED: return "Multiple measured targets";
|
||||
case RC_INVALID_MEASURED_TARGET: return "Invalid measured target";
|
||||
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
@ -803,7 +810,6 @@ static void rcheevos_test_leaderboards(void)
|
||||
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Leaderboard started: %s\n", lboard->info->title);
|
||||
lboard->active = 1;
|
||||
lboard->last_value = 0;
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"Leaderboard Active: %s", lboard->info->title);
|
||||
@ -824,19 +830,29 @@ void rcheevos_reset_game(void)
|
||||
cheevo = rcheevos_locals.core;
|
||||
for (i = 0; i < rcheevos_locals.patchdata.core_count; i++, cheevo++)
|
||||
{
|
||||
rc_reset_trigger(cheevo->trigger);
|
||||
cheevo->last = 1;
|
||||
}
|
||||
|
||||
cheevo = rcheevos_locals.unofficial;
|
||||
for (i = 0; i < rcheevos_locals.patchdata.unofficial_count; i++, cheevo++)
|
||||
{
|
||||
rc_reset_trigger(cheevo->trigger);
|
||||
cheevo->last = 1;
|
||||
}
|
||||
|
||||
lboard = rcheevos_locals.lboards;
|
||||
for (i = 0; i < rcheevos_locals.patchdata.lboard_count; i++, lboard++)
|
||||
{
|
||||
rc_reset_lboard(lboard->lboard);
|
||||
|
||||
if (lboard->active)
|
||||
{
|
||||
lboard->active = 0;
|
||||
|
||||
/* this ensures the leaderboard won't restart until the start trigger is false for at least one frame */
|
||||
lboard->lboard->submitted = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
59
deps/rcheevos/README.md
vendored
59
deps/rcheevos/README.md
vendored
@ -53,7 +53,13 @@ enum {
|
||||
RC_MISSING_CANCEL = -14,
|
||||
RC_MISSING_SUBMIT = -15,
|
||||
RC_MISSING_VALUE = -16,
|
||||
RC_INVALID_LBOARD_FIELD = -17
|
||||
RC_INVALID_LBOARD_FIELD = -17,
|
||||
RC_MISSING_DISPLAY_STRING = -18,
|
||||
RC_OUT_OF_MEMORY = -19,
|
||||
RC_INVALID_VALUE_FLAG = -20,
|
||||
RC_MISSING_VALUE_MEASURED = -21,
|
||||
RC_MULTIPLE_MEASURED = -22,
|
||||
RC_INVALID_MEASURED_TARGET = -23
|
||||
};
|
||||
```
|
||||
|
||||
@ -190,16 +196,14 @@ struct rc_condition_t {
|
||||
/* Number of hits so far. */
|
||||
unsigned current_hits;
|
||||
|
||||
/**
|
||||
* Set if the condition needs to processed as part of the "check if paused"
|
||||
* pass
|
||||
*/
|
||||
char pause;
|
||||
|
||||
/* The type of the condition. */
|
||||
char type;
|
||||
/* The comparison operator to use. */
|
||||
char oper; /* operator is a reserved word in C++. */
|
||||
/* Set if the condition needs to processed as part of the "check if paused" pass. */
|
||||
char pause;
|
||||
/* Whether or not the condition evaluated as true on the last check. */
|
||||
char is_true;
|
||||
};
|
||||
```
|
||||
|
||||
@ -212,7 +216,10 @@ enum {
|
||||
RC_CONDITION_RESET_IF,
|
||||
RC_CONDITION_ADD_SOURCE,
|
||||
RC_CONDITION_SUB_SOURCE,
|
||||
RC_CONDITION_ADD_HITS
|
||||
RC_CONDITION_ADD_HITS,
|
||||
RC_CONDITION_AND_NEXT,
|
||||
RC_CONDITION_MEASURED,
|
||||
RC_CONDITION_ADD_ADDRESS
|
||||
};
|
||||
```
|
||||
|
||||
@ -225,7 +232,8 @@ enum {
|
||||
RC_CONDITION_LE,
|
||||
RC_CONDITION_GT,
|
||||
RC_CONDITION_GE,
|
||||
RC_CONDITION_NE
|
||||
RC_CONDITION_NE,
|
||||
RC_CONDITION_NONE
|
||||
};
|
||||
```
|
||||
|
||||
@ -279,10 +287,10 @@ rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L,
|
||||
|
||||
`buffer` is the caller-allocated buffer, which must have enough space for the trigger. `memaddr` describes the trigger, and must be the same one used to compute the trigger's size with `rc_trigger_size`. `L` must be a valid Lua state, and `funcs_ndx` must be an index to the current Lua stack which contains a table which is a map of names to functions. This map is used to look for operands which are Lua functions.
|
||||
|
||||
Once the trigger is created, `rc_test_trigger` can be called to test whether the trigger fires or not.
|
||||
Once the trigger is created, `rc_evaluate_trigger` can be called to test whether the trigger fires or not.
|
||||
|
||||
```c
|
||||
int rc_test_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
|
||||
int rc_evaluate_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
|
||||
```
|
||||
|
||||
`trigger` is the trigger to test. `peek` is a callback used to read bytes from the emulated memory. `ud` is an user-provided opaque value that is passed to `peek`. `L` is the Lua state in which context the Lua functions are looked for and called, if necessary.
|
||||
@ -297,6 +305,18 @@ where `address` is the starting address to read from, `num_bytes` the number of
|
||||
|
||||
> Addresses passed to `peek` do *not* map 1:1 to the emulated memory. (**TODO**: document the mapping from `peek` addresses to emulated memory for each supported system.)
|
||||
|
||||
The return value of `rc_evaluate_trigger` is one of the following:
|
||||
```c
|
||||
enum {
|
||||
RC_TRIGGER_STATE_INACTIVE, /* achievement is not being processed */
|
||||
RC_TRIGGER_STATE_WAITING, /* achievement cannot trigger until it has been false for at least one frame */
|
||||
RC_TRIGGER_STATE_ACTIVE, /* achievement is active and may trigger */
|
||||
RC_TRIGGER_STATE_PAUSED, /* achievement is currently paused and will not trigger */
|
||||
RC_TRIGGER_STATE_RESET, /* achievement hit counts were reset */
|
||||
RC_TRIGGER_STATE_TRIGGERED /* achievement has triggered */
|
||||
};
|
||||
```
|
||||
|
||||
Finally, `rc_reset_trigger` can be used to reset the internal state of a trigger.
|
||||
|
||||
```c
|
||||
@ -348,6 +368,12 @@ A value is a collection of expressions. It's used to give the value for a leader
|
||||
typedef struct {
|
||||
/* The list of expression to evaluate. */
|
||||
rc_expression_t* expressions;
|
||||
|
||||
/* The list of conditions to evaluate. */
|
||||
rc_condset_t* conditions;
|
||||
|
||||
/* The memory references required by the value. */
|
||||
rc_memref_value_t* memrefs;
|
||||
}
|
||||
rc_value_t;
|
||||
```
|
||||
@ -369,7 +395,7 @@ rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int
|
||||
To compute the value, use `rc_evaluate_value`:
|
||||
|
||||
```c
|
||||
unsigned rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
||||
int rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
||||
```
|
||||
|
||||
`value` is the value to compute the value of, and `peek`, `ud`, and `L`, are as in [`rc_test_trigger`](#rc_test_trigger).
|
||||
@ -404,7 +430,7 @@ rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, in
|
||||
A leaderboard can be evaluated with the `rc_evaluate_lboard` function:
|
||||
|
||||
```c
|
||||
int rc_evaluate_lboard(rc_lboard_t* lboard, unsigned* value, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||
int rc_evaluate_lboard(rc_lboard_t* lboard, int* value, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||
```
|
||||
|
||||
The function returns an action that must be performed by the caller, and `value` contains the value to be used for that action when the function returns. The action can be one of:
|
||||
@ -451,7 +477,8 @@ enum {
|
||||
RC_FORMAT_CENTISECS,
|
||||
RC_FORMAT_SCORE,
|
||||
RC_FORMAT_VALUE,
|
||||
RC_FORMAT_OTHER,
|
||||
RC_FORMAT_MINUTES,
|
||||
RC_FORMAT_SECONDS_AS_MINUTES
|
||||
};
|
||||
```
|
||||
|
||||
@ -460,10 +487,10 @@ enum {
|
||||
`rc_format_value` can be used to format the given value into the provided buffer:
|
||||
|
||||
```c
|
||||
void rc_format_value(char* buffer, int size, unsigned value, int format);
|
||||
int rc_format_value(char* buffer, int size, int value, int format);
|
||||
```
|
||||
|
||||
`buffer` receives `value` formatted according to `format`. No more than `size` characters will be written to `buffer`. 32 characters are enough to hold any valid value with any format.
|
||||
`buffer` receives `value` formatted according to `format`. No more than `size` characters will be written to `buffer`. 32 characters are enough to hold any valid value with any format. The returned value is the number of characters written.
|
||||
|
||||
# **rurl**
|
||||
|
||||
|
65
deps/rcheevos/include/rcheevos.h
vendored
65
deps/rcheevos/include/rcheevos.h
vendored
@ -31,7 +31,11 @@ enum {
|
||||
RC_MISSING_VALUE = -16,
|
||||
RC_INVALID_LBOARD_FIELD = -17,
|
||||
RC_MISSING_DISPLAY_STRING = -18,
|
||||
RC_OUT_OF_MEMORY = -19
|
||||
RC_OUT_OF_MEMORY = -19,
|
||||
RC_INVALID_VALUE_FLAG = -20,
|
||||
RC_MISSING_VALUE_MEASURED = -21,
|
||||
RC_MULTIPLE_MEASURED = -22,
|
||||
RC_INVALID_MEASURED_TARGET = -23
|
||||
};
|
||||
|
||||
/*****************************************************************************\
|
||||
@ -112,6 +116,8 @@ typedef struct {
|
||||
char size;
|
||||
/* True if the value is in BCD. */
|
||||
char is_bcd;
|
||||
/* True if the reference will be used in indirection */
|
||||
char is_indirect;
|
||||
} rc_memref_t;
|
||||
|
||||
typedef struct rc_memref_value_t rc_memref_value_t;
|
||||
@ -176,7 +182,9 @@ enum {
|
||||
RC_CONDITION_ADD_SOURCE,
|
||||
RC_CONDITION_SUB_SOURCE,
|
||||
RC_CONDITION_ADD_HITS,
|
||||
RC_CONDITION_AND_NEXT
|
||||
RC_CONDITION_AND_NEXT,
|
||||
RC_CONDITION_MEASURED,
|
||||
RC_CONDITION_ADD_ADDRESS
|
||||
};
|
||||
|
||||
/* operators */
|
||||
@ -186,7 +194,8 @@ enum {
|
||||
RC_CONDITION_LE,
|
||||
RC_CONDITION_GT,
|
||||
RC_CONDITION_GE,
|
||||
RC_CONDITION_NE
|
||||
RC_CONDITION_NE,
|
||||
RC_CONDITION_NONE
|
||||
};
|
||||
|
||||
typedef struct rc_condition_t rc_condition_t;
|
||||
@ -204,16 +213,17 @@ struct rc_condition_t {
|
||||
/* The next condition in the chain. */
|
||||
rc_condition_t* next;
|
||||
|
||||
/**
|
||||
* Set if the condition needs to processed as part of the "check if paused"
|
||||
* pass
|
||||
*/
|
||||
char pause;
|
||||
|
||||
/* The type of the condition. */
|
||||
char type;
|
||||
|
||||
/* The comparison operator to use. */
|
||||
char oper; /* operator is a reserved word in C++. */
|
||||
|
||||
/* Set if the condition needs to processed as part of the "check if paused" pass. */
|
||||
char pause;
|
||||
|
||||
/* Whether or not the condition evaluated true on the last check */
|
||||
char is_true;
|
||||
};
|
||||
|
||||
/*****************************************************************************\
|
||||
@ -231,12 +241,24 @@ struct rc_condset_t {
|
||||
|
||||
/* True if any condition in the set is a pause condition. */
|
||||
char has_pause;
|
||||
|
||||
/* True if the set is currently paused. */
|
||||
char is_paused;
|
||||
};
|
||||
|
||||
/*****************************************************************************\
|
||||
| Trigger |
|
||||
\*****************************************************************************/
|
||||
|
||||
enum {
|
||||
RC_TRIGGER_STATE_INACTIVE, /* achievement is not being processed */
|
||||
RC_TRIGGER_STATE_WAITING, /* achievement cannot trigger until it has been false for at least one frame */
|
||||
RC_TRIGGER_STATE_ACTIVE, /* achievement is active and may trigger */
|
||||
RC_TRIGGER_STATE_PAUSED, /* achievement is currently paused and will not trigger */
|
||||
RC_TRIGGER_STATE_RESET, /* achievement hit counts were reset */
|
||||
RC_TRIGGER_STATE_TRIGGERED /* achievement has triggered */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
/* The main condition set. */
|
||||
rc_condset_t* requirement;
|
||||
@ -246,11 +268,24 @@ typedef struct {
|
||||
|
||||
/* The memory references required by the trigger. */
|
||||
rc_memref_value_t* memrefs;
|
||||
|
||||
/* The current state of the MEASURED condition. */
|
||||
unsigned measured_value;
|
||||
|
||||
/* The target state of the MEASURED condition */
|
||||
unsigned measured_target;
|
||||
|
||||
/* The current state of the trigger */
|
||||
char state;
|
||||
|
||||
/* True if at least one condition has a non-zero hit count */
|
||||
char has_hits;
|
||||
}
|
||||
rc_trigger_t;
|
||||
|
||||
int rc_trigger_size(const char* memaddr);
|
||||
rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
|
||||
int rc_evaluate_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
|
||||
int rc_test_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State* L);
|
||||
void rc_reset_trigger(rc_trigger_t* self);
|
||||
|
||||
@ -287,6 +322,9 @@ typedef struct {
|
||||
/* The list of expression to evaluate. */
|
||||
rc_expression_t* expressions;
|
||||
|
||||
/* The list of conditions to evaluate. */
|
||||
rc_condset_t* conditions;
|
||||
|
||||
/* The memory references required by the value. */
|
||||
rc_memref_value_t* memrefs;
|
||||
}
|
||||
@ -294,7 +332,7 @@ rc_value_t;
|
||||
|
||||
int rc_value_size(const char* memaddr);
|
||||
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
|
||||
unsigned rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
||||
int rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Leaderboards |
|
||||
@ -324,7 +362,7 @@ rc_lboard_t;
|
||||
|
||||
int rc_lboard_size(const char* memaddr);
|
||||
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
|
||||
int rc_evaluate_lboard(rc_lboard_t* lboard, unsigned* value, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||
int rc_evaluate_lboard(rc_lboard_t* lboard, int* value, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||
void rc_reset_lboard(rc_lboard_t* lboard);
|
||||
|
||||
/*****************************************************************************\
|
||||
@ -338,11 +376,12 @@ enum {
|
||||
RC_FORMAT_CENTISECS,
|
||||
RC_FORMAT_SCORE,
|
||||
RC_FORMAT_VALUE,
|
||||
RC_FORMAT_OTHER
|
||||
RC_FORMAT_MINUTES,
|
||||
RC_FORMAT_SECONDS_AS_MINUTES
|
||||
};
|
||||
|
||||
int rc_parse_format(const char* format_str);
|
||||
int rc_format_value(char* buffer, int size, unsigned value, int format);
|
||||
int rc_format_value(char* buffer, int size, int value, int format);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Rich Presence |
|
||||
|
2
deps/rcheevos/include/rurl.h
vendored
2
deps/rcheevos/include/rurl.h
vendored
@ -9,7 +9,7 @@ extern "C" {
|
||||
|
||||
int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned cheevo_id, int hardcore);
|
||||
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, unsigned value, unsigned char hash[16]);
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, unsigned char hash[16]);
|
||||
|
||||
int rc_url_get_gameid(char* buffer, size_t size, unsigned char hash[16]);
|
||||
|
||||
|
1
deps/rcheevos/src/rcheevos/alloc.c
vendored
1
deps/rcheevos/src/rcheevos/alloc.c
vendored
@ -44,6 +44,7 @@ void rc_init_parse_state(rc_parse_state_t* parse, void* buffer, lua_State* L, in
|
||||
parse->scratch.memref_size = sizeof(parse->scratch.memref_buffer) / sizeof(parse->scratch.memref_buffer[0]);
|
||||
parse->scratch.memref_count = 0;
|
||||
parse->first_memref = 0;
|
||||
parse->measured_target = 0;
|
||||
}
|
||||
|
||||
void rc_destroy_parse_state(rc_parse_state_t* parse)
|
||||
|
25
deps/rcheevos/src/rcheevos/condition.c
vendored
25
deps/rcheevos/src/rcheevos/condition.c
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect) {
|
||||
rc_condition_t* self;
|
||||
const char* aux;
|
||||
int ret2;
|
||||
@ -19,6 +19,8 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
case 'b': case 'B': self->type = RC_CONDITION_SUB_SOURCE; break;
|
||||
case 'c': case 'C': self->type = RC_CONDITION_ADD_HITS; break;
|
||||
case 'n': case 'N': self->type = RC_CONDITION_AND_NEXT; break;
|
||||
case 'm': case 'M': self->type = RC_CONDITION_MEASURED; break;
|
||||
case 'i': case 'I': self->type = RC_CONDITION_ADD_ADDRESS; break;
|
||||
default: parse->offset = RC_INVALID_CONDITION_TYPE; return 0;
|
||||
}
|
||||
|
||||
@ -28,7 +30,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
self->type = RC_CONDITION_STANDARD;
|
||||
}
|
||||
|
||||
ret2 = rc_parse_operand(&self->operand1, &aux, 1, parse);
|
||||
ret2 = rc_parse_operand(&self->operand1, &aux, 1, is_indirect, parse);
|
||||
|
||||
if (ret2 < 0) {
|
||||
parse->offset = ret2;
|
||||
@ -71,9 +73,19 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '_':
|
||||
case ')':
|
||||
case '\0':
|
||||
self->oper = RC_CONDITION_NONE;
|
||||
self->operand2.type = RC_OPERAND_CONST;
|
||||
self->operand2.value.num = 1;
|
||||
self->required_hits = 0;
|
||||
*memaddr = aux - 1;
|
||||
return self;
|
||||
}
|
||||
|
||||
ret2 = rc_parse_operand(&self->operand2, &aux, 1, parse);
|
||||
ret2 = rc_parse_operand(&self->operand2, &aux, 1, is_indirect, parse);
|
||||
|
||||
if (ret2 < 0) {
|
||||
parse->offset = ret2;
|
||||
@ -110,9 +122,9 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
return self;
|
||||
}
|
||||
|
||||
int rc_test_condition(rc_condition_t* self, unsigned add_buffer, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
unsigned value1 = rc_evaluate_operand(&self->operand1, peek, ud, L) + add_buffer;
|
||||
unsigned value2 = rc_evaluate_operand(&self->operand2, peek, ud, L);
|
||||
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
|
||||
unsigned value1 = rc_evaluate_operand(&self->operand1, eval_state) + eval_state->add_value;
|
||||
unsigned value2 = rc_evaluate_operand(&self->operand2, eval_state);
|
||||
|
||||
switch (self->oper) {
|
||||
case RC_CONDITION_EQ: return value1 == value2;
|
||||
@ -121,6 +133,7 @@ int rc_test_condition(rc_condition_t* self, unsigned add_buffer, rc_peek_t peek,
|
||||
case RC_CONDITION_LE: return value1 <= value2;
|
||||
case RC_CONDITION_GT: return value1 > value2;
|
||||
case RC_CONDITION_GE: return value1 >= value2;
|
||||
case RC_CONDITION_NONE: return 1;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
120
deps/rcheevos/src/rcheevos/condset.c
vendored
120
deps/rcheevos/src/rcheevos/condset.c
vendored
@ -14,6 +14,7 @@ static void rc_update_condition_pause(rc_condition_t* condition, int* in_pause)
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
condition->pause = *in_pause;
|
||||
break;
|
||||
|
||||
@ -27,9 +28,10 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_condset_t* self;
|
||||
rc_condition_t** next;
|
||||
int in_pause;
|
||||
int in_add_address;
|
||||
|
||||
self = RC_ALLOC(rc_condset_t, parse);
|
||||
self->has_pause = 0;
|
||||
self->has_pause = self->is_paused = 0;
|
||||
next = &self->conditions;
|
||||
|
||||
if (**memaddr == 'S' || **memaddr == 's' || !**memaddr) {
|
||||
@ -38,14 +40,54 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
|
||||
return self;
|
||||
}
|
||||
|
||||
in_add_address = 0;
|
||||
for (;;) {
|
||||
*next = rc_parse_condition(memaddr, parse);
|
||||
*next = rc_parse_condition(memaddr, parse, in_add_address);
|
||||
|
||||
if (parse->offset < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((*next)->oper == RC_CONDITION_NONE) {
|
||||
switch ((*next)->type) {
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
case RC_CONDITION_ADD_SOURCE:
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
break;
|
||||
|
||||
default:
|
||||
parse->offset = RC_INVALID_OPERATOR;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
self->has_pause |= (*next)->type == RC_CONDITION_PAUSE_IF;
|
||||
in_add_address = (*next)->type == RC_CONDITION_ADD_ADDRESS;
|
||||
|
||||
if ((*next)->type == RC_CONDITION_MEASURED) {
|
||||
unsigned measured_target = 0;
|
||||
if ((*next)->required_hits == 0) {
|
||||
if ((*next)->operand2.type != RC_OPERAND_CONST) {
|
||||
parse->offset = RC_INVALID_MEASURED_TARGET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
measured_target = (*next)->operand2.value.num;
|
||||
}
|
||||
else {
|
||||
measured_target = (*next)->required_hits;
|
||||
}
|
||||
|
||||
if (parse->measured_target && measured_target != parse->measured_target) {
|
||||
parse->offset = RC_MULTIPLE_MEASURED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
parse->measured_target = measured_target;
|
||||
}
|
||||
|
||||
next = &(*next)->next;
|
||||
|
||||
if (**memaddr != '_') {
|
||||
@ -66,14 +108,13 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
|
||||
return self;
|
||||
}
|
||||
|
||||
static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, int* reset, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc_eval_state_t* eval_state) {
|
||||
rc_condition_t* condition;
|
||||
int set_valid, cond_valid, prev_cond;
|
||||
unsigned add_buffer, add_hits;
|
||||
|
||||
set_valid = 1;
|
||||
prev_cond = 1;
|
||||
add_buffer = add_hits = 0;
|
||||
eval_state->add_value = eval_state->add_hits = eval_state->add_address = 0;
|
||||
|
||||
for (condition = self->conditions; condition != 0; condition = condition->next) {
|
||||
if (condition->pause != processing_pause) {
|
||||
@ -82,39 +123,60 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, in
|
||||
|
||||
switch (condition->type) {
|
||||
case RC_CONDITION_ADD_SOURCE:
|
||||
add_buffer += rc_evaluate_operand(&condition->operand1, peek, ud, L);
|
||||
eval_state->add_value += rc_evaluate_operand(&condition->operand1, eval_state);
|
||||
eval_state->add_address = 0;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
add_buffer -= rc_evaluate_operand(&condition->operand1, peek, ud, L);
|
||||
eval_state->add_value -= rc_evaluate_operand(&condition->operand1, eval_state);
|
||||
eval_state->add_address = 0;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
if (rc_test_condition(condition, add_buffer, peek, ud, L)) {
|
||||
/* always evaluate the condition to ensure everything is updated correctly */
|
||||
cond_valid = rc_test_condition(condition, eval_state);
|
||||
|
||||
/* merge AndNext value and reset it for the next condition */
|
||||
cond_valid &= prev_cond;
|
||||
prev_cond = 1;
|
||||
|
||||
/* if the condition is true, tally it */
|
||||
if (cond_valid) {
|
||||
if (condition->required_hits == 0 || condition->current_hits < condition->required_hits) {
|
||||
condition->current_hits++;
|
||||
}
|
||||
|
||||
condition->is_true = (condition->required_hits == 0 || condition->current_hits >= condition->required_hits);
|
||||
}
|
||||
else {
|
||||
condition->is_true = 0;
|
||||
}
|
||||
|
||||
add_buffer = 0;
|
||||
add_hits += condition->current_hits;
|
||||
eval_state->add_value = 0;
|
||||
eval_state->add_address = 0;
|
||||
eval_state->add_hits += condition->current_hits;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
prev_cond &= rc_test_condition(condition, add_buffer, peek, ud, L);
|
||||
add_buffer = 0;
|
||||
prev_cond &= rc_test_condition(condition, eval_state);
|
||||
eval_state->add_value = 0;
|
||||
eval_state->add_address = 0;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
eval_state->add_address = rc_evaluate_operand(&condition->operand1, eval_state);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* always evaluate the condition to ensure delta values get tracked correctly */
|
||||
cond_valid = rc_test_condition(condition, add_buffer, peek, ud, L);
|
||||
/* always evaluate the condition to ensure everything is updated correctly */
|
||||
cond_valid = rc_test_condition(condition, eval_state);
|
||||
|
||||
/* merge AndNext value and reset it for the next condition */
|
||||
cond_valid &= prev_cond;
|
||||
prev_cond = 1;
|
||||
|
||||
/* if the condition has a target hit count that has already been met, it's automatically true, even if not currently true. */
|
||||
if (condition->required_hits != 0 && (condition->current_hits + add_hits) >= condition->required_hits) {
|
||||
if (condition->required_hits != 0 && (condition->current_hits + eval_state->add_hits) >= condition->required_hits) {
|
||||
cond_valid = 1;
|
||||
}
|
||||
else if (cond_valid) {
|
||||
@ -123,14 +185,28 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, in
|
||||
if (condition->required_hits == 0) {
|
||||
/* not a hit-based requirement: ignore any additional logic! */
|
||||
}
|
||||
else if ((condition->current_hits + add_hits) < condition->required_hits) {
|
||||
else if ((condition->current_hits + eval_state->add_hits) < condition->required_hits) {
|
||||
/* HitCount target has not yet been met, condition is not yet valid */
|
||||
cond_valid = 0;
|
||||
}
|
||||
}
|
||||
condition->is_true = cond_valid;
|
||||
eval_state->has_hits |= (condition->current_hits || eval_state->add_hits);
|
||||
|
||||
/* capture measured state */
|
||||
if (condition->type == RC_CONDITION_MEASURED) {
|
||||
unsigned int measured_value;
|
||||
if (condition->required_hits > 0)
|
||||
measured_value = condition->current_hits + eval_state->add_hits;
|
||||
else
|
||||
measured_value = rc_evaluate_operand(&condition->operand1, eval_state) + eval_state->add_value;
|
||||
|
||||
if (measured_value > eval_state->measured_value)
|
||||
eval_state->measured_value = measured_value;
|
||||
}
|
||||
|
||||
/* reset AddHits and AddSource/SubSource values */
|
||||
add_buffer = add_hits = 0;
|
||||
eval_state->add_value = eval_state->add_hits = eval_state->add_address = 0;
|
||||
|
||||
switch (condition->type) {
|
||||
case RC_CONDITION_PAUSE_IF:
|
||||
@ -155,7 +231,7 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, in
|
||||
|
||||
case RC_CONDITION_RESET_IF:
|
||||
if (cond_valid) {
|
||||
*reset = 1; /* let caller know to reset all hit counts */
|
||||
eval_state->was_reset = 1; /* let caller know to reset all hit counts */
|
||||
set_valid = 0; /* cannot be valid if we've hit a reset condition */
|
||||
}
|
||||
|
||||
@ -170,18 +246,20 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, in
|
||||
return set_valid;
|
||||
}
|
||||
|
||||
int rc_test_condset(rc_condset_t* self, int* reset, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state) {
|
||||
if (self->conditions == 0) {
|
||||
/* important: empty group must evaluate true */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (self->has_pause && rc_test_condset_internal(self, 1, reset, peek, ud, L)) {
|
||||
if (self->has_pause) {
|
||||
if ((self->is_paused = rc_test_condset_internal(self, 1, eval_state))) {
|
||||
/* one or more Pause conditions exists, if any of them are true, stop processing this group */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc_test_condset_internal(self, 0, reset, peek, ud, L);
|
||||
return rc_test_condset_internal(self, 0, eval_state);
|
||||
}
|
||||
|
||||
void rc_reset_condset(rc_condset_t* self) {
|
||||
|
8
deps/rcheevos/src/rcheevos/expression.c
vendored
8
deps/rcheevos/src/rcheevos/expression.c
vendored
@ -8,7 +8,7 @@ rc_expression_t* rc_parse_expression(const char** memaddr, rc_parse_state_t* par
|
||||
next = &self->terms;
|
||||
|
||||
for (;;) {
|
||||
*next = rc_parse_term(memaddr, parse);
|
||||
*next = rc_parse_term(memaddr, 0, parse);
|
||||
|
||||
if (parse->offset < 0) {
|
||||
return 0;
|
||||
@ -27,14 +27,14 @@ rc_expression_t* rc_parse_expression(const char** memaddr, rc_parse_state_t* par
|
||||
return self;
|
||||
}
|
||||
|
||||
unsigned rc_evaluate_expression(rc_expression_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
int rc_evaluate_expression(rc_expression_t* self, rc_eval_state_t* eval_state) {
|
||||
rc_term_t* term;
|
||||
unsigned value;
|
||||
int value;
|
||||
|
||||
value = 0;
|
||||
|
||||
for (term = self->terms; term != 0; term = term->next) {
|
||||
value += rc_evaluate_term(term, peek, ud, L);
|
||||
value += rc_evaluate_term(term, eval_state);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
91
deps/rcheevos/src/rcheevos/format.c
vendored
91
deps/rcheevos/src/rcheevos/format.c
vendored
@ -29,6 +29,9 @@ int rc_parse_format(const char* format_str) {
|
||||
if (!strcmp(format_str, "CORE")) {
|
||||
return RC_FORMAT_SCORE;
|
||||
}
|
||||
if (!strcmp(format_str, "ECS_AS_MINS")) {
|
||||
return RC_FORMAT_SECONDS_AS_MINUTES;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -36,6 +39,9 @@ int rc_parse_format(const char* format_str) {
|
||||
if (!strcmp(format_str, "ILLISECS")) {
|
||||
return RC_FORMAT_CENTISECS;
|
||||
}
|
||||
if (!strcmp(format_str, "INUTES")) {
|
||||
return RC_FORMAT_MINUTES;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -55,7 +61,7 @@ int rc_parse_format(const char* format_str) {
|
||||
|
||||
case 'O':
|
||||
if (!strcmp(format_str, "THER")) {
|
||||
return RC_FORMAT_OTHER;
|
||||
return RC_FORMAT_SCORE;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -64,45 +70,82 @@ int rc_parse_format(const char* format_str) {
|
||||
return RC_FORMAT_VALUE;
|
||||
}
|
||||
|
||||
int rc_format_value(char* buffer, int size, unsigned value, int format) {
|
||||
unsigned a, b, c;
|
||||
static int rc_format_value_minutes(char* buffer, int size, unsigned minutes) {
|
||||
unsigned hours;
|
||||
|
||||
hours = minutes / 60;
|
||||
minutes -= hours * 60;
|
||||
return snprintf(buffer, size, "%uh%02u", hours, minutes);
|
||||
}
|
||||
|
||||
static int rc_format_value_seconds(char* buffer, int size, unsigned seconds) {
|
||||
unsigned hours, minutes;
|
||||
|
||||
/* apply modulus math to split the seconds into hours/minutes/seconds */
|
||||
minutes = seconds / 60;
|
||||
seconds -= minutes * 60;
|
||||
if (minutes < 60) {
|
||||
return snprintf(buffer, size, "%u:%02u", minutes, seconds);
|
||||
}
|
||||
|
||||
hours = minutes / 60;
|
||||
minutes -= hours * 60;
|
||||
return snprintf(buffer, size, "%uh%02u:%02u", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
static int rc_format_value_centiseconds(char* buffer, int size, unsigned centiseconds) {
|
||||
unsigned seconds;
|
||||
int chars, chars2;
|
||||
|
||||
/* modulus off the centiseconds */
|
||||
seconds = centiseconds / 100;
|
||||
centiseconds -= seconds * 100;
|
||||
|
||||
chars = rc_format_value_seconds(buffer, size, seconds);
|
||||
if (chars > 0) {
|
||||
chars2 = snprintf(buffer + chars, size - chars, ".%02u", centiseconds);
|
||||
if (chars2 > 0) {
|
||||
chars += chars2;
|
||||
} else {
|
||||
chars = chars2;
|
||||
}
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
int rc_format_value(char* buffer, int size, int value, int format) {
|
||||
int chars;
|
||||
|
||||
switch (format) {
|
||||
case RC_FORMAT_FRAMES:
|
||||
a = value * 10 / 6; /* centisecs */
|
||||
b = a / 100; /* seconds */
|
||||
a -= b * 100;
|
||||
c = b / 60; /* minutes */
|
||||
b -= c * 60;
|
||||
chars = snprintf(buffer, size, "%02u:%02u.%02u", c, b, a);
|
||||
/* 60 frames per second = 100 centiseconds / 60 frames; multiply frames by 100 / 60 */
|
||||
chars = rc_format_value_centiseconds(buffer, size, value * 10 / 6);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_SECONDS:
|
||||
a = value / 60; /* minutes */
|
||||
value -= a * 60;
|
||||
chars = snprintf(buffer, size, "%02u:%02u", a, value);
|
||||
chars = rc_format_value_seconds(buffer, size, value);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_CENTISECS:
|
||||
a = value / 100; /* seconds */
|
||||
value -= a * 100;
|
||||
b = a / 60; /* minutes */
|
||||
a -= b * 60;
|
||||
chars = snprintf(buffer, size, "%02u:%02u.%02u", b, a, value);
|
||||
chars = rc_format_value_centiseconds(buffer, size, value);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_SECONDS_AS_MINUTES:
|
||||
chars = rc_format_value_minutes(buffer, size, value / 60);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_MINUTES:
|
||||
chars = rc_format_value_minutes(buffer, size, value);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_SCORE:
|
||||
chars = snprintf(buffer, size, "%06u Points", value);
|
||||
chars = snprintf(buffer, size, "%06d", value);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_VALUE:
|
||||
chars = snprintf(buffer, size, "%01u", value);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_OTHER:
|
||||
default:
|
||||
chars = snprintf(buffer, size, "%06u", value);
|
||||
case RC_FORMAT_VALUE:
|
||||
chars = snprintf(buffer, size, "%d", value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
42
deps/rcheevos/src/rcheevos/internal.h
vendored
42
deps/rcheevos/src/rcheevos/internal.h
vendored
@ -1,8 +1,7 @@
|
||||
#ifndef INTERNAL_H
|
||||
#define INTERNAL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <rcheevos.h>
|
||||
#include "rcheevos.h"
|
||||
|
||||
#define RC_ALLOW_ALIGN(T) struct __align_ ## T { char ch; T t; };
|
||||
RC_ALLOW_ALIGN(rc_condition_t)
|
||||
@ -21,8 +20,6 @@ RC_ALLOW_ALIGN(rc_trigger_t)
|
||||
RC_ALLOW_ALIGN(rc_value_t)
|
||||
RC_ALLOW_ALIGN(char)
|
||||
|
||||
#define RC_TAG2(x,y) x ## y
|
||||
#define RC_TAG(x,y) RC_TAG2(x,y)
|
||||
#define RC_ALIGNOF(T) (sizeof(struct __align_ ## T) - sizeof(T))
|
||||
|
||||
#define RC_ALLOC(t, p) ((t*)rc_alloc((p)->buffer, &(p)->offset, sizeof(t), RC_ALIGNOF(t), &(p)->scratch))
|
||||
@ -52,6 +49,21 @@ typedef struct {
|
||||
}
|
||||
rc_scratch_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned add_value; /* AddSource/SubSource */
|
||||
unsigned add_hits; /* AddHits */
|
||||
unsigned add_address; /* AddAddress */
|
||||
|
||||
rc_peek_t peek;
|
||||
void* peek_userdata;
|
||||
lua_State* L;
|
||||
|
||||
unsigned measured_value; /* Measured */
|
||||
char was_reset; /* ResetIf triggered */
|
||||
char has_hits; /* one of more hit counts is non-zero */
|
||||
}
|
||||
rc_eval_state_t;
|
||||
|
||||
typedef struct {
|
||||
int offset;
|
||||
|
||||
@ -62,6 +74,8 @@ typedef struct {
|
||||
rc_scratch_t scratch;
|
||||
|
||||
rc_memref_value_t** first_memref;
|
||||
|
||||
unsigned measured_target;
|
||||
}
|
||||
rc_parse_state_t;
|
||||
|
||||
@ -72,26 +86,28 @@ void rc_destroy_parse_state(rc_parse_state_t* parse);
|
||||
void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch);
|
||||
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, int length);
|
||||
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_bcd);
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect);
|
||||
void rc_update_memref_values(rc_memref_value_t* memref, rc_peek_t peek, void* ud);
|
||||
void rc_update_memref_value(rc_memref_value_t* memref, rc_peek_t peek, void* ud);
|
||||
rc_memref_value_t* rc_get_indirect_memref(rc_memref_value_t* memref, rc_eval_state_t* eval_state);
|
||||
|
||||
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse);
|
||||
|
||||
rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse);
|
||||
int rc_test_condset(rc_condset_t* self, int* reset, rc_peek_t peek, void* ud, lua_State* L);
|
||||
int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state);
|
||||
void rc_reset_condset(rc_condset_t* self);
|
||||
|
||||
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse);
|
||||
int rc_test_condition(rc_condition_t* self, unsigned add_buffer, rc_peek_t peek, void* ud, lua_State* L);
|
||||
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_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, rc_parse_state_t* parse);
|
||||
unsigned rc_evaluate_operand(rc_operand_t* self, rc_peek_t peek, void* ud, lua_State* L);
|
||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, int is_indirect, rc_parse_state_t* parse);
|
||||
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state);
|
||||
|
||||
rc_term_t* rc_parse_term(const char** memaddr, rc_parse_state_t* parse);
|
||||
unsigned rc_evaluate_term(rc_term_t* self, rc_peek_t peek, void* ud, lua_State* L);
|
||||
rc_term_t* rc_parse_term(const char** memaddr, int is_indirect, rc_parse_state_t* parse);
|
||||
int rc_evaluate_term(rc_term_t* self, rc_eval_state_t* eval_state);
|
||||
|
||||
rc_expression_t* rc_parse_expression(const char** memaddr, rc_parse_state_t* parse);
|
||||
unsigned rc_evaluate_expression(rc_expression_t* self, rc_peek_t peek, void* ud, lua_State* L);
|
||||
int rc_evaluate_expression(rc_expression_t* self, rc_eval_state_t* eval_state);
|
||||
|
||||
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse);
|
||||
|
||||
|
7
deps/rcheevos/src/rcheevos/lboard.c
vendored
7
deps/rcheevos/src/rcheevos/lboard.c
vendored
@ -162,7 +162,7 @@ rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, in
|
||||
return parse.offset >= 0 ? self : 0;
|
||||
}
|
||||
|
||||
int rc_evaluate_lboard(rc_lboard_t* self, unsigned* value, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
||||
int rc_evaluate_lboard(rc_lboard_t* self, int* value, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
||||
int start_ok, cancel_ok, submit_ok;
|
||||
int action = -1;
|
||||
|
||||
@ -217,8 +217,11 @@ int rc_evaluate_lboard(rc_lboard_t* self, unsigned* value, rc_peek_t peek, void*
|
||||
|
||||
/* Calculate the value */
|
||||
switch (action) {
|
||||
case RC_LBOARD_ACTIVE: /* fall through */
|
||||
case RC_LBOARD_STARTED:
|
||||
if (self->value.conditions)
|
||||
rc_reset_condset(self->value.conditions);
|
||||
/* fall through */
|
||||
case RC_LBOARD_ACTIVE:
|
||||
*value = rc_evaluate_value(self->progress != 0 ? self->progress : &self->value, peek, peek_ud, L);
|
||||
break;
|
||||
|
||||
|
103
deps/rcheevos/src/rcheevos/memref.c
vendored
103
deps/rcheevos/src/rcheevos/memref.c
vendored
@ -3,14 +3,21 @@
|
||||
#include <stdlib.h> /* malloc/realloc */
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_bcd) {
|
||||
rc_memref_value_t** next_memref_value;
|
||||
rc_memref_value_t* memref_value;
|
||||
#define MEMREF_PLACEHOLDER_ADDRESS 0xFFFFFFFF
|
||||
|
||||
static rc_memref_value_t* rc_alloc_memref_value_sizing_mode(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect) {
|
||||
rc_memref_t* memref;
|
||||
int i;
|
||||
|
||||
if (!parse->first_memref) {
|
||||
/* sizing mode - have to track unique address/size/bcd combinations */
|
||||
/* indirect address always creates two new entries; don't bother tracking them */
|
||||
if (is_indirect) {
|
||||
RC_ALLOC(rc_memref_value_t, parse);
|
||||
return RC_ALLOC(rc_memref_value_t, parse);
|
||||
}
|
||||
|
||||
memref = NULL;
|
||||
|
||||
/* have to track unique address/size/bcd combinations - use scratch.memref for sizing mode */
|
||||
for (i = 0; i < parse->scratch.memref_count; ++i) {
|
||||
memref = &parse->scratch.memref[i];
|
||||
if (memref->address == address && memref->size == size && memref->is_bcd == is_bcd) {
|
||||
@ -18,7 +25,7 @@ rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned addre
|
||||
}
|
||||
}
|
||||
|
||||
/* resize unique tracking buffer if necessary */
|
||||
/* no match found - resize unique tracking buffer if necessary */
|
||||
if (parse->scratch.memref_count == parse->scratch.memref_size) {
|
||||
if (parse->scratch.memref == parse->scratch.memref_buffer) {
|
||||
parse->scratch.memref_size += 16;
|
||||
@ -51,27 +58,46 @@ rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned addre
|
||||
memref->address = address;
|
||||
memref->size = size;
|
||||
memref->is_bcd = is_bcd;
|
||||
memref->is_indirect = is_indirect;
|
||||
}
|
||||
|
||||
/* allocate memory but don't actually populate, as it might overwrite the self object referencing the rc_memref_value_t */
|
||||
return RC_ALLOC(rc_memref_value_t, parse);
|
||||
}
|
||||
}
|
||||
|
||||
/* construction mode - find or create the appropriate rc_memref_value_t */
|
||||
static rc_memref_value_t* rc_alloc_memref_value_constuct_mode(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect) {
|
||||
rc_memref_value_t** next_memref_value;
|
||||
rc_memref_value_t* memref_value;
|
||||
rc_memref_value_t* indirect_memref_value;
|
||||
|
||||
if (!is_indirect) {
|
||||
/* attempt to find an existing rc_memref_value_t */
|
||||
next_memref_value = parse->first_memref;
|
||||
while (*next_memref_value) {
|
||||
memref_value = *next_memref_value;
|
||||
if (memref_value->memref.address == address && memref_value->memref.size == size && memref_value->memref.is_bcd == is_bcd) {
|
||||
if (!memref_value->memref.is_indirect && memref_value->memref.address == address &&
|
||||
memref_value->memref.size == size && memref_value->memref.is_bcd == is_bcd) {
|
||||
return memref_value;
|
||||
}
|
||||
|
||||
next_memref_value = &memref_value->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* indirect address always creates two new entries - one for the original address, and one for
|
||||
the indirect dereference - just skip ahead to the end of the list */
|
||||
next_memref_value = parse->first_memref;
|
||||
while (*next_memref_value) {
|
||||
next_memref_value = &(*next_memref_value)->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* no match found, create a new entry */
|
||||
memref_value = RC_ALLOC(rc_memref_value_t, parse);
|
||||
memref_value->memref.address = address;
|
||||
memref_value->memref.size = size;
|
||||
memref_value->memref.is_bcd = is_bcd;
|
||||
memref_value->memref.is_indirect = is_indirect;
|
||||
memref_value->value = 0;
|
||||
memref_value->previous = 0;
|
||||
memref_value->prior = 0;
|
||||
@ -79,9 +105,31 @@ rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned addre
|
||||
|
||||
*next_memref_value = memref_value;
|
||||
|
||||
/* also create the indirect deference entry for indirect references */
|
||||
if (is_indirect) {
|
||||
indirect_memref_value = RC_ALLOC(rc_memref_value_t, parse);
|
||||
indirect_memref_value->memref.address = MEMREF_PLACEHOLDER_ADDRESS;
|
||||
indirect_memref_value->memref.size = size;
|
||||
indirect_memref_value->memref.is_bcd = is_bcd;
|
||||
indirect_memref_value->memref.is_indirect = 1;
|
||||
indirect_memref_value->value = 0;
|
||||
indirect_memref_value->previous = 0;
|
||||
indirect_memref_value->prior = 0;
|
||||
indirect_memref_value->next = 0;
|
||||
|
||||
memref_value->next = indirect_memref_value;
|
||||
}
|
||||
|
||||
return memref_value;
|
||||
}
|
||||
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect) {
|
||||
if (!parse->first_memref)
|
||||
return rc_alloc_memref_value_sizing_mode(parse, address, size, is_bcd, is_indirect);
|
||||
|
||||
return rc_alloc_memref_value_constuct_mode(parse, address, size, is_bcd, is_indirect);
|
||||
}
|
||||
|
||||
static unsigned rc_memref_get_value(rc_memref_t* self, rc_peek_t peek, void* ud) {
|
||||
unsigned value;
|
||||
|
||||
@ -149,6 +197,7 @@ static unsigned rc_memref_get_value(rc_memref_t* self, rc_peek_t peek, void* ud)
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_24_BITS:
|
||||
/* peek 4 bytes - don't expect the caller to understand 24-bit numbers */
|
||||
value = peek(self->address, 4, ud);
|
||||
|
||||
if (self->is_bcd) {
|
||||
@ -158,6 +207,8 @@ static unsigned rc_memref_get_value(rc_memref_t* self, rc_peek_t peek, void* ud)
|
||||
+ ((value >> 8) & 0x0f) * 100
|
||||
+ ((value >> 4) & 0x0f) * 10
|
||||
+ ((value >> 0) & 0x0f) * 1;
|
||||
} else {
|
||||
value &= 0x00FFFFFF;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -186,19 +237,45 @@ static unsigned rc_memref_get_value(rc_memref_t* self, rc_peek_t peek, void* ud)
|
||||
return value;
|
||||
}
|
||||
|
||||
void rc_update_memref_values(rc_memref_value_t* memref, rc_peek_t peek, void* ud) {
|
||||
while (memref) {
|
||||
void rc_update_memref_value(rc_memref_value_t* memref, rc_peek_t peek, void* ud) {
|
||||
memref->previous = memref->value;
|
||||
memref->value = rc_memref_get_value(&memref->memref, peek, ud);
|
||||
if (memref->value != memref->previous)
|
||||
memref->prior = memref->previous;
|
||||
}
|
||||
|
||||
void rc_update_memref_values(rc_memref_value_t* memref, rc_peek_t peek, void* ud) {
|
||||
while (memref) {
|
||||
if (memref->memref.address != MEMREF_PLACEHOLDER_ADDRESS)
|
||||
rc_update_memref_value(memref, peek, ud);
|
||||
memref = memref->next;
|
||||
}
|
||||
}
|
||||
|
||||
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_value_t** memrefs)
|
||||
{
|
||||
void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_value_t** memrefs) {
|
||||
parse->first_memref = memrefs;
|
||||
*memrefs = 0;
|
||||
}
|
||||
|
||||
rc_memref_value_t* rc_get_indirect_memref(rc_memref_value_t* memref, rc_eval_state_t* eval_state) {
|
||||
unsigned new_address;
|
||||
|
||||
if (eval_state->add_address == 0)
|
||||
return memref;
|
||||
|
||||
if (!memref->memref.is_indirect)
|
||||
return memref;
|
||||
|
||||
new_address = memref->memref.address + eval_state->add_address;
|
||||
|
||||
/* an extra rc_memref_value_t is allocated for offset calculations */
|
||||
memref = memref->next;
|
||||
|
||||
/* if the adjusted address has changed, update the record */
|
||||
if (memref->memref.address != new_address) {
|
||||
memref->memref.address = new_address;
|
||||
rc_update_memref_value(memref, eval_state->peek, eval_state->peek_userdata);
|
||||
}
|
||||
|
||||
return memref;
|
||||
}
|
||||
|
62
deps/rcheevos/src/rcheevos/operand.c
vendored
62
deps/rcheevos/src/rcheevos/operand.c
vendored
@ -66,7 +66,7 @@ static int rc_parse_operand_lua(rc_operand_t* self, const char** memaddr, rc_par
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse, int is_indirect) {
|
||||
const char* aux = *memaddr;
|
||||
char* end;
|
||||
unsigned long address;
|
||||
@ -135,7 +135,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
address = 0xffffffffU;
|
||||
}
|
||||
|
||||
self->value.memref = rc_alloc_memref_value(parse, (unsigned)address, size, is_bcd);
|
||||
self->value.memref = rc_alloc_memref_value(parse, address, size, is_bcd, is_indirect);
|
||||
if (parse->offset < 0)
|
||||
return parse->offset;
|
||||
|
||||
@ -143,7 +143,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_parse_operand_trigger(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
static int rc_parse_operand_trigger(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
|
||||
const char* aux = *memaddr;
|
||||
char* end;
|
||||
int ret;
|
||||
@ -151,6 +151,11 @@ static int rc_parse_operand_trigger(rc_operand_t* self, const char** memaddr, rc
|
||||
|
||||
switch (*aux) {
|
||||
case 'h': case 'H':
|
||||
if (aux[2] == 'x' || aux[2] == 'X') {
|
||||
/* H0x1234 is a typo - either H1234 or 0xH1234 was probably meant */
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
}
|
||||
|
||||
value = strtoul(++aux, &end, 16);
|
||||
|
||||
if (end == aux) {
|
||||
@ -171,7 +176,7 @@ static int rc_parse_operand_trigger(rc_operand_t* self, const char** memaddr, rc
|
||||
if (aux[1] == 'x' || aux[1] == 'X') {
|
||||
/* fall through */
|
||||
default:
|
||||
ret = rc_parse_operand_memory(self, &aux, parse);
|
||||
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -214,11 +219,12 @@ static int rc_parse_operand_trigger(rc_operand_t* self, const char** memaddr, rc
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
|
||||
const char* aux = *memaddr;
|
||||
char* end;
|
||||
int ret;
|
||||
unsigned long value;
|
||||
long svalue;
|
||||
|
||||
switch (*aux) {
|
||||
case 'h': case 'H':
|
||||
@ -239,18 +245,18 @@ static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, rc_pa
|
||||
break;
|
||||
|
||||
case 'v': case 'V':
|
||||
value = strtoul(++aux, &end, 10);
|
||||
svalue = strtol(++aux, &end, 10);
|
||||
|
||||
if (end == aux) {
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
}
|
||||
|
||||
if (value > 0xffffffffU) {
|
||||
value = 0xffffffffU;
|
||||
if (svalue > 0xffffffffU) {
|
||||
svalue = 0xffffffffU;
|
||||
}
|
||||
|
||||
self->type = RC_OPERAND_CONST;
|
||||
self->value.num = (unsigned)value;
|
||||
self->value.num = (unsigned)svalue;
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
@ -259,7 +265,7 @@ static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, rc_pa
|
||||
if (aux[1] == 'x' || aux[1] == 'X') {
|
||||
/* fall through */
|
||||
default:
|
||||
ret = rc_parse_operand_memory(self, &aux, parse);
|
||||
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
@ -303,12 +309,12 @@ static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, rc_pa
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, rc_parse_state_t* parse) {
|
||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, int is_indirect, rc_parse_state_t* parse) {
|
||||
if (is_trigger) {
|
||||
return rc_parse_operand_trigger(self, memaddr, parse);
|
||||
return rc_parse_operand_trigger(self, memaddr, is_indirect, parse);
|
||||
}
|
||||
else {
|
||||
return rc_parse_operand_term(self, memaddr, parse);
|
||||
return rc_parse_operand_term(self, memaddr, is_indirect, parse);
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,7 +339,7 @@ static int rc_luapeek(lua_State* L) {
|
||||
|
||||
#endif /* RC_DISABLE_LUA */
|
||||
|
||||
unsigned rc_evaluate_operand(rc_operand_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
#ifndef RC_DISABLE_LUA
|
||||
rc_luapeek_t luapeek;
|
||||
#endif /* RC_DISABLE_LUA */
|
||||
@ -352,25 +358,25 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_peek_t peek, void* ud, lua_S
|
||||
case RC_OPERAND_LUA:
|
||||
#ifndef RC_DISABLE_LUA
|
||||
|
||||
if (L != 0) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, self->value.luafunc);
|
||||
lua_pushcfunction(L, rc_luapeek);
|
||||
if (eval_state->L != 0) {
|
||||
lua_rawgeti(eval_state->L, LUA_REGISTRYINDEX, self->value.luafunc);
|
||||
lua_pushcfunction(eval_state->L, rc_luapeek);
|
||||
|
||||
luapeek.peek = peek;
|
||||
luapeek.ud = ud;
|
||||
luapeek.peek = eval_state->peek;
|
||||
luapeek.ud = eval_state->peek_userdata;
|
||||
|
||||
lua_pushlightuserdata(L, &luapeek);
|
||||
lua_pushlightuserdata(eval_state->L, &luapeek);
|
||||
|
||||
if (lua_pcall(L, 2, 1, 0) == LUA_OK) {
|
||||
if (lua_isboolean(L, -1)) {
|
||||
value = lua_toboolean(L, -1);
|
||||
if (lua_pcall(eval_state->L, 2, 1, 0) == LUA_OK) {
|
||||
if (lua_isboolean(eval_state->L, -1)) {
|
||||
value = lua_toboolean(eval_state->L, -1);
|
||||
}
|
||||
else {
|
||||
value = (unsigned)lua_tonumber(L, -1);
|
||||
value = (unsigned)lua_tonumber(eval_state->L, -1);
|
||||
}
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
lua_pop(eval_state->L, 1);
|
||||
}
|
||||
|
||||
#endif /* RC_DISABLE_LUA */
|
||||
@ -378,15 +384,15 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_peek_t peek, void* ud, lua_S
|
||||
break;
|
||||
|
||||
case RC_OPERAND_ADDRESS:
|
||||
value = self->value.memref->value;
|
||||
value = rc_get_indirect_memref(self->value.memref, eval_state)->value;
|
||||
break;
|
||||
|
||||
case RC_OPERAND_DELTA:
|
||||
value = self->value.memref->previous;
|
||||
value = rc_get_indirect_memref(self->value.memref, eval_state)->previous;
|
||||
break;
|
||||
|
||||
case RC_OPERAND_PRIOR:
|
||||
value = self->value.memref->prior;
|
||||
value = rc_get_indirect_memref(self->value.memref, eval_state)->prior;
|
||||
break;
|
||||
}
|
||||
|
||||
|
23
deps/rcheevos/src/rcheevos/richpresence.c
vendored
23
deps/rcheevos/src/rcheevos/richpresence.c
vendored
@ -51,8 +51,10 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
|
||||
const char* in;
|
||||
char* out;
|
||||
|
||||
if (endline - line < 1)
|
||||
if (endline - line < 1) {
|
||||
parse->offset = RC_MISSING_DISPLAY_STRING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
self = RC_ALLOC(rc_richpresence_display_t, parse);
|
||||
@ -103,6 +105,11 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
|
||||
while (ptr < endline && *ptr != '(')
|
||||
++ptr;
|
||||
|
||||
if (ptr == endline) {
|
||||
parse->offset = RC_MISSING_VALUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ptr > line) {
|
||||
if (!parse->buffer) {
|
||||
/* just calculating size, can't confirm lookup exists */
|
||||
@ -179,6 +186,7 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
|
||||
const char* line;
|
||||
const char* endline;
|
||||
const char* defaultlabel = 0;
|
||||
char* endptr = 0;
|
||||
unsigned key;
|
||||
int chars;
|
||||
|
||||
@ -208,9 +216,14 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
|
||||
}
|
||||
|
||||
if (number[0] == '0' && number[1] == 'x')
|
||||
key = (unsigned)strtoul(&number[2], 0, 16);
|
||||
key = strtoul(&number[2], &endptr, 16);
|
||||
else
|
||||
key = (unsigned)strtoul(&number[0], 0, 10);
|
||||
key = strtoul(&number[0], &endptr, 10);
|
||||
|
||||
if (*endptr && !isspace(*endptr)) {
|
||||
parse->offset = RC_INVALID_CONST_OPERAND;
|
||||
return nextline;
|
||||
}
|
||||
|
||||
item = RC_ALLOC(rc_richpresence_lookup_item_t, parse);
|
||||
item->value = key;
|
||||
@ -263,6 +276,8 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
|
||||
nextlookup = &lookup->next;
|
||||
|
||||
nextline = rc_parse_richpresence_lookup(lookup, nextline, parse);
|
||||
if (parse->offset < 0)
|
||||
return;
|
||||
|
||||
} else if (strncmp(line, "Format:", 7) == 0) {
|
||||
line += 7;
|
||||
@ -316,6 +331,8 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
|
||||
|
||||
if (ptr < endline) {
|
||||
*nextdisplay = rc_parse_richpresence_display_internal(ptr + 1, endline, parse, self);
|
||||
if (parse->offset < 0)
|
||||
return;
|
||||
trigger = &((*nextdisplay)->trigger);
|
||||
rc_parse_trigger_internal(trigger, &line, parse);
|
||||
trigger->memrefs = 0;
|
||||
|
18
deps/rcheevos/src/rcheevos/term.c
vendored
18
deps/rcheevos/src/rcheevos/term.c
vendored
@ -1,6 +1,6 @@
|
||||
#include "internal.h"
|
||||
|
||||
rc_term_t* rc_parse_term(const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_term_t* rc_parse_term(const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
|
||||
rc_term_t* self;
|
||||
const char* aux;
|
||||
char size;
|
||||
@ -10,7 +10,7 @@ rc_term_t* rc_parse_term(const char** memaddr, rc_parse_state_t* parse) {
|
||||
self = RC_ALLOC(rc_term_t, parse);
|
||||
self->invert = 0;
|
||||
|
||||
ret2 = rc_parse_operand(&self->operand1, &aux, 0, parse);
|
||||
ret2 = rc_parse_operand(&self->operand1, &aux, 0, is_indirect, parse);
|
||||
|
||||
if (ret2 < 0) {
|
||||
parse->offset = ret2;
|
||||
@ -25,7 +25,7 @@ rc_term_t* rc_parse_term(const char** memaddr, rc_parse_state_t* parse) {
|
||||
self->invert = 1;
|
||||
}
|
||||
|
||||
ret2 = rc_parse_operand(&self->operand2, &aux, 0, parse);
|
||||
ret2 = rc_parse_operand(&self->operand2, &aux, 0, is_indirect, parse);
|
||||
|
||||
if (ret2 < 0) {
|
||||
parse->offset = ret2;
|
||||
@ -88,12 +88,16 @@ rc_term_t* rc_parse_term(const char** memaddr, rc_parse_state_t* parse) {
|
||||
return self;
|
||||
}
|
||||
|
||||
unsigned rc_evaluate_term(rc_term_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
unsigned value = rc_evaluate_operand(&self->operand1, peek, ud, L);
|
||||
int rc_evaluate_term(rc_term_t* self, rc_eval_state_t* eval_state) {
|
||||
/* Operands are usually memory references and are always retrieved as unsigned. The floating
|
||||
* point operand is signed, and will automatically make the result signed. Otherwise, multiply
|
||||
* by the secondary operand (which is usually 1) and cast to signed.
|
||||
*/
|
||||
unsigned value = rc_evaluate_operand(&self->operand1, eval_state);
|
||||
|
||||
if (self->operand2.type != RC_OPERAND_FP) {
|
||||
return value * (rc_evaluate_operand(&self->operand2, peek, ud, L) ^ self->invert);
|
||||
return (int)(value * (rc_evaluate_operand(&self->operand2, eval_state) ^ self->invert));
|
||||
}
|
||||
|
||||
return (unsigned)((double)value * self->operand2.value.dbl);
|
||||
return (int)((double)value * self->operand2.value.dbl);
|
||||
}
|
||||
|
136
deps/rcheevos/src/rcheevos/trigger.c
vendored
136
deps/rcheevos/src/rcheevos/trigger.c
vendored
@ -1,6 +1,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <memory.h>
|
||||
|
||||
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_condset_t** next;
|
||||
@ -35,6 +36,11 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
|
||||
|
||||
*next = 0;
|
||||
*memaddr = aux;
|
||||
|
||||
self->measured_value = 0;
|
||||
self->measured_target = parse->measured_target;
|
||||
self->state = RC_TRIGGER_STATE_WAITING;
|
||||
self->has_hits = 0;
|
||||
}
|
||||
|
||||
int rc_trigger_size(const char* memaddr) {
|
||||
@ -63,36 +69,7 @@ rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L,
|
||||
return parse.offset >= 0 ? self : 0;
|
||||
}
|
||||
|
||||
int rc_test_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
int ret, reset;
|
||||
rc_condset_t* condset;
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, ud);
|
||||
|
||||
reset = 0;
|
||||
ret = self->requirement != 0 ? rc_test_condset(self->requirement, &reset, peek, ud, L) : 1;
|
||||
condset = self->alternative;
|
||||
|
||||
if (condset) {
|
||||
int sub = 0;
|
||||
|
||||
do {
|
||||
sub |= rc_test_condset(condset, &reset, peek, ud, L);
|
||||
condset = condset->next;
|
||||
}
|
||||
while (condset != 0);
|
||||
|
||||
ret &= sub && !reset;
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
rc_reset_trigger(self);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rc_reset_trigger(rc_trigger_t* self) {
|
||||
static void rc_reset_trigger_hitcounts(rc_trigger_t* self) {
|
||||
rc_condset_t* condset;
|
||||
|
||||
if (self->requirement != 0) {
|
||||
@ -106,3 +83,102 @@ void rc_reset_trigger(rc_trigger_t* self) {
|
||||
condset = condset->next;
|
||||
}
|
||||
}
|
||||
|
||||
int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
rc_eval_state_t eval_state;
|
||||
rc_condset_t* condset;
|
||||
int ret;
|
||||
char is_paused;
|
||||
|
||||
/* previously triggered, do nothing - return INACTIVE so caller doesn't report a repeated trigger */
|
||||
if (self->state == RC_TRIGGER_STATE_TRIGGERED)
|
||||
return RC_TRIGGER_STATE_INACTIVE;
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, ud);
|
||||
|
||||
/* not yet active, only update the memrefs - so deltas are corrent when it becomes active */
|
||||
if (self->state == RC_TRIGGER_STATE_INACTIVE)
|
||||
return RC_TRIGGER_STATE_INACTIVE;
|
||||
|
||||
/* process the trigger */
|
||||
memset(&eval_state, 0, sizeof(eval_state));
|
||||
eval_state.peek = peek;
|
||||
eval_state.peek_userdata = ud;
|
||||
eval_state.L = L;
|
||||
|
||||
ret = self->requirement != 0 ? rc_test_condset(self->requirement, &eval_state) : 1;
|
||||
condset = self->alternative;
|
||||
|
||||
if (condset) {
|
||||
int sub = 0;
|
||||
|
||||
do {
|
||||
sub |= rc_test_condset(condset, &eval_state);
|
||||
condset = condset->next;
|
||||
}
|
||||
while (condset != 0);
|
||||
|
||||
ret &= sub;
|
||||
}
|
||||
|
||||
self->measured_value = eval_state.measured_value;
|
||||
|
||||
/* 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 (eval_state.was_reset) {
|
||||
/* if any ResetIf condition was true, reset the hit counts */
|
||||
rc_reset_trigger_hitcounts(self);
|
||||
|
||||
/* if there were hit counts to clear, return RESET, but don't change the state */
|
||||
if (self->has_hits) {
|
||||
self->has_hits = 0;
|
||||
return RC_TRIGGER_STATE_RESET;
|
||||
}
|
||||
|
||||
/* any hits that were tallied were just reset */
|
||||
eval_state.has_hits = 0;
|
||||
}
|
||||
else if (ret) {
|
||||
/* trigger was triggered */
|
||||
self->state = RC_TRIGGER_STATE_TRIGGERED;
|
||||
return RC_TRIGGER_STATE_TRIGGERED;
|
||||
}
|
||||
|
||||
/* did not trigger this frame - update the information we'll need for next time */
|
||||
self->has_hits = eval_state.has_hits;
|
||||
|
||||
/* check to see if the trigger is paused */
|
||||
is_paused = (self->requirement != NULL) ? self->requirement->is_paused : 0;
|
||||
if (!is_paused) {
|
||||
/* if the core is not paused, all alts must be paused to count as a paused trigger */
|
||||
is_paused = (self->alternative != NULL);
|
||||
for (condset = self->alternative; condset != NULL; condset = condset->next) {
|
||||
if (!condset->is_paused) {
|
||||
is_paused = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->state = is_paused ? RC_TRIGGER_STATE_PAUSED : RC_TRIGGER_STATE_ACTIVE;
|
||||
return self->state;
|
||||
}
|
||||
|
||||
int rc_test_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
/* for backwards compatibilty, rc_test_trigger always assumes the achievement is active */
|
||||
self->state = RC_TRIGGER_STATE_ACTIVE;
|
||||
|
||||
return (rc_evaluate_trigger(self, peek, ud, L) == RC_TRIGGER_STATE_TRIGGERED);
|
||||
}
|
||||
|
||||
void rc_reset_trigger(rc_trigger_t* self) {
|
||||
rc_reset_trigger_hitcounts(self);
|
||||
|
||||
self->state = RC_TRIGGER_STATE_WAITING;
|
||||
}
|
||||
|
107
deps/rcheevos/src/rcheevos/value.c
vendored
107
deps/rcheevos/src/rcheevos/value.c
vendored
@ -1,8 +1,88 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_condition_t** next;
|
||||
int has_measured;
|
||||
int in_add_address;
|
||||
|
||||
has_measured = 0;
|
||||
in_add_address = 0;
|
||||
self->expressions = 0;
|
||||
|
||||
/* this largely duplicates rc_parse_condset, but we cannot call it directly, as we need to check the
|
||||
* type of each condition as we go */
|
||||
self->conditions = RC_ALLOC(rc_condset_t, parse);
|
||||
self->conditions->next = 0;
|
||||
self->conditions->has_pause = 0;
|
||||
|
||||
next = &self->conditions->conditions;
|
||||
for (;;) {
|
||||
*next = rc_parse_condition(memaddr, parse, in_add_address);
|
||||
|
||||
if (parse->offset < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
in_add_address = (*next)->type == RC_CONDITION_ADD_ADDRESS;
|
||||
|
||||
switch ((*next)->type) {
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
case RC_CONDITION_ADD_SOURCE:
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
/* combining flags are allowed */
|
||||
break;
|
||||
|
||||
case RC_CONDITION_RESET_IF:
|
||||
/* ResetIf is allowed (primarily for rich presense - leaderboard will typically cancel instead of resetting) */
|
||||
break;
|
||||
|
||||
case RC_CONDITION_MEASURED:
|
||||
if (has_measured) {
|
||||
parse->offset = RC_MULTIPLE_MEASURED;
|
||||
return;
|
||||
}
|
||||
has_measured = 1;
|
||||
if ((*next)->required_hits == 0 && (*next)->oper != RC_CONDITION_NONE)
|
||||
(*next)->required_hits = (unsigned)-1;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* non-combinding flags and PauseIf are not allowed */
|
||||
parse->offset = RC_INVALID_VALUE_FLAG;
|
||||
return;
|
||||
}
|
||||
|
||||
(*next)->pause = 0;
|
||||
next = &(*next)->next;
|
||||
|
||||
if (**memaddr != '_') {
|
||||
break;
|
||||
}
|
||||
|
||||
(*memaddr)++;
|
||||
}
|
||||
|
||||
*next = 0;
|
||||
|
||||
if (!has_measured) {
|
||||
parse->offset = RC_MISSING_VALUE_MEASURED;
|
||||
}
|
||||
}
|
||||
|
||||
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_expression_t** next;
|
||||
|
||||
/* if it starts with a condition flag (M: A: B: C:), parse the conditions */
|
||||
if ((*memaddr)[1] == ':') {
|
||||
rc_parse_cond_value(self, memaddr, parse);
|
||||
return;
|
||||
}
|
||||
|
||||
self->conditions = 0;
|
||||
next = &self->expressions;
|
||||
|
||||
for (;;) {
|
||||
@ -50,17 +130,15 @@ rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int
|
||||
return parse.offset >= 0 ? self : 0;
|
||||
}
|
||||
|
||||
unsigned rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
static int rc_evaluate_expr_value(rc_value_t* self, rc_eval_state_t* eval_state) {
|
||||
rc_expression_t* exp;
|
||||
unsigned value, max;
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, ud);
|
||||
int value, max;
|
||||
|
||||
exp = self->expressions;
|
||||
max = rc_evaluate_expression(exp, peek, ud, L);
|
||||
max = rc_evaluate_expression(exp, eval_state);
|
||||
|
||||
for (exp = exp->next; exp != 0; exp = exp->next) {
|
||||
value = rc_evaluate_expression(exp, peek, ud, L);
|
||||
value = rc_evaluate_expression(exp, eval_state);
|
||||
|
||||
if (value > max) {
|
||||
max = value;
|
||||
@ -69,3 +147,20 @@ unsigned rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
int rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
rc_eval_state_t eval_state;
|
||||
memset(&eval_state, 0, sizeof(eval_state));
|
||||
eval_state.peek = peek;
|
||||
eval_state.peek_userdata = ud;
|
||||
eval_state.L = L;
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, ud);
|
||||
|
||||
if (self->expressions) {
|
||||
return rc_evaluate_expr_value(self, &eval_state);
|
||||
}
|
||||
|
||||
rc_test_condset(self->conditions, &eval_state);
|
||||
return (int)eval_state.measured_value;
|
||||
}
|
||||
|
4
deps/rcheevos/src/rurl/url.c
vendored
4
deps/rcheevos/src/rurl/url.c
vendored
@ -69,7 +69,7 @@ int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const
|
||||
return (size_t)written >= size ? -1 : 0;
|
||||
}
|
||||
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, unsigned value, unsigned char hash[16]) {
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, unsigned char hash[16]) {
|
||||
char urle_user_name[64];
|
||||
char urle_login_token[64];
|
||||
int written;
|
||||
@ -85,7 +85,7 @@ int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const
|
||||
written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
"http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%u&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
"http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
urle_user_name,
|
||||
urle_login_token,
|
||||
lboard_id,
|
||||
|
Loading…
x
Reference in New Issue
Block a user