support for ResetIf/PauseIf HitCount

This commit is contained in:
meleu 2018-06-22 05:21:15 -03:00 committed by meleu
parent e3d406808f
commit 536638eaf6
2 changed files with 101 additions and 69 deletions

View File

@ -1289,62 +1289,31 @@ static int cheevos_test_condition(cheevos_cond_t *cond)
return 1; return 1;
} }
static int cheevos_test_cond_set(const cheevos_condset_t *condset, static int cheevos_test_pause_cond_set(const cheevos_condset_t *condset,
int *dirty_conds, int *reset_conds, int match_any) int *dirty_conds, int *reset_conds, int process_pause)
{ {
int cond_valid = 0; int cond_valid = 0;
int set_valid = 1; int set_valid = 1; /* must start true so AND logic works */
const cheevos_cond_t *end = NULL;
cheevos_cond_t *cond = NULL; cheevos_cond_t *cond = NULL;
const cheevos_cond_t *end = condset->conds + condset->count;
if (!condset)
return 0;
end = condset->conds + condset->count;
cheevos_locals.add_buffer = 0; cheevos_locals.add_buffer = 0;
cheevos_locals.add_hits = 0; cheevos_locals.add_hits = 0;
/* Now, read all Pause conditions, and if any are true,
* do not process further (retain old state). */
for (cond = condset->conds; cond < end; cond++) for (cond = condset->conds; cond < end; cond++)
{ {
if (cond->type != CHEEVOS_COND_TYPE_PAUSE_IF) if (cond->pause != process_pause)
continue;
/* Reset by default, set to 1 if hit! */
cond->curr_hits = 0;
if (cheevos_test_condition(cond))
{
cond->curr_hits = 1;
*dirty_conds = 1;
/* Early out: this achievement is paused,
* do not process any further! */
return 0;
}
}
/* Read all standard conditions, and process as normal: */
for (cond = condset->conds; cond < end; cond++)
{
if ( cond->type == CHEEVOS_COND_TYPE_PAUSE_IF ||
cond->type == CHEEVOS_COND_TYPE_RESET_IF)
continue; continue;
if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE) if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE)
{ {
cheevos_locals.add_buffer += cheevos_var_get_value(&cond->source); cheevos_locals.add_buffer += cheevos_var_get_value(&cond->source);
set_valid &= 1;
continue; continue;
} }
if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE) if (cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE)
{ {
cheevos_locals.add_buffer -= cheevos_var_get_value(&cond->source); cheevos_locals.add_buffer -= cheevos_var_get_value(&cond->source);
set_valid &= 1;
continue; continue;
} }
@ -1360,17 +1329,17 @@ static int cheevos_test_cond_set(const cheevos_condset_t *condset,
continue; continue;
} }
/* always evaluate the condition to ensure delta values get tracked correctly */
cond_valid = cheevos_test_condition(cond);
/* if the condition has a target hit count that has already been met,
* it's automatically true, even if not currently true. */
if ( (cond->req_hits != 0) && if ( (cond->req_hits != 0) &&
(cond->curr_hits + cheevos_locals.add_hits) >= cond->req_hits) (cond->curr_hits + cheevos_locals.add_hits) >= cond->req_hits)
{ {
cheevos_locals.add_buffer = 0; cond_valid = 1;
cheevos_locals.add_hits = 0;
continue;
} }
else if (cond_valid)
cond_valid = cheevos_test_condition(cond);
if (cond_valid)
{ {
cond->curr_hits++; cond->curr_hits++;
*dirty_conds = 1; *dirty_conds = 1;
@ -1379,38 +1348,100 @@ static int cheevos_test_cond_set(const cheevos_condset_t *condset,
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 + cheevos_locals.add_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; /* HitCount target has not yet been met, condition is not yet valid. */
if (match_any)
break;
} }
cheevos_locals.add_buffer = 0; cheevos_locals.add_buffer = 0;
cheevos_locals.add_hits = 0; cheevos_locals.add_hits = 0;
/* Sequential or non-sequential? */ if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF)
set_valid &= cond_valid;
}
/* Now, ONLY read reset conditions! */
for (cond = condset->conds; cond < end; cond++)
{ {
if (cond->type != CHEEVOS_COND_TYPE_RESET_IF) /* as soon as we find a PauseIf that evaluates to true,
continue; * stop processing the rest of the group. */
if (cond_valid)
return 1;
cond_valid = cheevos_test_condition(cond); /* if we make it to the end of the function, make sure we are
* indicating nothing matched. if we do find a later PauseIf match,
* it'll automatically return true via the previous condition. */
set_valid = 0;
if (cond->req_hits == 0)
{
/* PauseIf didn't evaluate true, and doesn't have a HitCount,
* reset the HitCount to indicate the condition didn't match. */
if (cond->curr_hits != 0)
{
cond->curr_hits = 0;
*dirty_conds = 1;
}
}
else
{
/* PauseIf has a HitCount that hasn't been met, ignore it for now. */
}
}
else if (cond->type == CHEEVOS_COND_TYPE_RESET_IF)
{
if (cond_valid) if (cond_valid)
{ {
*reset_conds = 1; /* Resets all hits found so far */ *reset_conds = 1; /* Resets all hits found so far */
set_valid = 0; /* Cannot be valid if we've hit a reset condition. */ set_valid = 0; /* Cannot be valid if we've hit a reset condition. */
break; /* No point processing any further reset conditions. */
} }
} }
else /* Sequential or non-sequential? */
set_valid &= cond_valid;
}
return set_valid; return set_valid;
} }
static int cheevos_test_cond_set(const cheevos_condset_t *condset,
int *dirty_conds, int *reset_conds)
{
if (!condset)
return 1; /* important: empty group must evaluate true */
/* the ints below are used for Pause conditions and their dependent AddSource/AddHits. */
int in_pause = 0;
int has_pause = 0;
cheevos_cond_t *cond = NULL;
/* this loop needs to go backwards to check AddSource/AddHits */
cond = condset->conds + condset->count - 1;
for (; cond >= condset->conds; cond--)
{
if (cond->type == CHEEVOS_COND_TYPE_PAUSE_IF)
{
has_pause = 1;
in_pause = 1;
cond->pause = 1;
}
else if (cond->type == CHEEVOS_COND_TYPE_ADD_SOURCE ||
cond->type == CHEEVOS_COND_TYPE_SUB_SOURCE ||
cond->type == CHEEVOS_COND_TYPE_ADD_HITS)
{
cond->pause = in_pause;
}
else
{
in_pause = 0;
cond->pause = 0;
}
}
if (has_pause)
{ /* one or more Pause conditions exists, if any of them are true,
* stop processing this group. */
if (cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 1))
return 0;
}
/* process the non-Pause conditions to see if the group is true */
return cheevos_test_pause_cond_set(condset, dirty_conds, reset_conds, 0);
}
static int cheevos_reset_cond_set(cheevos_condset_t *condset, int deltas) static int cheevos_reset_cond_set(cheevos_condset_t *condset, int deltas)
{ {
int dirty = 0; int dirty = 0;
@ -1469,14 +1500,14 @@ static int cheevos_test_cheevo(cheevo_t *cheevo)
if (condset < end) if (condset < end)
{ {
ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds, 0); ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds);
condset++; condset++;
} }
while (condset < end) while (condset < end)
{ {
ret_val_sub_cond |= cheevos_test_cond_set( ret_val_sub_cond |= cheevos_test_cond_set(
condset, &dirty_conds, &reset_conds, 0); condset, &dirty_conds, &reset_conds);
condset++; condset++;
} }
@ -1674,14 +1705,14 @@ static int cheevos_test_lboard_condition(const cheevos_condition_t* condition)
if (condset < end) if (condset < end)
{ {
ret_val = cheevos_test_cond_set( ret_val = cheevos_test_cond_set(
condset, &dirty_conds, &reset_conds, 0); condset, &dirty_conds, &reset_conds);
condset++; condset++;
} }
while (condset < end) while (condset < end)
{ {
ret_val_sub_cond |= cheevos_test_cond_set( ret_val_sub_cond |= cheevos_test_cond_set(
condset, &dirty_conds, &reset_conds, 0); condset, &dirty_conds, &reset_conds);
condset++; condset++;
} }

View File

@ -47,6 +47,7 @@ typedef struct
cheevos_cond_type_t type; cheevos_cond_type_t type;
unsigned req_hits; unsigned req_hits;
unsigned curr_hits; unsigned curr_hits;
char pause;
cheevos_var_t source; cheevos_var_t source;
cheevos_cond_op_t op; cheevos_cond_op_t op;