mirror of
https://github.com/stenzek/duckstation.git
synced 2026-10-11 22:49:58 +00:00
dep/rcheevos: Add rc_client_set_unofficial_achievement_unlock_state()
This commit is contained in:
@@ -222,6 +222,10 @@ typedef struct rc_client_user_game_summary_t {
|
||||
/* minimum version: 12.1 */
|
||||
time_t beaten_time;
|
||||
time_t completed_time;
|
||||
|
||||
uint32_t num_unlocked_unofficial_achievements;
|
||||
uint32_t points_unofficial;
|
||||
uint32_t points_unlocked_unofficial;
|
||||
} rc_client_user_game_summary_t;
|
||||
|
||||
/**
|
||||
@@ -586,6 +590,14 @@ typedef struct rc_client_achievement_t {
|
||||
*/
|
||||
RC_EXPORT const rc_client_achievement_t* RC_CCONV rc_client_get_achievement_info(rc_client_t* client, uint32_t id);
|
||||
|
||||
/**
|
||||
* Sets the locally tracked unlock state for an unofficial achievement.
|
||||
* Returns RC_OK on success, RC_NOT_FOUND if the achievement does not exist or is not unofficial,
|
||||
* or another rc_error.h error code if the operation could not be performed.
|
||||
*/
|
||||
RC_EXPORT int RC_CCONV rc_client_set_unofficial_achievement_unlock_state(rc_client_t* client, uint32_t id,
|
||||
uint8_t unlock_state, time_t unlock_time_softcore, time_t unlock_time_hardcore);
|
||||
|
||||
/**
|
||||
* Gets the next achievement after a provided achievement that fits in the specified bucket. Returns NULL if none found.
|
||||
*/
|
||||
|
||||
@@ -989,6 +989,12 @@ static void rc_client_subset_get_user_game_summary(const rc_client_t* client,
|
||||
|
||||
case RC_CLIENT_ACHIEVEMENT_CATEGORY_UNOFFICIAL:
|
||||
++summary->num_unofficial_achievements;
|
||||
summary->points_unofficial += achievement->public_.points;
|
||||
|
||||
if (achievement->public_.unlocked & unlock_bit) {
|
||||
++summary->num_unlocked_unofficial_achievements;
|
||||
summary->points_unlocked_unofficial += achievement->public_.points;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1010,6 +1016,7 @@ void rc_client_get_user_game_summary(const rc_client_t* client, rc_client_user_g
|
||||
if (!summary)
|
||||
return;
|
||||
|
||||
/* External clients may only populate an older prefix of the structure. */
|
||||
memset(summary, 0, sizeof(*summary));
|
||||
if (!client)
|
||||
return;
|
||||
@@ -1036,6 +1043,7 @@ void rc_client_get_user_subset_summary(const rc_client_t* client, uint32_t subse
|
||||
if (!summary)
|
||||
return;
|
||||
|
||||
/* External clients may only populate an older prefix of the structure. */
|
||||
memset(summary, 0, sizeof(*summary));
|
||||
if (!client || !subset_id)
|
||||
return;
|
||||
@@ -4557,6 +4565,84 @@ const rc_client_achievement_t* rc_client_get_achievement_info(rc_client_t* clien
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc_client_set_unofficial_achievement_unlock_state(rc_client_t* client, uint32_t id,
|
||||
uint8_t unlock_state, time_t unlock_time_softcore, time_t unlock_time_hardcore)
|
||||
{
|
||||
rc_client_subset_info_t* subset;
|
||||
rc_client_achievement_info_t* achievement = NULL;
|
||||
uint8_t active_bit;
|
||||
|
||||
if (!client)
|
||||
return RC_INVALID_STATE;
|
||||
|
||||
#ifdef RC_CLIENT_SUPPORTS_EXTERNAL
|
||||
if (client->state.external_client) {
|
||||
RC_CLIENT_LOG_ERR_FORMATTED(client, "Cannot set unofficial achievement %u unlock state with external client", id);
|
||||
return RC_INVALID_STATE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!client->game)
|
||||
return RC_NO_GAME_LOADED;
|
||||
|
||||
if (unlock_state & ~RC_CLIENT_ACHIEVEMENT_UNLOCKED_BOTH)
|
||||
return RC_INVALID_VALUE;
|
||||
|
||||
for (subset = client->game->subsets; subset; subset = subset->next) {
|
||||
rc_client_achievement_info_t* scan = subset->achievements;
|
||||
rc_client_achievement_info_t* stop = scan + subset->public_.num_achievements;
|
||||
for (; scan < stop; ++scan) {
|
||||
if (scan->public_.id == id) {
|
||||
achievement = scan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (achievement)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!achievement || achievement->public_.category != RC_CLIENT_ACHIEVEMENT_CATEGORY_UNOFFICIAL)
|
||||
return RC_NOT_FOUND;
|
||||
|
||||
rc_mutex_lock(&client->state.mutex);
|
||||
|
||||
if ((unlock_state & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE) && !unlock_time_softcore)
|
||||
unlock_time_softcore = time(NULL);
|
||||
else if (!(unlock_state & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE))
|
||||
unlock_time_softcore = 0;
|
||||
|
||||
if ((unlock_state & RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE) && !unlock_time_hardcore)
|
||||
unlock_time_hardcore = time(NULL);
|
||||
else if (!(unlock_state & RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE))
|
||||
unlock_time_hardcore = 0;
|
||||
|
||||
achievement->public_.unlocked = unlock_state;
|
||||
achievement->unlock_time_softcore = unlock_time_softcore;
|
||||
achievement->unlock_time_hardcore = unlock_time_hardcore;
|
||||
achievement->public_.unlock_time = client->state.hardcore ? unlock_time_hardcore : unlock_time_softcore;
|
||||
|
||||
active_bit = client->state.encore_mode ? RC_CLIENT_ACHIEVEMENT_UNLOCKED_NONE :
|
||||
client->state.hardcore ? RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE : RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE;
|
||||
|
||||
if (achievement->public_.state != RC_CLIENT_ACHIEVEMENT_STATE_DISABLED) {
|
||||
if (unlock_state & active_bit) {
|
||||
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED;
|
||||
if (achievement->trigger)
|
||||
achievement->trigger->state = RC_TRIGGER_STATE_TRIGGERED;
|
||||
}
|
||||
else {
|
||||
if (achievement->trigger)
|
||||
rc_reset_trigger(achievement->trigger);
|
||||
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
rc_client_update_active_achievements(client->game);
|
||||
rc_mutex_unlock(&client->state.mutex);
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
const rc_client_achievement_t* rc_client_get_next_achievement_info(rc_client_t* client,
|
||||
const rc_client_achievement_t* achievement, int bucket)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user