mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-02-06 14:25:39 +00:00
Achievements: Backports from PCSX2
This commit is contained in:
parent
6d32e9bc10
commit
550b4928c2
|
@ -347,6 +347,7 @@ void Settings::Load(SettingsInterface& si)
|
||||||
achievements_challenge_mode = si.GetBoolValue("Cheevos", "ChallengeMode", false);
|
achievements_challenge_mode = si.GetBoolValue("Cheevos", "ChallengeMode", false);
|
||||||
achievements_leaderboards = si.GetBoolValue("Cheevos", "Leaderboards", true);
|
achievements_leaderboards = si.GetBoolValue("Cheevos", "Leaderboards", true);
|
||||||
achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true);
|
achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true);
|
||||||
|
achievements_primed_indicators = si.GetBoolValue("Cheevos", "PrimedIndicators", true);
|
||||||
|
|
||||||
log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str())
|
log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str())
|
||||||
.value_or(DEFAULT_LOG_LEVEL);
|
.value_or(DEFAULT_LOG_LEVEL);
|
||||||
|
@ -534,6 +535,7 @@ void Settings::Save(SettingsInterface& si) const
|
||||||
si.SetBoolValue("Cheevos", "ChallengeMode", achievements_challenge_mode);
|
si.SetBoolValue("Cheevos", "ChallengeMode", achievements_challenge_mode);
|
||||||
si.SetBoolValue("Cheevos", "Leaderboards", achievements_leaderboards);
|
si.SetBoolValue("Cheevos", "Leaderboards", achievements_leaderboards);
|
||||||
si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects);
|
si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects);
|
||||||
|
si.SetBoolValue("Cheevos", "PrimedIndicators", achievements_primed_indicators);
|
||||||
|
|
||||||
si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level));
|
si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level));
|
||||||
si.SetStringValue("Logging", "LogFilter", log_filter.c_str());
|
si.SetStringValue("Logging", "LogFilter", log_filter.c_str());
|
||||||
|
|
|
@ -178,6 +178,7 @@ struct Settings
|
||||||
bool achievements_challenge_mode : 1;
|
bool achievements_challenge_mode : 1;
|
||||||
bool achievements_leaderboards : 1;
|
bool achievements_leaderboards : 1;
|
||||||
bool achievements_sound_effects : 1;
|
bool achievements_sound_effects : 1;
|
||||||
|
bool achievements_primed_indicators : 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct DebugSettings
|
struct DebugSettings
|
||||||
|
|
|
@ -26,6 +26,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
|
||||||
"UseFirstDiscFromPlaylist", true);
|
"UseFirstDiscFromPlaylist", true);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboards, "Cheevos", "Leaderboards", true);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboards, "Cheevos", "Leaderboards", true);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Cheevos", "SoundEffects", true);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Cheevos", "SoundEffects", true);
|
||||||
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.primedIndicators, "Cheevos", "PrimedIndicators", true);
|
||||||
|
|
||||||
dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"),
|
dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"),
|
||||||
tr("When enabled and logged in, DuckStation will scan for achievements on startup."));
|
tr("When enabled and logged in, DuckStation will scan for achievements on startup."));
|
||||||
|
@ -53,6 +54,9 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
|
||||||
m_ui.leaderboards, tr("Enable Leaderboards"), tr("Checked"),
|
m_ui.leaderboards, tr("Enable Leaderboards"), tr("Checked"),
|
||||||
tr("Enables tracking and submission of leaderboards in supported games. If leaderboards "
|
tr("Enables tracking and submission of leaderboards in supported games. If leaderboards "
|
||||||
"are disabled, you will still be able to view the leaderboard and scores, but no scores will be uploaded."));
|
"are disabled, you will still be able to view the leaderboard and scores, but no scores will be uploaded."));
|
||||||
|
dialog->registerWidgetHelp(
|
||||||
|
m_ui.primedIndicators, tr("Show Challenge Indicators"), tr("Checked"),
|
||||||
|
tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active."));
|
||||||
|
|
||||||
connect(m_ui.enable, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
|
connect(m_ui.enable, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
|
||||||
connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
|
connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
|
||||||
|
@ -95,6 +99,7 @@ void AchievementSettingsWidget::updateEnableState()
|
||||||
m_ui.leaderboards->setEnabled(enabled && challenge);
|
m_ui.leaderboards->setEnabled(enabled && challenge);
|
||||||
m_ui.unofficialTestMode->setEnabled(enabled);
|
m_ui.unofficialTestMode->setEnabled(enabled);
|
||||||
m_ui.soundEffects->setEnabled(enabled);
|
m_ui.soundEffects->setEnabled(enabled);
|
||||||
|
m_ui.primedIndicators->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementSettingsWidget::onChallengeModeStateChanged()
|
void AchievementSettingsWidget::onChallengeModeStateChanged()
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>648</width>
|
<width>648</width>
|
||||||
<height>456</height>
|
<height>475</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -32,13 +32,6 @@
|
||||||
<string>Global Settings</string>
|
<string>Global Settings</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QCheckBox" name="enable">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable Achievements</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="unofficialTestMode">
|
<widget class="QCheckBox" name="unofficialTestMode">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -46,27 +39,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QCheckBox" name="richPresence">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable Rich Presence</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QCheckBox" name="testMode">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable Test Mode</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QCheckBox" name="challengeMode">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable Hardcore Mode</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QCheckBox" name="soundEffects">
|
<widget class="QCheckBox" name="soundEffects">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -74,10 +46,10 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QCheckBox" name="useFirstDiscFromPlaylist">
|
<widget class="QCheckBox" name="enable">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Use First Disc From Playlist</string>
|
<string>Enable Achievements</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -88,6 +60,41 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="primedIndicators">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show Challenge Indicators</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QCheckBox" name="richPresence">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Rich Presence</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QCheckBox" name="challengeMode">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Hardcore Mode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QCheckBox" name="useFirstDiscFromPlaylist">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use First Disc From Playlist</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QCheckBox" name="testMode">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Test Mode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -130,7 +137,7 @@
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>0</width>
|
<width>0</width>
|
||||||
<height>160</height>
|
<height>120</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
|
|
@ -867,7 +867,7 @@ void Achievements::LoginCallback(s32 status_code, std::string content_type, Comm
|
||||||
|
|
||||||
RAPIResponse<rc_api_login_response_t, rc_api_process_login_response, rc_api_destroy_login_response> response(
|
RAPIResponse<rc_api_login_response_t, rc_api_process_login_response, rc_api_destroy_login_response> response(
|
||||||
status_code, data);
|
status_code, data);
|
||||||
if (!response)
|
if (!response || !response.username || !response.api_token)
|
||||||
{
|
{
|
||||||
FormattedError("Login failed. Please check your user name and password, and try again.");
|
FormattedError("Login failed. Please check your user name and password, and try again.");
|
||||||
return;
|
return;
|
||||||
|
@ -1104,7 +1104,7 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
||||||
|
|
||||||
std::unique_lock lock(s_achievements_mutex);
|
std::unique_lock lock(s_achievements_mutex);
|
||||||
ClearGameInfo();
|
ClearGameInfo();
|
||||||
if (!response)
|
if (!response || !response.title)
|
||||||
{
|
{
|
||||||
DisableChallengeMode();
|
DisableChallengeMode();
|
||||||
return;
|
return;
|
||||||
|
@ -1117,7 +1117,7 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
||||||
s_game_title = response.title;
|
s_game_title = response.title;
|
||||||
|
|
||||||
// try for a icon
|
// try for a icon
|
||||||
if (std::strlen(response.image_name) > 0)
|
if (response.image_name && std::strlen(response.image_name) > 0)
|
||||||
{
|
{
|
||||||
s_game_icon = Path::Combine(s_game_icon_cache_directory, fmt::format("{}.png", s_game_id));
|
s_game_icon = Path::Combine(s_game_icon_cache_directory, fmt::format("{}.png", s_game_id));
|
||||||
if (!FileSystem::FileExists(s_game_icon.c_str()))
|
if (!FileSystem::FileExists(s_game_icon.c_str()))
|
||||||
|
@ -1155,6 +1155,12 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!defn.definition || !defn.title || !defn.description || !defn.badge_name)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Incomplete achievement %u", defn.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Achievement cheevo;
|
Achievement cheevo;
|
||||||
cheevo.id = defn.id;
|
cheevo.id = defn.id;
|
||||||
cheevo.memaddr = defn.definition;
|
cheevo.memaddr = defn.definition;
|
||||||
|
@ -1172,6 +1178,11 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
||||||
for (u32 i = 0; i < response.num_leaderboards; i++)
|
for (u32 i = 0; i < response.num_leaderboards; i++)
|
||||||
{
|
{
|
||||||
const rc_api_leaderboard_definition_t& defn = response.leaderboards[i];
|
const rc_api_leaderboard_definition_t& defn = response.leaderboards[i];
|
||||||
|
if (!defn.title || !defn.description || !defn.definition)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Incomplete achievement %u", defn.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Leaderboard lboard;
|
Leaderboard lboard;
|
||||||
lboard.id = defn.id;
|
lboard.id = defn.id;
|
||||||
|
@ -1192,7 +1203,7 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse rich presence
|
// parse rich presence
|
||||||
if (std::strlen(response.rich_presence_script) > 0)
|
if (response.rich_presence_script && std::strlen(response.rich_presence_script) > 0)
|
||||||
{
|
{
|
||||||
const int res = rc_runtime_activate_richpresence(&s_rcheevos_runtime, response.rich_presence_script, nullptr, 0);
|
const int res = rc_runtime_activate_richpresence(&s_rcheevos_runtime, response.rich_presence_script, nullptr, 0);
|
||||||
if (res == RC_OK)
|
if (res == RC_OK)
|
||||||
|
@ -1263,6 +1274,8 @@ void Achievements::GetLbInfoCallback(s32 status_code, std::string content_type,
|
||||||
for (u32 i = 0; i < response.num_entries; i++)
|
for (u32 i = 0; i < response.num_entries; i++)
|
||||||
{
|
{
|
||||||
const rc_api_lboard_info_entry_t& entry = response.entries[i];
|
const rc_api_lboard_info_entry_t& entry = response.entries[i];
|
||||||
|
if (!entry.username)
|
||||||
|
continue;
|
||||||
|
|
||||||
char score[128];
|
char score[128];
|
||||||
rc_runtime_format_lboard_value(score, sizeof(score), entry.score, leaderboard->format);
|
rc_runtime_format_lboard_value(score, sizeof(score), entry.score, leaderboard->format);
|
||||||
|
@ -1903,16 +1916,18 @@ TinyString Achievements::GetAchievementProgressText(const Achievement& achieveme
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Achievements::GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing)
|
const std::string& Achievements::GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing,
|
||||||
|
bool force_unlocked_icon)
|
||||||
{
|
{
|
||||||
std::string& badge_path = achievement.locked ? achievement.locked_badge_path : achievement.unlocked_badge_path;
|
const bool use_locked = (achievement.locked && !force_unlocked_icon);
|
||||||
|
std::string& badge_path = use_locked ? achievement.locked_badge_path : achievement.unlocked_badge_path;
|
||||||
if (!badge_path.empty() || achievement.badge_name.empty())
|
if (!badge_path.empty() || achievement.badge_name.empty())
|
||||||
return badge_path;
|
return badge_path;
|
||||||
|
|
||||||
// well, this comes from the internet.... :)
|
// well, this comes from the internet.... :)
|
||||||
const std::string clean_name(Path::SanitizeFileName(achievement.badge_name));
|
const std::string clean_name(Path::SanitizeFileName(achievement.badge_name));
|
||||||
badge_path = Path::Combine(s_achievement_icon_cache_directory,
|
badge_path =
|
||||||
fmt::format("{}{}.png", clean_name, achievement.locked ? "_lock" : ""));
|
Path::Combine(s_achievement_icon_cache_directory, fmt::format("{}{}.png", clean_name, use_locked ? "_lock" : ""));
|
||||||
if (FileSystem::FileExists(badge_path.c_str()))
|
if (FileSystem::FileExists(badge_path.c_str()))
|
||||||
return badge_path;
|
return badge_path;
|
||||||
|
|
||||||
|
@ -1921,7 +1936,7 @@ const std::string& Achievements::GetAchievementBadgePath(const Achievement& achi
|
||||||
{
|
{
|
||||||
RAPIRequest<rc_api_fetch_image_request_t, rc_api_init_fetch_image_request> request;
|
RAPIRequest<rc_api_fetch_image_request_t, rc_api_init_fetch_image_request> request;
|
||||||
request.image_name = achievement.badge_name.c_str();
|
request.image_name = achievement.badge_name.c_str();
|
||||||
request.image_type = achievement.locked ? RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED : RC_IMAGE_TYPE_ACHIEVEMENT;
|
request.image_type = use_locked ? RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED : RC_IMAGE_TYPE_ACHIEVEMENT;
|
||||||
request.DownloadImage(badge_path);
|
request.DownloadImage(badge_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,8 @@ u32 GetPrimedAchievementCount();
|
||||||
const Achievement* GetAchievementByID(u32 id);
|
const Achievement* GetAchievementByID(u32 id);
|
||||||
std::pair<u32, u32> GetAchievementProgress(const Achievement& achievement);
|
std::pair<u32, u32> GetAchievementProgress(const Achievement& achievement);
|
||||||
TinyString GetAchievementProgressText(const Achievement& achievement);
|
TinyString GetAchievementProgressText(const Achievement& achievement);
|
||||||
const std::string& GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing = true);
|
const std::string& GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing = true,
|
||||||
|
bool force_unlocked_icon = false);
|
||||||
std::string GetAchievementBadgeURL(const Achievement& achievement);
|
std::string GetAchievementBadgeURL(const Achievement& achievement);
|
||||||
|
|
||||||
#ifdef WITH_RAINTEGRATION
|
#ifdef WITH_RAINTEGRATION
|
||||||
|
|
|
@ -427,7 +427,8 @@ static GameListPage s_game_list_page = GameListPage::Grid;
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
static void DrawAchievementsWindow();
|
static void DrawAchievementsWindow();
|
||||||
static void DrawAchievement(const Achievements::Achievement& cheevo);
|
static void DrawAchievement(const Achievements::Achievement& cheevo);
|
||||||
static void DrawPrimedAchievements();
|
static void DrawPrimedAchievementsIcons();
|
||||||
|
static void DrawPrimedAchievementsList();
|
||||||
static void DrawLeaderboardsWindow();
|
static void DrawLeaderboardsWindow();
|
||||||
static void DrawLeaderboardListEntry(const Achievements::Leaderboard& lboard);
|
static void DrawLeaderboardListEntry(const Achievements::Leaderboard& lboard);
|
||||||
static void DrawLeaderboardEntry(const Achievements::LeaderboardEntry& lbEntry, float rank_column_width,
|
static void DrawLeaderboardEntry(const Achievements::LeaderboardEntry& lbEntry, float rank_column_width,
|
||||||
|
@ -723,8 +724,11 @@ void FullscreenUI::Render()
|
||||||
|
|
||||||
#ifdef WITH_CHEEVOS
|
#ifdef WITH_CHEEVOS
|
||||||
// Primed achievements must come first, because we don't want the pause screen to be behind them.
|
// Primed achievements must come first, because we don't want the pause screen to be behind them.
|
||||||
if (Achievements::GetPrimedAchievementCount() > 0)
|
if (g_settings.achievements_primed_indicators && s_current_main_window == MainWindowType::None &&
|
||||||
DrawPrimedAchievements();
|
Achievements::GetPrimedAchievementCount() > 0)
|
||||||
|
{
|
||||||
|
DrawPrimedAchievementsIcons();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (s_current_main_window)
|
switch (s_current_main_window)
|
||||||
|
@ -3579,6 +3583,10 @@ void FullscreenUI::DrawAchievementsSettingsPage()
|
||||||
DrawToggleSetting(bsi, ICON_FA_HEADPHONES " Sound Effects",
|
DrawToggleSetting(bsi, ICON_FA_HEADPHONES " Sound Effects",
|
||||||
"Plays sound effects for events such as achievement unlocks and leaderboard submissions.",
|
"Plays sound effects for events such as achievement unlocks and leaderboard submissions.",
|
||||||
"Cheevos", "SoundEffects", true, enabled);
|
"Cheevos", "SoundEffects", true, enabled);
|
||||||
|
DrawToggleSetting(
|
||||||
|
bsi, ICON_FA_MAGIC " Show Challenge Indicators",
|
||||||
|
"Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active.", "Cheevos",
|
||||||
|
"PrimedIndicators", true, enabled);
|
||||||
DrawToggleSetting(bsi, ICON_FA_MEDAL " Test Unofficial Achievements",
|
DrawToggleSetting(bsi, ICON_FA_MEDAL " Test Unofficial Achievements",
|
||||||
"When enabled, DuckStation will list achievements from unofficial sets. These achievements are not "
|
"When enabled, DuckStation will list achievements from unofficial sets. These achievements are not "
|
||||||
"tracked by RetroAchievements.",
|
"tracked by RetroAchievements.",
|
||||||
|
@ -4036,6 +4044,11 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
|
||||||
|
|
||||||
EndFullscreenWindow();
|
EndFullscreenWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_CHEEVOS
|
||||||
|
if (Achievements::GetPrimedAchievementCount() > 0)
|
||||||
|
DrawPrimedAchievementsList();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::InitializePlaceholderSaveStateListEntry(SaveStateListEntry* li, const std::string& title,
|
void FullscreenUI::InitializePlaceholderSaveStateListEntry(SaveStateListEntry* li, const std::string& title,
|
||||||
|
@ -5572,7 +5585,7 @@ void FullscreenUI::DrawAchievementsWindow()
|
||||||
EndFullscreenWindow();
|
EndFullscreenWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::DrawPrimedAchievements()
|
void FullscreenUI::DrawPrimedAchievementsIcons()
|
||||||
{
|
{
|
||||||
const ImVec2 image_size(LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT, LAYOUT_MENU_BUTTON_HEIGHT));
|
const ImVec2 image_size(LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT, LAYOUT_MENU_BUTTON_HEIGHT));
|
||||||
const float spacing = LayoutScale(10.0f);
|
const float spacing = LayoutScale(10.0f);
|
||||||
|
@ -5588,7 +5601,7 @@ void FullscreenUI::DrawPrimedAchievements()
|
||||||
if (!achievement.primed)
|
if (!achievement.primed)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const std::string& badge_path = Achievements::GetAchievementBadgePath(achievement);
|
const std::string& badge_path = Achievements::GetAchievementBadgePath(achievement, true, true);
|
||||||
if (badge_path.empty())
|
if (badge_path.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -5603,6 +5616,80 @@ void FullscreenUI::DrawPrimedAchievements()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FullscreenUI::DrawPrimedAchievementsList()
|
||||||
|
{
|
||||||
|
auto lock = Achievements::GetLock();
|
||||||
|
const u32 primed_count = Achievements::GetPrimedAchievementCount();
|
||||||
|
|
||||||
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImFont* font = g_medium_font;
|
||||||
|
|
||||||
|
const ImVec2 image_size(LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY));
|
||||||
|
const float margin = LayoutScale(10.0f);
|
||||||
|
const float spacing = LayoutScale(10.0f);
|
||||||
|
const float padding = LayoutScale(10.0f);
|
||||||
|
|
||||||
|
const float max_text_width = LayoutScale(300.0f);
|
||||||
|
const float row_width = max_text_width + padding + padding + image_size.x + spacing;
|
||||||
|
const float title_height = padding + font->FontSize + padding;
|
||||||
|
const ImVec2 box_min(io.DisplaySize.x - row_width - margin, margin);
|
||||||
|
const ImVec2 box_max(box_min.x + row_width,
|
||||||
|
box_min.y + title_height + (static_cast<float>(primed_count) * (image_size.y + padding)));
|
||||||
|
|
||||||
|
ImDrawList* dl = ImGui::GetBackgroundDrawList();
|
||||||
|
dl->AddRectFilled(box_min, box_max, IM_COL32(0x21, 0x21, 0x21, 200), LayoutScale(10.0f));
|
||||||
|
dl->AddText(font, font->FontSize, ImVec2(box_min.x + padding, box_min.y + padding), IM_COL32(255, 255, 255, 255),
|
||||||
|
"Active Challenge Achievements");
|
||||||
|
|
||||||
|
const float y_advance = image_size.y + spacing;
|
||||||
|
const float acheivement_name_offset = (image_size.y - font->FontSize) / 2.0f;
|
||||||
|
const float max_non_ellipised_text_width = max_text_width - LayoutScale(10.0f);
|
||||||
|
ImVec2 position(box_min.x + padding, box_min.y + title_height);
|
||||||
|
|
||||||
|
Achievements::EnumerateAchievements([font, &image_size, max_text_width, spacing, y_advance, acheivement_name_offset,
|
||||||
|
max_non_ellipised_text_width,
|
||||||
|
&position](const Achievements::Achievement& achievement) {
|
||||||
|
if (!achievement.primed)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const std::string& badge_path = Achievements::GetAchievementBadgePath(achievement, true, true);
|
||||||
|
if (badge_path.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
GPUTexture* badge = GetCachedTextureAsync(badge_path.c_str());
|
||||||
|
if (!badge)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
ImDrawList* dl = ImGui::GetBackgroundDrawList();
|
||||||
|
dl->AddImage(badge, position, position + image_size);
|
||||||
|
|
||||||
|
const char* achievement_title = achievement.title.c_str();
|
||||||
|
const char* achievement_tile_end = achievement_title + achievement.title.length();
|
||||||
|
const char* remaining_text = nullptr;
|
||||||
|
const ImVec2 text_width(font->CalcTextSizeA(font->FontSize, max_non_ellipised_text_width, 0.0f, achievement_title,
|
||||||
|
achievement_tile_end, &remaining_text));
|
||||||
|
const ImVec2 text_position(position.x + image_size.x + spacing, position.y + acheivement_name_offset);
|
||||||
|
const ImVec4 text_bbox(text_position.x, text_position.y, text_position.x + max_text_width,
|
||||||
|
text_position.y + image_size.y);
|
||||||
|
const u32 text_color = IM_COL32(255, 255, 255, 255);
|
||||||
|
|
||||||
|
if (remaining_text < achievement_tile_end)
|
||||||
|
{
|
||||||
|
dl->AddText(font, font->FontSize, text_position, text_color, achievement_title, remaining_text, 0.0f, &text_bbox);
|
||||||
|
dl->AddText(font, font->FontSize, ImVec2(text_position.x + text_width.x, text_position.y), text_color, "...",
|
||||||
|
nullptr, 0.0f, &text_bbox);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dl->AddText(font, font->FontSize, text_position, text_color, achievement_title,
|
||||||
|
achievement_title + achievement.title.length(), 0.0f, &text_bbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
position.y += y_advance;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool FullscreenUI::OpenLeaderboardsWindow()
|
bool FullscreenUI::OpenLeaderboardsWindow()
|
||||||
{
|
{
|
||||||
if (!System::IsValid() || !Achievements::HasActiveGame() || Achievements::GetLeaderboardCount() == 0 || !Initialize())
|
if (!System::IsValid() || !Achievements::HasActiveGame() || Achievements::GetLeaderboardCount() == 0 || !Initialize())
|
||||||
|
|
|
@ -2145,7 +2145,7 @@ void ImGuiFullscreen::DrawMessageDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
static float s_notification_vertical_position = 0.3f;
|
static float s_notification_vertical_position = 0.3f;
|
||||||
static float s_notification_vertical_direction = -1.0f;
|
static float s_notification_vertical_direction = 1.0f;
|
||||||
|
|
||||||
float ImGuiFullscreen::GetNotificationVerticalPosition()
|
float ImGuiFullscreen::GetNotificationVerticalPosition()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue