Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

track when a ResetIf condition causes a reset #397

Merged
merged 1 commit into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion include/rc_runtime_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,15 @@ struct rc_condition_t {
/* The comparison operator to use. (RC_OPERATOR_*) */
uint8_t oper; /* operator is a reserved word in C++. */

/* Whether or not the condition evaluated true on the last check. (bool) */
/* Will be non-zero if the condition evaluated true on the last check.
* - The lowest bit indicates whether the condition itself was true.
* - The second lowest bit will only ever be set on ResetIf conditions.
* If set, it indicates that the condition was responsible for resetting the
* trigger. A reset clears all hit counts, so the condition may not appear to
* be true just from looking at it (in which case the lower bit will be 0).
* Also, the condition might have only met its required_hits target though
* an AddHits chain which will have also been reset.
*/
uint8_t is_true;

/* Unique identifier of optimized comparator to use. (RC_PROCESSING_COMPARE_*) */
Expand Down
4 changes: 4 additions & 0 deletions src/rcheevos/condset.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@ static void rc_condset_evaluate_reset_if(rc_condition_t* condition, rc_eval_stat
const uint8_t cond_valid = rc_condset_evaluate_condition(condition, eval_state);

if (cond_valid) {
/* flag the condition as being responsible for the reset */
/* make sure not to modify bit0, as we use bitwise-and operators to combine truthiness */
condition->is_true |= 0x02;

/* set cannot be valid if we've hit a reset condition */
eval_state->is_true = eval_state->is_primed = 0;

Expand Down
8 changes: 3 additions & 5 deletions src/rcheevos/runtime_progress.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ typedef struct rc_runtime_progress_t {

#define RC_VAR_FLAG_HAS_COND_DATA 0x01000000

#define RC_COND_FLAG_IS_TRUE 0x00000001
#define RC_COND_FLAG_IS_TRUE_MASK 0x00000003
#define RC_COND_FLAG_OPERAND1_IS_INDIRECT_MEMREF 0x00010000
#define RC_COND_FLAG_OPERAND1_MEMREF_CHANGED_THIS_FRAME 0x00020000
#define RC_COND_FLAG_OPERAND2_IS_INDIRECT_MEMREF 0x00100000
Expand Down Expand Up @@ -325,9 +325,7 @@ static int rc_runtime_progress_write_condset(rc_runtime_progress_t* progress, rc

cond = condset->conditions;
while (cond) {
flags = 0;
if (cond->is_true)
flags |= RC_COND_FLAG_IS_TRUE;
flags = (cond->is_true & RC_COND_FLAG_IS_TRUE_MASK);

if (rc_runtime_progress_is_indirect_memref(&cond->operand1)) {
flags |= RC_COND_FLAG_OPERAND1_IS_INDIRECT_MEMREF;
Expand Down Expand Up @@ -381,7 +379,7 @@ static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_
cond->current_hits = rc_runtime_progress_read_uint(progress);
flags = rc_runtime_progress_read_uint(progress);

cond->is_true = (flags & RC_COND_FLAG_IS_TRUE) ? 1 : 0;
cond->is_true = (flags & RC_COND_FLAG_IS_TRUE_MASK);

if (flags & RC_COND_FLAG_OPERAND1_IS_INDIRECT_MEMREF) {
if (!rc_operand_is_memref(&cond->operand1)) /* this should never happen, but better safe than sorry */
Expand Down
10 changes: 9 additions & 1 deletion test/rcheevos/test_condset.c
Original file line number Diff line number Diff line change
Expand Up @@ -660,12 +660,15 @@ static void test_resetif_hitcount() {
assert_hit_count(condset, 0, 2);
assert_hit_count(condset, 1, 4);
assert_hit_count(condset, 2, 1);
ASSERT_NUM_EQUALS(condset_get_cond(condset, 2)->is_true, 1);

/* second hit on reset condition should reset everything */
assert_evaluate_condset(condset, memrefs, &memory, 0);
assert_hit_count(condset, 0, 0);
assert_hit_count(condset, 1, 0);
assert_hit_count(condset, 2, 0);
/* is_true=3 indicates the condition was true this frame, and its hit target was met before it got reset */
ASSERT_NUM_EQUALS(condset_get_cond(condset, 2)->is_true, 3);
}

static void test_resetif_hitcount_one() {
Expand Down Expand Up @@ -718,12 +721,17 @@ static void test_resetif_hitcount_addhits() {
assert_evaluate_condset(condset, memrefs, &memory, 1);
assert_hit_count(condset, 0, 1);
assert_hit_count(condset, 1, 1);
ASSERT_NUM_EQUALS(condset_get_cond(condset, 0)->is_true, 1);
ASSERT_NUM_EQUALS(condset_get_cond(condset, 1)->is_true, 1);

/* total hitcount is met (2 for each condition, need 3 total) , everything resets */
/* total hitcount is met (2 for first condition, 1 for second, need 3 total) , everything resets */
ram[4] = 0x54;
assert_evaluate_condset(condset, memrefs, &memory, 0);
assert_hit_count(condset, 0, 0);
assert_hit_count(condset, 1, 0);
ASSERT_NUM_EQUALS(condset_get_cond(condset, 0)->is_true, 1);
/* is_true=2 indicates the condition was not true this frame, but its hit target was met before it got reset due to the AddHits */
ASSERT_NUM_EQUALS(condset_get_cond(condset, 1)->is_true, 2);
}

static void test_pauseif_resetif_hitcounts() {
Expand Down
Loading