mirror of
https://github.com/libretro/RetroArch
synced 2025-04-17 11:43:00 +00:00
Merge pull request #12474 from Jamiras/cheevos_menu
(cheevos) group achievements by category in quick menu
This commit is contained in:
commit
140b8f5e0a
@ -2107,7 +2107,7 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
INCLUDE_DIRS += -Ideps/rcheevos/include
|
||||
|
||||
OBJ += cheevos/cheevos.o \
|
||||
cheevos/badges.o \
|
||||
cheevos/cheevos_menu.o \
|
||||
cheevos/cheevos_memory.o \
|
||||
cheevos/cheevos_parser.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
|
||||
|
@ -1,91 +0,0 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2015-2016 - Andre Leiradella
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <file/file_path.h>
|
||||
|
||||
#include "../file_path_special.h"
|
||||
#include "../configuration.h"
|
||||
#include "../gfx/gfx_display.h"
|
||||
|
||||
#include "badges.h"
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
|
||||
#define CHEEVOS_MENU_BADGE_LIMIT 256
|
||||
/* TODO/FIXME - public global variables */
|
||||
static uintptr_t cheevos_badge_menu_texture_list[CHEEVOS_MENU_BADGE_LIMIT] = { 0 };
|
||||
|
||||
void cheevos_reset_menu_badges(void)
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < CHEEVOS_MENU_BADGE_LIMIT; ++index)
|
||||
{
|
||||
if (cheevos_badge_menu_texture_list[index])
|
||||
video_driver_texture_unload(&cheevos_badge_menu_texture_list[index]);
|
||||
}
|
||||
|
||||
memset(&cheevos_badge_menu_texture_list, 0,
|
||||
sizeof(cheevos_badge_menu_texture_list));
|
||||
}
|
||||
|
||||
void cheevos_set_menu_badge(int index, const char *badge, bool locked)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
if (index >= CHEEVOS_MENU_BADGE_LIMIT)
|
||||
return;
|
||||
|
||||
if (!settings || !settings->bools.cheevos_badges_enable)
|
||||
cheevos_badge_menu_texture_list[index] = 0;
|
||||
else
|
||||
cheevos_badge_menu_texture_list[index] =
|
||||
cheevos_get_badge_texture(badge, locked);
|
||||
}
|
||||
|
||||
uintptr_t cheevos_get_menu_badge_texture(int index)
|
||||
{
|
||||
if (index < CHEEVOS_MENU_BADGE_LIMIT)
|
||||
return cheevos_badge_menu_texture_list[index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uintptr_t cheevos_get_badge_texture(const char *badge, bool locked)
|
||||
{
|
||||
char badge_file[24];
|
||||
char fullpath[PATH_MAX_LENGTH];
|
||||
uintptr_t tex = 0;
|
||||
|
||||
if (!badge)
|
||||
return 0;
|
||||
|
||||
fullpath[0] = badge_file[0] = '\0';
|
||||
|
||||
strlcpy(badge_file, badge, sizeof(badge_file));
|
||||
if (locked)
|
||||
strlcat(badge_file, "_lock", sizeof(badge_file));
|
||||
strlcat(badge_file, FILE_PATH_PNG_EXTENSION, sizeof(badge_file));
|
||||
|
||||
fill_pathname_application_special(fullpath, sizeof(fullpath),
|
||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
|
||||
|
||||
if (!gfx_display_reset_textures_list(badge_file, fullpath,
|
||||
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
|
||||
tex = 0;
|
||||
|
||||
return tex;
|
||||
}
|
@ -33,11 +33,6 @@
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
#include "../menu/menu_driver.h"
|
||||
#include "../menu/menu_entries.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GFX_WIDGETS
|
||||
#include "../gfx/gfx_widgets.h"
|
||||
#endif
|
||||
@ -58,11 +53,10 @@
|
||||
#include "streams/chd_stream.h"
|
||||
#endif
|
||||
|
||||
#include "badges.h"
|
||||
#include "cheevos.h"
|
||||
#include "cheevos_locals.h"
|
||||
#include "cheevos_memory.h"
|
||||
#include "cheevos_parser.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "../file_path_special.h"
|
||||
#include "../paths.h"
|
||||
@ -80,7 +74,6 @@
|
||||
#include "../network/net_http_special.h"
|
||||
#include "../tasks/tasks_internal.h"
|
||||
|
||||
#include "../deps/rcheevos/include/rc_runtime.h"
|
||||
#include "../deps/rcheevos/include/rc_runtime_types.h"
|
||||
#include "../deps/rcheevos/include/rc_url.h"
|
||||
#include "../deps/rcheevos/include/rc_hash.h"
|
||||
@ -132,30 +125,6 @@ typedef struct rcheevos_async_io_request
|
||||
char hardcore;
|
||||
} rcheevos_async_io_request;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rc_runtime_t runtime;
|
||||
rcheevos_rapatchdata_t patchdata; /* ptr alignment */
|
||||
rcheevos_memory_regions_t memory; /* ptr alignment */
|
||||
|
||||
retro_task_t* task;
|
||||
#ifdef HAVE_THREADS
|
||||
slock_t* task_lock;
|
||||
enum event_command queued_command;
|
||||
#endif
|
||||
|
||||
char token[32];
|
||||
char hash[33];
|
||||
char user_agent_prefix[128];
|
||||
|
||||
bool hardcore_active;
|
||||
bool loaded;
|
||||
bool core_supports;
|
||||
bool leaderboards_enabled;
|
||||
bool leaderboard_notifications;
|
||||
bool leaderboard_trackers;
|
||||
} rcheevos_locals_t;
|
||||
|
||||
static rcheevos_locals_t rcheevos_locals =
|
||||
{
|
||||
{0}, /* runtime */
|
||||
@ -169,6 +138,11 @@ static rcheevos_locals_t rcheevos_locals =
|
||||
{0}, /* token */
|
||||
"N/A",/* hash */
|
||||
"", /* user_agent_prefix */
|
||||
#ifdef HAVE_MENU
|
||||
NULL, /* menuitems */
|
||||
0, /* menuitem_capacity */
|
||||
0, /* menuitem_count */
|
||||
#endif
|
||||
false,/* hardcore_active */
|
||||
false,/* loaded */
|
||||
true, /* core_supports */
|
||||
@ -177,6 +151,11 @@ static rcheevos_locals_t rcheevos_locals =
|
||||
false /* leaderboard_trackers */
|
||||
};
|
||||
|
||||
rcheevos_locals_t* get_rcheevos_locals()
|
||||
{
|
||||
return &rcheevos_locals;
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#define CHEEVOS_LOCK(l) do { slock_lock(l); } while (0)
|
||||
#define CHEEVOS_UNLOCK(l) do { slock_unlock(l); } while (0)
|
||||
@ -986,6 +965,8 @@ static void rcheevos_award_achievement(rcheevos_locals_t *locals,
|
||||
if (locals->hardcore_active)
|
||||
cheevo->active &= ~RCHEEVOS_ACTIVE_HARDCORE;
|
||||
|
||||
cheevo->unlock_time = cpu_features_get_time_usec();
|
||||
|
||||
/* Show the OSD message. */
|
||||
{
|
||||
#if defined(HAVE_GFX_WIDGETS)
|
||||
@ -1235,231 +1216,6 @@ void rcheevos_reset_game(bool widgets_ready)
|
||||
rcheevos_locals.patchdata.console_id);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
void rcheevos_get_achievement_state(unsigned index,
|
||||
char *buffer, size_t len)
|
||||
{
|
||||
enum msg_hash_enums enum_idx;
|
||||
rcheevos_racheevo_t *cheevo = NULL;
|
||||
bool check_measured = false;
|
||||
|
||||
if (index < rcheevos_locals.patchdata.core_count)
|
||||
{
|
||||
enum_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY;
|
||||
if (rcheevos_locals.patchdata.core)
|
||||
cheevo = &rcheevos_locals.patchdata.core[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
enum_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
|
||||
if (rcheevos_locals.patchdata.unofficial)
|
||||
cheevo = &rcheevos_locals.patchdata.unofficial[index -
|
||||
rcheevos_locals.patchdata.core_count];
|
||||
}
|
||||
|
||||
if (!cheevo || !cheevo->memaddr)
|
||||
enum_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY;
|
||||
else if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE))
|
||||
enum_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE;
|
||||
else if (!(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
|
||||
{
|
||||
enum_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
|
||||
/* if in hardcore mode, track progress towards hardcore unlock */
|
||||
check_measured = rcheevos_locals.hardcore_active;
|
||||
}
|
||||
/* Use either "Locked" for core or "Unofficial"
|
||||
* for unofficial as set above and track progress */
|
||||
else
|
||||
check_measured = true;
|
||||
|
||||
strlcpy(buffer, msg_hash_to_str(enum_idx), len);
|
||||
|
||||
if (check_measured)
|
||||
{
|
||||
const rc_trigger_t* trigger = rc_runtime_get_achievement(
|
||||
&rcheevos_locals.runtime, cheevo->id);
|
||||
const unsigned int target = trigger->measured_target;
|
||||
|
||||
if (target > 0 && trigger->measured_value > 0)
|
||||
{
|
||||
char measured_buffer[12];
|
||||
const unsigned int value = MIN(trigger->measured_value, target);
|
||||
const int percent = (int)(((unsigned long)value) * 100 / target);
|
||||
|
||||
snprintf(measured_buffer, sizeof(measured_buffer),
|
||||
" - %d%%", percent);
|
||||
strlcat(buffer, measured_buffer, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_append_menu_achievement(
|
||||
menu_displaylist_info_t* info, size_t idx,
|
||||
rcheevos_racheevo_t* cheevo)
|
||||
{
|
||||
bool badge_grayscale;
|
||||
|
||||
menu_entries_append_enum(info->list, cheevo->title,
|
||||
cheevo->description, MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
|
||||
(unsigned)(MENU_SETTINGS_CHEEVOS_START + idx), 0, 0);
|
||||
|
||||
/* TODO/FIXME - can we refactor this?
|
||||
* Make badge_grayscale true by default, then
|
||||
* have one conditional (second one here) that sets it
|
||||
* to false */
|
||||
if (!cheevo->memaddr)
|
||||
badge_grayscale = true; /* unsupported */
|
||||
else if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE) ||
|
||||
!(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
|
||||
badge_grayscale = false; /* unlocked */
|
||||
else
|
||||
badge_grayscale = true; /* locked */
|
||||
|
||||
cheevos_set_menu_badge((int)idx, cheevo->badge, badge_grayscale);
|
||||
}
|
||||
#endif
|
||||
|
||||
void rcheevos_populate_hardcore_pause_menu(void* data)
|
||||
{
|
||||
#ifdef HAVE_MENU
|
||||
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
|
||||
settings_t* settings = config_get_ptr();
|
||||
bool cheevos_hardcore_mode_enable = settings->bools.cheevos_hardcore_mode_enable;
|
||||
|
||||
if (cheevos_hardcore_mode_enable && rcheevos_locals.loaded)
|
||||
{
|
||||
if (rcheevos_locals.hardcore_active)
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_CANCEL),
|
||||
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE_CANCEL),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL,
|
||||
MENU_SETTING_ACTION_CLOSE, 0, 0);
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE,
|
||||
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME_CANCEL),
|
||||
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME_CANCEL),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL,
|
||||
MENU_SETTING_ACTION_CLOSE, 0, 0);
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME,
|
||||
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void rcheevos_populate_menu(void* data)
|
||||
{
|
||||
#ifdef HAVE_MENU
|
||||
int i = 0;
|
||||
int count = 0;
|
||||
rcheevos_racheevo_t* cheevo = NULL;
|
||||
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
|
||||
settings_t* settings = config_get_ptr();
|
||||
bool cheevos_enable = settings->bools.cheevos_enable;
|
||||
bool cheevos_hardcore_mode_enable = settings->bools.cheevos_hardcore_mode_enable;
|
||||
bool cheevos_test_unofficial = settings->bools.cheevos_test_unofficial;
|
||||
|
||||
if ( cheevos_enable
|
||||
&& cheevos_hardcore_mode_enable
|
||||
&& rcheevos_locals.loaded)
|
||||
{
|
||||
if (rcheevos_locals.hardcore_active)
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
|
||||
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0);
|
||||
else
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
|
||||
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0);
|
||||
}
|
||||
|
||||
cheevo = rcheevos_locals.patchdata.core;
|
||||
for (count = rcheevos_locals.patchdata.core_count; count > 0; count--)
|
||||
rcheevos_append_menu_achievement(info, i++, cheevo++);
|
||||
|
||||
if (cheevos_test_unofficial)
|
||||
{
|
||||
cheevo = rcheevos_locals.patchdata.unofficial;
|
||||
for (count = rcheevos_locals.patchdata.unofficial_count; count > 0; count--)
|
||||
rcheevos_append_menu_achievement(info, i++, cheevo++);
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (!rcheevos_locals.core_supports)
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
|
||||
MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
else if (!settings->arrays.cheevos_token[0])
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NOT_LOGGED_IN),
|
||||
MENU_ENUM_LABEL_NOT_LOGGED_IN,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rcheevos_get_description(rcheevos_ctx_desc_t* desc)
|
||||
{
|
||||
unsigned idx;
|
||||
const rcheevos_racheevo_t* cheevo;
|
||||
|
||||
if (!desc)
|
||||
return false;
|
||||
|
||||
*desc->s = 0;
|
||||
|
||||
if (rcheevos_locals.loaded)
|
||||
{
|
||||
idx = desc->idx;
|
||||
|
||||
if (idx < rcheevos_locals.patchdata.core_count)
|
||||
cheevo = rcheevos_locals.patchdata.core + idx;
|
||||
else
|
||||
{
|
||||
idx -= rcheevos_locals.patchdata.core_count;
|
||||
|
||||
if (idx >= rcheevos_locals.patchdata.unofficial_count)
|
||||
return true;
|
||||
cheevo = rcheevos_locals.patchdata.unofficial + idx;
|
||||
}
|
||||
|
||||
strlcpy(desc->s, cheevo->description, desc->len);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rcheevos_hardcore_active(void)
|
||||
{
|
||||
return rcheevos_locals.hardcore_active;
|
||||
@ -1500,10 +1256,17 @@ bool rcheevos_unload(void)
|
||||
|
||||
if (rcheevos_locals.loaded)
|
||||
{
|
||||
rcheevos_free_patchdata(&rcheevos_locals.patchdata);
|
||||
#ifdef HAVE_MENU
|
||||
cheevos_reset_menu_badges();
|
||||
rcheevos_menu_reset_badges();
|
||||
|
||||
if (rcheevos_locals.menuitems)
|
||||
{
|
||||
CHEEVOS_FREE(rcheevos_locals.menuitems);
|
||||
rcheevos_locals.menuitems = NULL;
|
||||
rcheevos_locals.menuitem_capacity = rcheevos_locals.menuitem_count = 0;
|
||||
}
|
||||
#endif
|
||||
rcheevos_free_patchdata(&rcheevos_locals.patchdata);
|
||||
|
||||
rcheevos_locals.loaded = false;
|
||||
rcheevos_locals.hardcore_active = false;
|
||||
@ -2451,10 +2214,43 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
cheevos_reset_menu_badges();
|
||||
#endif
|
||||
/* make sure the directory exists */
|
||||
coro->badge_fullpath[0] = '\0';
|
||||
fill_pathname_application_special(coro->badge_fullpath,
|
||||
sizeof(coro->badge_fullpath),
|
||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
|
||||
|
||||
if (!path_is_directory(coro->badge_fullpath))
|
||||
path_mkdir(coro->badge_fullpath);
|
||||
|
||||
/* fetch the placeholder image */
|
||||
strlcpy(coro->badge_name, "00000" FILE_PATH_PNG_EXTENSION,
|
||||
sizeof(coro->badge_name));
|
||||
fill_pathname_join(coro->badge_fullpath, coro->badge_fullpath,
|
||||
coro->badge_name, sizeof(coro->badge_fullpath));
|
||||
|
||||
if (!path_is_valid(coro->badge_fullpath))
|
||||
{
|
||||
#ifdef CHEEVOS_LOG_BADGES
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "downloading badge %s\n",
|
||||
coro->badge_fullpath);
|
||||
#endif
|
||||
snprintf(coro->url, sizeof(coro->url),
|
||||
FILE_PATH_RETROACHIEVEMENTS_URL "/Badge/%s", coro->badge_name);
|
||||
|
||||
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
||||
|
||||
if (coro->json)
|
||||
{
|
||||
if (!filestream_write_file(coro->badge_fullpath, coro->json, coro->k))
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "Error writing badge %s\n", coro->badge_fullpath);
|
||||
|
||||
CHEEVOS_FREE(coro->json);
|
||||
coro->json = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* fetch the game images */
|
||||
for (coro->i = 0; coro->i < 2; coro->i++)
|
||||
{
|
||||
if (coro->i == 0)
|
||||
@ -2470,24 +2266,13 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
||||
|
||||
for (; coro->cheevo < coro->cheevo_end; coro->cheevo++)
|
||||
{
|
||||
if (!coro->cheevo->badge[0])
|
||||
if (!coro->cheevo->badge || !coro->cheevo->badge[0])
|
||||
continue;
|
||||
|
||||
for (coro->j = 0 ; coro->j < 2; coro->j++)
|
||||
{
|
||||
coro->badge_fullpath[0] = '\0';
|
||||
fill_pathname_application_special(
|
||||
coro->badge_fullpath,
|
||||
sizeof(coro->badge_fullpath),
|
||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
|
||||
|
||||
if (!path_is_directory(coro->badge_fullpath))
|
||||
path_mkdir(coro->badge_fullpath);
|
||||
CORO_YIELD();
|
||||
|
||||
if (!coro->cheevo->badge || !coro->cheevo->badge[0])
|
||||
continue;
|
||||
|
||||
if (coro->j == 0)
|
||||
snprintf(coro->badge_name,
|
||||
sizeof(coro->badge_name),
|
||||
@ -2499,6 +2284,11 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
||||
"%s_lock" FILE_PATH_PNG_EXTENSION,
|
||||
coro->cheevo->badge);
|
||||
|
||||
coro->badge_fullpath[0] = '\0';
|
||||
fill_pathname_application_special(coro->badge_fullpath,
|
||||
sizeof(coro->badge_fullpath),
|
||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
|
||||
|
||||
fill_pathname_join(
|
||||
coro->badge_fullpath,
|
||||
coro->badge_fullpath,
|
||||
@ -2524,11 +2314,9 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
||||
if (!filestream_write_file(coro->badge_fullpath,
|
||||
coro->json, coro->k))
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "Error writing badge %s\n", coro->badge_fullpath);
|
||||
else
|
||||
{
|
||||
CHEEVOS_FREE(coro->json);
|
||||
coro->json = NULL;
|
||||
}
|
||||
|
||||
CHEEVOS_FREE(coro->json);
|
||||
coro->json = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,64 +21,39 @@
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
#include "../verbosity.h"
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct rcheevos_ctx_desc
|
||||
{
|
||||
unsigned idx;
|
||||
char *s;
|
||||
size_t len;
|
||||
} rcheevos_ctx_desc_t;
|
||||
|
||||
enum
|
||||
{
|
||||
RCHEEVOS_ACTIVE_SOFTCORE = 1 << 0,
|
||||
RCHEEVOS_ACTIVE_HARDCORE = 1 << 1,
|
||||
RCHEEVOS_ACTIVE_UNOFFICIAL = 1 << 2
|
||||
};
|
||||
|
||||
bool rcheevos_load(const void *data);
|
||||
size_t rcheevos_get_serialize_size(void);
|
||||
bool rcheevos_get_serialized_data(void* buffer);
|
||||
bool rcheevos_set_serialized_data(void* buffer);
|
||||
|
||||
void rcheevos_reset_game(bool widgets_ready);
|
||||
|
||||
void rcheevos_populate_menu(void* data);
|
||||
void rcheevos_populate_hardcore_pause_menu(void* data);
|
||||
void rcheevos_get_achievement_state(unsigned index, char* buffer, size_t buffer_size);
|
||||
|
||||
bool rcheevos_get_description(rcheevos_ctx_desc_t *desc);
|
||||
|
||||
void rcheevos_pause_hardcore(void);
|
||||
|
||||
bool rcheevos_unload(void);
|
||||
|
||||
void rcheevos_test(void);
|
||||
|
||||
void rcheevos_reset_game(bool widgets_ready);
|
||||
|
||||
void rcheevos_pause_hardcore(void);
|
||||
void rcheevos_hardcore_enabled_changed(void);
|
||||
void rcheevos_toggle_hardcore_paused(void);
|
||||
bool rcheevos_hardcore_active(void);
|
||||
|
||||
void rcheevos_validate_config_settings(void);
|
||||
|
||||
void rcheevos_leaderboards_enabled_changed(void);
|
||||
|
||||
void rcheevos_test(void);
|
||||
|
||||
void rcheevos_set_support_cheevos(bool state);
|
||||
|
||||
bool rcheevos_get_support_cheevos(void);
|
||||
|
||||
const char* rcheevos_get_hash(void);
|
||||
|
||||
int rcheevos_get_richpresence(char buffer[], int buffer_size);
|
||||
uintptr_t rcheevos_get_badge_texture(const char *badge, bool locked);
|
||||
|
||||
uint8_t* rcheevos_patch_address(unsigned address);
|
||||
|
||||
bool rcheevos_hardcore_active(void);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif /* __RARCH_CHEEVOS_CHEEVOS_H */
|
||||
|
158
cheevos/cheevos_locals.h
Normal file
158
cheevos/cheevos_locals.h
Normal file
@ -0,0 +1,158 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2015-2018 - Andre Leiradella
|
||||
* Copyright (C) 2019-2021 - Brian Weiss
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_CHEEVOS_LOCALS_H
|
||||
#define __RARCH_CHEEVOS_LOCALS_H
|
||||
|
||||
#include "../deps/rcheevos/include/rc_runtime.h"
|
||||
|
||||
#include "cheevos_memory.h"
|
||||
|
||||
#include <../command.h>
|
||||
#include <../verbosity.h>
|
||||
#include <boolean.h>
|
||||
#include <queues/task_queue.h>
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#include <rthreads/rthreads.h>
|
||||
#endif
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/************************************************************************
|
||||
* Logging *
|
||||
************************************************************************/
|
||||
|
||||
/* Define this macro to get extra-verbose log for cheevos. */
|
||||
#define CHEEVOS_VERBOSE
|
||||
|
||||
#define RCHEEVOS_TAG "[RCHEEVOS]: "
|
||||
#define CHEEVOS_FREE(p) do { void* q = (void*)p; if (q) free(q); } while (0)
|
||||
|
||||
#ifdef CHEEVOS_VERBOSE
|
||||
#define CHEEVOS_LOG RARCH_LOG
|
||||
#define CHEEVOS_ERR RARCH_ERR
|
||||
#else
|
||||
void rcheevos_log(const char *fmt, ...);
|
||||
#define CHEEVOS_LOG rcheevos_log
|
||||
#define CHEEVOS_ERR RARCH_ERR
|
||||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* State *
|
||||
************************************************************************/
|
||||
|
||||
enum
|
||||
{
|
||||
RCHEEVOS_ACTIVE_SOFTCORE = 1 << 0,
|
||||
RCHEEVOS_ACTIVE_HARDCORE = 1 << 1,
|
||||
RCHEEVOS_ACTIVE_UNOFFICIAL = 1 << 2
|
||||
};
|
||||
|
||||
typedef struct rcheevos_racheevo_t
|
||||
{
|
||||
const char* title;
|
||||
const char* description;
|
||||
const char* badge;
|
||||
const char* memaddr;
|
||||
unsigned id;
|
||||
unsigned points;
|
||||
|
||||
retro_time_t unlock_time;
|
||||
uint8_t active;
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
uint8_t menu_bucket;
|
||||
uint8_t menu_progress;
|
||||
uint8_t menu_badge_grayscale;
|
||||
uintptr_t menu_badge_texture;
|
||||
#endif
|
||||
|
||||
} rcheevos_racheevo_t;
|
||||
|
||||
typedef struct rcheevos_ralboard_t
|
||||
{
|
||||
const char* title;
|
||||
const char* description;
|
||||
const char* mem;
|
||||
unsigned id;
|
||||
unsigned format;
|
||||
} rcheevos_ralboard_t;
|
||||
|
||||
typedef struct rcheevos_rapatchdata_t
|
||||
{
|
||||
char* title;
|
||||
rcheevos_racheevo_t* core;
|
||||
rcheevos_racheevo_t* unofficial;
|
||||
rcheevos_ralboard_t* lboards;
|
||||
char* richpresence_script;
|
||||
|
||||
unsigned game_id;
|
||||
unsigned console_id;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
unsigned lboard_count;
|
||||
} rcheevos_rapatchdata_t;
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
|
||||
typedef struct rcheevos_menuitem_t
|
||||
{
|
||||
rcheevos_racheevo_t* cheevo;
|
||||
enum msg_hash_enums state_label_idx;
|
||||
} rcheevos_menuitem_t;
|
||||
|
||||
void rcheevos_menu_reset_badges(void);
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct rcheevos_locals_t
|
||||
{
|
||||
rc_runtime_t runtime; /* rcheevos runtime state */
|
||||
rcheevos_rapatchdata_t patchdata; /* achievement/leaderboard data from the server */
|
||||
rcheevos_memory_regions_t memory; /* achievement addresses to core memory mappings */
|
||||
|
||||
retro_task_t* task; /* load task */
|
||||
#ifdef HAVE_THREADS
|
||||
slock_t* task_lock; /* mutex for starting/stopping load task */
|
||||
enum event_command queued_command; /* action queued by background thread to be run on main thread */
|
||||
#endif
|
||||
|
||||
char token[32]; /* user's session token */
|
||||
char hash[33]; /* retroachievements hash for current content */
|
||||
char user_agent_prefix[128]; /* RetroArch/OS version information */
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
rcheevos_menuitem_t* menuitems; /* array of items for the achievements quick menu */
|
||||
unsigned menuitem_capacity; /* maximum number of items in the menuitems array */
|
||||
unsigned menuitem_count; /* current number of items in the menuitems array */
|
||||
#endif
|
||||
|
||||
bool hardcore_active; /* hardcore functionality is active */
|
||||
bool loaded; /* load task has completed */
|
||||
bool core_supports; /* false if core explicitly disables achievements */
|
||||
bool leaderboards_enabled; /* leaderboards are enabled */
|
||||
bool leaderboard_notifications; /* leaderboard notifications are enabled */
|
||||
bool leaderboard_trackers; /* leaderboard trackers are enabled */
|
||||
} rcheevos_locals_t;
|
||||
|
||||
rcheevos_locals_t* get_rcheevos_locals();
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif /* __RARCH_CHEEVOS_LOCALS_H */
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include "cheevos_memory.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "cheevos_locals.h"
|
||||
|
||||
#include "../retroarch.h"
|
||||
#include "../verbosity.h"
|
||||
|
708
cheevos/cheevos_menu.c
Normal file
708
cheevos/cheevos_menu.c
Normal file
@ -0,0 +1,708 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2019-2021 - Brian Weiss
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "cheevos_locals.h"
|
||||
|
||||
#include "../gfx/gfx_display.h"
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
|
||||
#include "cheevos.h"
|
||||
|
||||
#include "../deps/rcheevos/include/rc_runtime_types.h"
|
||||
|
||||
#include "../file_path_special.h"
|
||||
#include "../menu/menu_driver.h"
|
||||
#include "../menu/menu_entries.h"
|
||||
|
||||
#include <features/features_cpu.h>
|
||||
|
||||
enum rcheevos_menuitem_bucket
|
||||
{
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNKNOWN = 0,
|
||||
RCHEEVOS_MENUITEM_BUCKET_LOCKED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE
|
||||
};
|
||||
|
||||
static void rcheevos_menu_update_bucket(rcheevos_racheevo_t* cheevo)
|
||||
{
|
||||
if (!cheevo->memaddr)
|
||||
{
|
||||
/* non-active unsupported achievement */
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED;
|
||||
}
|
||||
else if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE))
|
||||
{
|
||||
/* non-active unlocked in hardcore achievement */
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNLOCKED;
|
||||
}
|
||||
else
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
rc_trigger_t* trigger;
|
||||
|
||||
if (!rcheevos_locals->hardcore_active && !(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
|
||||
{
|
||||
/* non-active unlocked in softcore achievement in softcore mode */
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNLOCKED;
|
||||
return;
|
||||
}
|
||||
|
||||
/* active achievement */
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_LOCKED;
|
||||
cheevo->menu_progress = 0;
|
||||
|
||||
trigger = rc_runtime_get_achievement(&rcheevos_locals->runtime, cheevo->id);
|
||||
if (trigger)
|
||||
{
|
||||
if (trigger->measured_value && trigger->measured_target)
|
||||
{
|
||||
const unsigned long clamped_value = (unsigned long)
|
||||
MIN(trigger->measured_value, trigger->measured_target);
|
||||
cheevo->menu_progress =
|
||||
(uint8_t)((clamped_value * 100) / trigger->measured_target);
|
||||
}
|
||||
|
||||
if (trigger->state == RC_TRIGGER_STATE_PRIMED)
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE;
|
||||
else if (cheevo->menu_progress >= 80)
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_menu_update_buckets(bool cheevos_test_unofficial)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
rcheevos_menu_update_bucket(cheevo);
|
||||
++cheevo;
|
||||
}
|
||||
|
||||
if (cheevos_test_unofficial)
|
||||
{
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
rcheevos_menu_update_bucket(cheevo);
|
||||
++cheevo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool rcheevos_menu_get_state(unsigned menu_offset, char *buffer, size_t len)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
if (menu_offset < rcheevos_locals->menuitem_count)
|
||||
{
|
||||
const rcheevos_menuitem_t* menuitem = &rcheevos_locals->menuitems[menu_offset];
|
||||
const rcheevos_racheevo_t* cheevo = menuitem->cheevo;
|
||||
if (cheevo)
|
||||
{
|
||||
if (cheevo->menu_progress)
|
||||
{
|
||||
snprintf(buffer, len, "%s - %d%%",
|
||||
msg_hash_to_str(menuitem->state_label_idx),
|
||||
cheevo->menu_progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
strlcpy(buffer, msg_hash_to_str(menuitem->state_label_idx), len);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
buffer[0] = '\0';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rcheevos_menu_get_sublabel(unsigned menu_offset, char *buffer, size_t len)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
if (menu_offset < rcheevos_locals->menuitem_count)
|
||||
{
|
||||
const rcheevos_racheevo_t* cheevo = rcheevos_locals->menuitems[menu_offset].cheevo;
|
||||
if (cheevo && buffer)
|
||||
{
|
||||
strlcpy(buffer, cheevo->description, len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
buffer[0] = '\0';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void rcheevos_menu_reset_badges(void)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
if (cheevo->menu_badge_texture)
|
||||
video_driver_texture_unload(&cheevo->menu_badge_texture);
|
||||
++cheevo;
|
||||
}
|
||||
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
if (cheevo->menu_badge_texture)
|
||||
video_driver_texture_unload(&cheevo->menu_badge_texture);
|
||||
++cheevo;
|
||||
}
|
||||
}
|
||||
|
||||
static rcheevos_menuitem_t* rcheevos_menu_allocate(
|
||||
rcheevos_locals_t* rcheevos_locals, rcheevos_racheevo_t* cheevo)
|
||||
{
|
||||
rcheevos_menuitem_t* menuitem;
|
||||
|
||||
if (rcheevos_locals->menuitem_count == rcheevos_locals->menuitem_capacity)
|
||||
{
|
||||
if (rcheevos_locals->menuitems)
|
||||
{
|
||||
rcheevos_menuitem_t* new_menuitems;
|
||||
rcheevos_locals->menuitem_capacity += 32;
|
||||
new_menuitems = (rcheevos_menuitem_t*)realloc(rcheevos_locals->menuitems,
|
||||
rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
|
||||
|
||||
if (new_menuitems)
|
||||
{
|
||||
rcheevos_locals->menuitems = new_menuitems;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* realloc failed */
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG " could not allocate space for %u menu items\n",
|
||||
rcheevos_locals->menuitem_capacity);
|
||||
rcheevos_locals->menuitem_capacity -= 32;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rcheevos_locals->menuitem_capacity = 64;
|
||||
rcheevos_locals->menuitems = (rcheevos_menuitem_t*)
|
||||
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
|
||||
|
||||
if (!rcheevos_locals->menuitems)
|
||||
{
|
||||
/* malloc failed */
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG " could not allocate space for %u menu items\n",
|
||||
rcheevos_locals->menuitem_capacity);
|
||||
rcheevos_locals->menuitem_capacity = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menuitem = &rcheevos_locals->menuitems[rcheevos_locals->menuitem_count++];
|
||||
menuitem->cheevo = cheevo;
|
||||
menuitem->state_label_idx = MSG_UNKNOWN;
|
||||
return menuitem;
|
||||
}
|
||||
|
||||
static void rcheevos_menu_append_header(rcheevos_locals_t* rcheevos_locals,
|
||||
enum msg_hash_enums label)
|
||||
{
|
||||
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals, NULL);
|
||||
if (menuitem)
|
||||
menuitem->state_label_idx = label;
|
||||
}
|
||||
|
||||
static void rcheevos_menu_update_badge(rcheevos_racheevo_t* cheevo)
|
||||
{
|
||||
bool badge_grayscale = false;
|
||||
switch (cheevo->menu_bucket)
|
||||
{
|
||||
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE:
|
||||
badge_grayscale = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
badge_grayscale = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cheevo->menu_badge_texture || cheevo->menu_badge_grayscale != badge_grayscale)
|
||||
{
|
||||
uintptr_t new_badge_texture =
|
||||
rcheevos_get_badge_texture(cheevo->badge, badge_grayscale);
|
||||
|
||||
if (new_badge_texture)
|
||||
{
|
||||
if (cheevo->menu_badge_texture)
|
||||
video_driver_texture_unload(&cheevo->menu_badge_texture);
|
||||
|
||||
cheevo->menu_badge_texture = new_badge_texture;
|
||||
cheevo->menu_badge_grayscale = badge_grayscale;
|
||||
}
|
||||
/* menu_badge_grayscale is overloaded such that any value greater than 1 indicates
|
||||
* the server default image is being used */
|
||||
else if (cheevo->menu_badge_grayscale < 2)
|
||||
{
|
||||
if (cheevo->menu_badge_texture)
|
||||
video_driver_texture_unload(&cheevo->menu_badge_texture);
|
||||
|
||||
/* requested badge is not available, check for server default */
|
||||
cheevo->menu_badge_texture =
|
||||
rcheevos_get_badge_texture("00000", false);
|
||||
|
||||
if (cheevo->menu_badge_texture)
|
||||
cheevo->menu_badge_grayscale = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_menu_append_items(rcheevos_locals_t* rcheevos_locals,
|
||||
bool cheevos_test_unofficial, enum rcheevos_menuitem_bucket bucket)
|
||||
{
|
||||
const settings_t *settings = config_get_ptr();
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
bool processing_unofficial = false;
|
||||
const unsigned first_index = rcheevos_locals->menuitem_count;
|
||||
|
||||
do
|
||||
{
|
||||
if (cheevo == stop)
|
||||
{
|
||||
if (!cheevos_test_unofficial || processing_unofficial)
|
||||
break;
|
||||
|
||||
processing_unofficial = true;
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cheevo->menu_bucket == bucket)
|
||||
{
|
||||
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals, cheevo);
|
||||
if (!menuitem)
|
||||
return;
|
||||
|
||||
switch (cheevo->menu_bucket)
|
||||
{
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY;
|
||||
break;
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED:
|
||||
{
|
||||
/* insert the item such that the unlock times are descending */
|
||||
unsigned entry_index = rcheevos_locals->menuitem_count - 1;
|
||||
while (entry_index > first_index)
|
||||
{
|
||||
rcheevos_menuitem_t* prev_menuitem = menuitem - 1;
|
||||
if (prev_menuitem->cheevo->unlock_time >= cheevo->unlock_time)
|
||||
break;
|
||||
|
||||
memcpy(menuitem, prev_menuitem, sizeof(rcheevos_menuitem_t));
|
||||
menuitem = prev_menuitem;
|
||||
--entry_index;
|
||||
}
|
||||
|
||||
menuitem->cheevo = cheevo;
|
||||
}
|
||||
/* fallthrough to RCHEEVOS_MENUITEM_BUCKET_UNLOCKED */
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNLOCKED:
|
||||
if (!(cheevo->active & RCHEEVOS_ACTIVE_HARDCORE))
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY_HARDCORE;
|
||||
else
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
|
||||
break;
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
|
||||
{
|
||||
/* insert the item such that the progresses are descending */
|
||||
unsigned entry_index = rcheevos_locals->menuitem_count - 1;
|
||||
while (entry_index > first_index)
|
||||
{
|
||||
rcheevos_menuitem_t* prev_menuitem = menuitem - 1;
|
||||
if (prev_menuitem->cheevo->menu_progress >= cheevo->menu_progress)
|
||||
break;
|
||||
|
||||
memcpy(menuitem, prev_menuitem, sizeof(rcheevos_menuitem_t));
|
||||
menuitem = prev_menuitem;
|
||||
--entry_index;
|
||||
}
|
||||
|
||||
menuitem->cheevo = cheevo;
|
||||
}
|
||||
/* fallthrough to default */
|
||||
|
||||
default:
|
||||
if (processing_unofficial)
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
|
||||
else if (!(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
|
||||
else
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cheevo->badge && cheevo->badge[0] && settings &&
|
||||
settings->bools.cheevos_badges_enable)
|
||||
{
|
||||
rcheevos_menu_update_badge(cheevo);
|
||||
}
|
||||
}
|
||||
|
||||
++cheevo;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
if (menu_offset < rcheevos_locals->menuitem_count)
|
||||
{
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->menuitems[menu_offset].cheevo;
|
||||
if (cheevo)
|
||||
{
|
||||
/* if we're using the placeholder badge, check to see if the real badge
|
||||
* has become available (do this roughly once a second) */
|
||||
if (cheevo->menu_badge_grayscale >= 2)
|
||||
{
|
||||
if (++cheevo->menu_badge_grayscale == 64)
|
||||
{
|
||||
cheevo->menu_badge_grayscale = 2;
|
||||
rcheevos_menu_update_badge(cheevo);
|
||||
}
|
||||
}
|
||||
|
||||
return cheevo->menu_badge_texture;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rcheevos_menu_populate_hardcore_pause_submenu(void* data)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
|
||||
const settings_t* settings = config_get_ptr();
|
||||
const bool cheevos_hardcore_mode_enable = settings->bools.cheevos_hardcore_mode_enable;
|
||||
|
||||
if (cheevos_hardcore_mode_enable && rcheevos_locals->loaded)
|
||||
{
|
||||
if (rcheevos_locals->hardcore_active)
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_CANCEL),
|
||||
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE_CANCEL),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_CANCEL,
|
||||
MENU_SETTING_ACTION_CLOSE, 0, 0);
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE,
|
||||
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME_CANCEL),
|
||||
msg_hash_to_str(MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME_CANCEL),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME_CANCEL,
|
||||
MENU_SETTING_ACTION_CLOSE, 0, 0);
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_ACHIEVEMENT_RESUME),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_RESUME,
|
||||
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rcheevos_menu_populate(void* data)
|
||||
{
|
||||
menu_displaylist_info_t* info = (menu_displaylist_info_t*)data;
|
||||
rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
const settings_t* settings = config_get_ptr();
|
||||
const bool cheevos_test_unofficial = settings->bools.cheevos_test_unofficial;
|
||||
unsigned num_locked = 0;
|
||||
unsigned num_unlocked = 0;
|
||||
unsigned num_recently_unlocked = 0;
|
||||
unsigned num_unsupported = 0;
|
||||
unsigned num_active_challenges = 0;
|
||||
unsigned num_almost_there = 0;
|
||||
|
||||
if (rcheevos_locals->loaded)
|
||||
{
|
||||
const retro_time_t now = cpu_features_get_time_usec();
|
||||
const retro_time_t recent_unlock_time = now - (10 * 60 * 1000000); /* 10 minutes ago */
|
||||
bool processing_unofficial = false;
|
||||
rcheevos_racheevo_t* cheevo = NULL;
|
||||
rcheevos_racheevo_t* stop = NULL;
|
||||
|
||||
/* first menu item is the Pause/Resume Hardcore option (unless hardcore is disabled) */
|
||||
if (settings->bools.cheevos_enable && settings->bools.cheevos_hardcore_mode_enable)
|
||||
{
|
||||
if (rcheevos_locals->hardcore_active)
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
|
||||
MENU_SETTING_ACTION_PAUSE_ACHIEVEMENTS, 0, 0);
|
||||
else
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_RESUME),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_PAUSE_MENU),
|
||||
MENU_ENUM_LABEL_ACHIEVEMENT_PAUSE_MENU,
|
||||
MENU_SETTING_ACTION_RESUME_ACHIEVEMENTS, 0, 0);
|
||||
}
|
||||
|
||||
/* update the bucket for each achievement */
|
||||
rcheevos_menu_update_buckets(cheevos_test_unofficial);
|
||||
|
||||
/* count items in each bucket */
|
||||
cheevo = rcheevos_locals->patchdata.core;
|
||||
stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
|
||||
do
|
||||
{
|
||||
if (cheevo == stop)
|
||||
{
|
||||
if (!cheevos_test_unofficial || processing_unofficial)
|
||||
break;
|
||||
|
||||
processing_unofficial = true;
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cheevo->menu_bucket)
|
||||
{
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNLOCKED:
|
||||
if (cheevo->unlock_time && cheevo->unlock_time >= recent_unlock_time)
|
||||
{
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED;
|
||||
++num_recently_unlocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
++num_unlocked;
|
||||
}
|
||||
break;
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
|
||||
++num_locked;
|
||||
break;
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
|
||||
++num_unsupported;
|
||||
break;
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE:
|
||||
++num_active_challenges;
|
||||
break;
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
|
||||
++num_almost_there;
|
||||
break;
|
||||
}
|
||||
|
||||
++cheevo;
|
||||
} while(true);
|
||||
|
||||
if (!rcheevos_locals->menuitems)
|
||||
{
|
||||
/* reserve space for all achievements and up to 6 headers before we need to realloc */
|
||||
rcheevos_locals->menuitem_capacity = rcheevos_locals->patchdata.core_count + 6;
|
||||
if (cheevos_test_unofficial)
|
||||
rcheevos_locals->menuitem_capacity += rcheevos_locals->patchdata.unofficial_count;
|
||||
|
||||
rcheevos_locals->menuitems = (rcheevos_menuitem_t*)
|
||||
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
|
||||
if (!rcheevos_locals->menuitems)
|
||||
rcheevos_locals->menuitem_capacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset menu */
|
||||
rcheevos_locals->menuitem_count = 0;
|
||||
|
||||
/* active challenges */
|
||||
if (num_active_challenges)
|
||||
{
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY);
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE);
|
||||
}
|
||||
|
||||
/* recently unlocked */
|
||||
if (num_recently_unlocked)
|
||||
{
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY);
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED);
|
||||
}
|
||||
|
||||
/* almost there */
|
||||
if (num_almost_there)
|
||||
{
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY);
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE);
|
||||
}
|
||||
|
||||
/* locked */
|
||||
if (num_locked)
|
||||
{
|
||||
if (rcheevos_locals->menuitem_count > 0)
|
||||
{
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY);
|
||||
}
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
RCHEEVOS_MENUITEM_BUCKET_LOCKED);
|
||||
}
|
||||
|
||||
/* unlocked */
|
||||
if (num_unlocked)
|
||||
{
|
||||
if (rcheevos_locals->menuitem_count > 0)
|
||||
{
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY);
|
||||
}
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED);
|
||||
}
|
||||
|
||||
if (rcheevos_locals->menuitem_count > 0)
|
||||
{
|
||||
/* convert to menu entries */
|
||||
rcheevos_menuitem_t* menuitem = rcheevos_locals->menuitems;
|
||||
rcheevos_menuitem_t* stop = menuitem + rcheevos_locals->menuitem_count;
|
||||
char buffer[128];
|
||||
unsigned idx = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (menuitem->cheevo)
|
||||
{
|
||||
menu_entries_append_enum(info->list, menuitem->cheevo->title,
|
||||
menuitem->cheevo->description,
|
||||
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
|
||||
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(buffer, sizeof(buffer), "----- %s -----",
|
||||
msg_hash_to_str(menuitem->state_label_idx));
|
||||
|
||||
menu_entries_append_enum(info->list, buffer, "",
|
||||
MENU_ENUM_LABEL_CHEEVOS_LOCKED_ENTRY,
|
||||
MENU_SETTINGS_CHEEVOS_START + idx, 0, 0);
|
||||
}
|
||||
|
||||
++idx;
|
||||
++menuitem;
|
||||
} while (menuitem != stop);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no achievements found */
|
||||
if (!rcheevos_locals->core_supports)
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE),
|
||||
MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
else if (!rcheevos_locals->token[0])
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_LOGGED_IN),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NOT_LOGGED_IN),
|
||||
MENU_ENUM_LABEL_NOT_LOGGED_IN,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY),
|
||||
MENU_ENUM_LABEL_NO_ACHIEVEMENTS_TO_DISPLAY,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_MENU */
|
||||
|
||||
uintptr_t rcheevos_get_badge_texture(const char *badge, bool locked)
|
||||
{
|
||||
char badge_file[24];
|
||||
char fullpath[PATH_MAX_LENGTH];
|
||||
uintptr_t tex = 0;
|
||||
|
||||
if (!badge)
|
||||
return 0;
|
||||
|
||||
snprintf(badge_file, sizeof(badge_file), "%s%s%s", badge,
|
||||
locked ? "_lock" : "", FILE_PATH_PNG_EXTENSION);
|
||||
|
||||
fill_pathname_application_special(fullpath, sizeof(fullpath),
|
||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
|
||||
|
||||
if (!gfx_display_reset_textures_list(badge_file, fullpath,
|
||||
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
|
||||
{
|
||||
tex = 0;
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2015-2018 - Andre Leiradella
|
||||
* Copyright (C) 2019-2021 - Brian Weiss
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
@ -13,23 +14,28 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_CHEEVOS_BADGE_H
|
||||
#define __RARCH_CHEEVOS_BADGE_H
|
||||
#ifndef __RARCH_CHEEVOS_MENU_H
|
||||
#define __RARCH_CHEEVOS_MENU_H
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
|
||||
#include <stdint.h>
|
||||
#include <retro_common_api.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
void cheevos_reset_menu_badges(void);
|
||||
void cheevos_set_menu_badge(int index, const char *badge, bool locked);
|
||||
uintptr_t cheevos_get_menu_badge_texture(int index);
|
||||
#endif
|
||||
|
||||
uintptr_t cheevos_get_badge_texture(const char* badge, bool locked);
|
||||
void rcheevos_menu_populate(void* data);
|
||||
void rcheevos_menu_populate_hardcore_pause_submenu(void* data);
|
||||
bool rcheevos_menu_get_state(unsigned menu_offset, char* buffer, size_t buffer_size);
|
||||
bool rcheevos_menu_get_sublabel(unsigned menu_offset, char* buffer, size_t buffer_size);
|
||||
uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
#endif /* HAVE_MENU */
|
||||
|
||||
#endif /* __RARCH_CHEEVOS_MENU_H */
|
@ -1,6 +1,6 @@
|
||||
#include "cheevos_parser.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "cheevos_locals.h"
|
||||
|
||||
#include <encodings/utf.h>
|
||||
#include <formats/rjson.h>
|
||||
|
@ -16,49 +16,10 @@
|
||||
#ifndef __RARCH_CHEEVOS_PARSER_H
|
||||
#define __RARCH_CHEEVOS_PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include "cheevos_locals.h"
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* title;
|
||||
const char* description;
|
||||
const char* badge;
|
||||
const char* memaddr;
|
||||
unsigned points;
|
||||
unsigned id;
|
||||
unsigned active;
|
||||
} rcheevos_racheevo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* title;
|
||||
const char* description;
|
||||
const char* mem;
|
||||
unsigned id;
|
||||
unsigned format;
|
||||
} rcheevos_ralboard_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* title;
|
||||
rcheevos_racheevo_t* core;
|
||||
rcheevos_racheevo_t* unofficial;
|
||||
rcheevos_ralboard_t* lboards;
|
||||
char* richpresence_script;
|
||||
|
||||
unsigned game_id;
|
||||
unsigned console_id;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
unsigned lboard_count;
|
||||
} rcheevos_rapatchdata_t;
|
||||
|
||||
typedef void (*rcheevos_unlock_cb_t)(unsigned id, void* userdata);
|
||||
|
||||
int rcheevos_get_json_error(const char* json, char* token, size_t length);
|
||||
|
@ -1,53 +0,0 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2015-2016 - Andre Leiradella
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_CHEEVOS_UTIL_H
|
||||
#define __RARCH_CHEEVOS_UTIL_H
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/*****************************************************************************
|
||||
Setup - mainly for debugging
|
||||
*****************************************************************************/
|
||||
|
||||
/* Define this macro to get extra-verbose log for cheevos. */
|
||||
#define CHEEVOS_VERBOSE
|
||||
|
||||
/*****************************************************************************
|
||||
End of setup
|
||||
*****************************************************************************/
|
||||
|
||||
#define RCHEEVOS_TAG "[RCHEEVOS]: "
|
||||
#define CHEEVOS_FREE(p) do { void* q = (void*)p; if (q) free(q); } while (0)
|
||||
|
||||
#ifdef CHEEVOS_VERBOSE
|
||||
|
||||
#define CHEEVOS_LOG RARCH_LOG
|
||||
#define CHEEVOS_ERR RARCH_ERR
|
||||
|
||||
#else
|
||||
|
||||
#define CHEEVOS_LOG rcheevos_log
|
||||
#define CHEEVOS_ERR RARCH_ERR
|
||||
|
||||
void rcheevos_log(const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif /* __RARCH_CHEEVOS_UTIL_H */
|
@ -18,7 +18,7 @@
|
||||
#include "../gfx_display.h"
|
||||
#include "../gfx_widgets.h"
|
||||
|
||||
#include "../cheevos/badges.h"
|
||||
#include "../cheevos/cheevos.h"
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#define SLOCK_LOCK(x) slock_lock(x)
|
||||
@ -391,7 +391,7 @@ void gfx_widgets_push_achievement(const char *title, const char *badge)
|
||||
|
||||
/* important - this must be done outside the lock because it has the potential to need to
|
||||
* lock the video thread, which may be waiting for the popup queue lock to render popups */
|
||||
uintptr_t badge_id = cheevos_get_badge_texture(badge, 0);
|
||||
uintptr_t badge_id = rcheevos_get_badge_texture(badge, 0);
|
||||
|
||||
if (state->queue_read_index < 0)
|
||||
{
|
||||
|
@ -191,7 +191,7 @@ ACHIEVEMENTS
|
||||
#include "../network/net_http_special.c"
|
||||
|
||||
#include "../cheevos/cheevos.c"
|
||||
#include "../cheevos/badges.c"
|
||||
#include "../cheevos/cheevos_menu.c"
|
||||
#include "../cheevos/cheevos_memory.c"
|
||||
#include "../cheevos/cheevos_parser.c"
|
||||
|
||||
|
@ -7979,6 +7979,18 @@ MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY,
|
||||
"Unsupported"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY,
|
||||
"Recently Unlocked"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY,
|
||||
"Almost There"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY,
|
||||
"Active Challenges"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_TRACKERS_ONLY,
|
||||
"Trackers Only"
|
||||
|
@ -53,7 +53,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "../../cheevos/cheevos.h"
|
||||
#include "../../cheevos/cheevos_menu.h"
|
||||
#endif
|
||||
|
||||
#ifndef BIND_ACTION_GET_VALUE
|
||||
@ -129,7 +129,7 @@ static void menu_action_setting_disp_set_label_cheevos_entry(
|
||||
*w = 19;
|
||||
strlcpy(s2, path, len2);
|
||||
|
||||
rcheevos_get_achievement_state(type - MENU_SETTINGS_CHEEVOS_START, s, len);
|
||||
rcheevos_menu_get_state(type - MENU_SETTINGS_CHEEVOS_START, s, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "../../core_option_manager.h"
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "../../cheevos/cheevos.h"
|
||||
#include "../../cheevos/cheevos_menu.h"
|
||||
#endif
|
||||
#include "../../core_info.h"
|
||||
#include "../../verbosity.h"
|
||||
@ -1052,20 +1052,8 @@ static int action_bind_sublabel_cheevos_entry(
|
||||
const char *label, const char *path,
|
||||
char *s, size_t len)
|
||||
{
|
||||
rcheevos_ctx_desc_t desc_info;
|
||||
unsigned new_id;
|
||||
char fetched_sublabel[MENU_SUBLABEL_MAX_LENGTH];
|
||||
|
||||
fetched_sublabel[0] = '\0';
|
||||
|
||||
new_id = type - MENU_SETTINGS_CHEEVOS_START;
|
||||
desc_info.idx = new_id;
|
||||
desc_info.s = fetched_sublabel;
|
||||
desc_info.len = len;
|
||||
|
||||
rcheevos_get_description((rcheevos_ctx_desc_t*) &desc_info);
|
||||
|
||||
strlcpy(s, desc_info.s, len);
|
||||
unsigned offset = type - MENU_SETTINGS_CHEEVOS_START;
|
||||
rcheevos_menu_get_sublabel(offset, s, len);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <file/file_path.h>
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "../../../cheevos/badges.h"
|
||||
#include "../../../cheevos/cheevos_menu.h"
|
||||
#endif
|
||||
|
||||
#include "../../../file_path_special.h"
|
||||
@ -464,11 +464,17 @@ uintptr_t ozone_entries_icon_get_texture(ozone_handle_t *ozone,
|
||||
(type < MENU_SETTINGS_NETPLAY_ROOMS_START)
|
||||
)
|
||||
{
|
||||
char buffer[64];
|
||||
int index = type - MENU_SETTINGS_CHEEVOS_START;
|
||||
uintptr_t badge_texture = cheevos_get_menu_badge_texture(index);
|
||||
uintptr_t badge_texture = rcheevos_menu_get_badge_texture(index);
|
||||
if (badge_texture)
|
||||
return badge_texture;
|
||||
/* Should be replaced with placeholder badge icon. */
|
||||
|
||||
/* no state means its a header - show the info icon */
|
||||
if (!rcheevos_menu_get_state(index, buffer, sizeof(buffer)))
|
||||
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INFO];
|
||||
|
||||
/* placeholder badge image was not found, show generic menu icon */
|
||||
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_ACHIEVEMENTS];
|
||||
}
|
||||
#endif
|
||||
|
@ -59,7 +59,7 @@
|
||||
#include "../../tasks/tasks_internal.h"
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "../../cheevos/badges.h"
|
||||
#include "../../cheevos/cheevos_menu.h"
|
||||
#endif
|
||||
#include "../../content.h"
|
||||
|
||||
@ -2905,11 +2905,17 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb,
|
||||
(type < MENU_SETTINGS_NETPLAY_ROOMS_START)
|
||||
)
|
||||
{
|
||||
char buffer[64];
|
||||
int index = type - MENU_SETTINGS_CHEEVOS_START;
|
||||
uintptr_t badge_texture = cheevos_get_menu_badge_texture(index);
|
||||
uintptr_t badge_texture = rcheevos_menu_get_badge_texture(index);
|
||||
if (badge_texture)
|
||||
return badge_texture;
|
||||
/* Should be replaced with placeholder badge icon. */
|
||||
|
||||
/* no state means its a header - show the info icon */
|
||||
if (!rcheevos_menu_get_state(index, buffer, sizeof(buffer)))
|
||||
return xmb->textures.list[XMB_TEXTURE_INFO];
|
||||
|
||||
/* placeholder badge image was not found, show generic menu icon */
|
||||
return xmb->textures.list[XMB_TEXTURE_ACHIEVEMENTS];
|
||||
}
|
||||
#endif
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "../cheevos/cheevos.h"
|
||||
#include "../cheevos/cheevos_menu.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETWORKING
|
||||
@ -10982,7 +10983,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
||||
case DISPLAYLIST_ACHIEVEMENT_PAUSE_MENU:
|
||||
#ifdef HAVE_CHEEVOS
|
||||
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
|
||||
rcheevos_populate_hardcore_pause_menu(info);
|
||||
rcheevos_menu_populate_hardcore_pause_submenu(info);
|
||||
#endif
|
||||
info->need_push = true;
|
||||
info->need_refresh = true;
|
||||
@ -10990,7 +10991,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
||||
case DISPLAYLIST_ACHIEVEMENT_LIST:
|
||||
#ifdef HAVE_CHEEVOS
|
||||
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
|
||||
rcheevos_populate_menu(info);
|
||||
rcheevos_menu_populate(info);
|
||||
#endif
|
||||
info->need_push = true;
|
||||
info->need_refresh = true;
|
||||
|
@ -704,6 +704,9 @@ enum msg_hash_enums
|
||||
MENU_LABEL(CHEEVOS_LOCKED_ENTRY),
|
||||
MENU_LABEL(CHEEVOS_UNSUPPORTED_ENTRY),
|
||||
MENU_LABEL(CHEEVOS_UNOFFICIAL_ENTRY),
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_TRACKERS_ONLY,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_NOTIFICATIONS_ONLY,
|
||||
|
||||
|
10
retroarch.c
10
retroarch.c
@ -174,6 +174,7 @@
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
#include "cheevos/cheevos.h"
|
||||
#include "cheevos/cheevos_menu.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TRANSLATE
|
||||
@ -789,13 +790,8 @@ static int menu_dialog_iterate(
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
case MENU_DIALOG_HELP_CHEEVOS_DESCRIPTION:
|
||||
{
|
||||
rcheevos_ctx_desc_t desc_info;
|
||||
desc_info.idx = p_dialog->current_id;
|
||||
desc_info.s = s;
|
||||
desc_info.len = len;
|
||||
rcheevos_get_description((rcheevos_ctx_desc_t*) &desc_info);
|
||||
}
|
||||
if (!rcheevos_menu_get_sublabel(p_dialog->current_id, s, len))
|
||||
return 1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user