mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Achievement Unlocked and Leaderboard Submitted sound effects
This commit is contained in:
parent
277790f18e
commit
af92430b18
@ -21,7 +21,7 @@ static bool focusMovementEnabled;
|
|||||||
bool focusForced;
|
bool focusForced;
|
||||||
static std::mutex eventMutex_;
|
static std::mutex eventMutex_;
|
||||||
|
|
||||||
static std::function<void(UISound)> soundCallback;
|
static std::function<void(UISound, float)> soundCallback;
|
||||||
static bool soundEnabled = true;
|
static bool soundEnabled = true;
|
||||||
|
|
||||||
struct DispatchQueueItem {
|
struct DispatchQueueItem {
|
||||||
@ -158,13 +158,13 @@ void SetSoundEnabled(bool enabled) {
|
|||||||
soundEnabled = enabled;
|
soundEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSoundCallback(std::function<void(UISound)> func) {
|
void SetSoundCallback(std::function<void(UISound, float)> func) {
|
||||||
soundCallback = func;
|
soundCallback = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayUISound(UISound sound) {
|
void PlayUISound(UISound sound, float volume) {
|
||||||
if (soundEnabled && soundCallback) {
|
if (soundEnabled && soundCallback) {
|
||||||
soundCallback(sound);
|
soundCallback(sound, volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,12 +43,14 @@ enum class UISound {
|
|||||||
CONFIRM,
|
CONFIRM,
|
||||||
TOGGLE_ON,
|
TOGGLE_ON,
|
||||||
TOGGLE_OFF,
|
TOGGLE_OFF,
|
||||||
|
ACHIEVEMENT_UNLOCKED,
|
||||||
|
LEADERBOARD_SUBMITTED,
|
||||||
COUNT,
|
COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetSoundEnabled(bool enabled);
|
void SetSoundEnabled(bool enabled);
|
||||||
void SetSoundCallback(std::function<void(UISound)> func);
|
void SetSoundCallback(std::function<void(UISound, float)> func);
|
||||||
|
|
||||||
void PlayUISound(UISound sound);
|
void PlayUISound(UISound sound, float volume = 0.25f);
|
||||||
|
|
||||||
} // namespace UI
|
} // namespace UI
|
||||||
|
@ -261,10 +261,14 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t *
|
|||||||
case RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED:
|
case RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED:
|
||||||
// An achievement was earned by the player. The handler should notify the player that the achievement was earned.
|
// An achievement was earned by the player. The handler should notify the player that the achievement was earned.
|
||||||
g_OSD.ShowAchievementUnlocked(event->achievement->id);
|
g_OSD.ShowAchievementUnlocked(event->achievement->id);
|
||||||
|
System_PostUIMessage("play_sound", "achievement_unlocked");
|
||||||
INFO_LOG(ACHIEVEMENTS, "Achievement unlocked: '%s' (%d)", event->achievement->title, event->achievement->id);
|
INFO_LOG(ACHIEVEMENTS, "Achievement unlocked: '%s' (%d)", event->achievement->title, event->achievement->id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RC_CLIENT_EVENT_GAME_COMPLETED:
|
case RC_CLIENT_EVENT_GAME_COMPLETED:
|
||||||
{
|
{
|
||||||
|
// TODO: Do some zany fireworks!
|
||||||
|
|
||||||
// All achievements for the game have been earned. The handler should notify the player that the game was completed or mastered, depending on challenge mode.
|
// All achievements for the game have been earned. The handler should notify the player that the game was completed or mastered, depending on challenge mode.
|
||||||
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
|
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
|
||||||
|
|
||||||
@ -279,6 +283,8 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t *
|
|||||||
|
|
||||||
g_OSD.Show(OSDType::MESSAGE_INFO, title, message, DeNull(gameInfo->badge_name), 10.0f);
|
g_OSD.Show(OSDType::MESSAGE_INFO, title, message, DeNull(gameInfo->badge_name), 10.0f);
|
||||||
|
|
||||||
|
System_PostUIMessage("play_sound", "achievement_unlocked");
|
||||||
|
|
||||||
INFO_LOG(ACHIEVEMENTS, "%s", message.c_str());
|
INFO_LOG(ACHIEVEMENTS, "%s", message.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -295,7 +301,7 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t *
|
|||||||
case RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED:
|
case RC_CLIENT_EVENT_LEADERBOARD_SUBMITTED:
|
||||||
NOTICE_LOG(ACHIEVEMENTS, "Leaderboard result submitted: %s", event->leaderboard->title);
|
NOTICE_LOG(ACHIEVEMENTS, "Leaderboard result submitted: %s", event->leaderboard->title);
|
||||||
g_OSD.Show(OSDType::MESSAGE_SUCCESS, ReplaceAll(ReplaceAll(ac->T("%1: Submitting leaderboard score: %2!"), "%1", DeNull(event->leaderboard->title)), "%2", DeNull(event->leaderboard->tracker_value)), DeNull(event->leaderboard->description), 3.0f);
|
g_OSD.Show(OSDType::MESSAGE_SUCCESS, ReplaceAll(ReplaceAll(ac->T("%1: Submitting leaderboard score: %2!"), "%1", DeNull(event->leaderboard->title)), "%2", DeNull(event->leaderboard->tracker_value)), DeNull(event->leaderboard->description), 3.0f);
|
||||||
// A leaderboard attempt was completed.The handler may show a message with the leaderboard title and /or description indicating the final value being submitted to the server.
|
System_PostUIMessage("play_sound", "leaderboard_submitted");
|
||||||
break;
|
break;
|
||||||
case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW:
|
case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW:
|
||||||
NOTICE_LOG(ACHIEVEMENTS, "Challenge indicator show: %s", event->achievement->title);
|
NOTICE_LOG(ACHIEVEMENTS, "Challenge indicator show: %s", event->achievement->title);
|
||||||
|
@ -381,12 +381,17 @@ void SoundEffectMixer::Mix(int16_t *buffer, int sz, int sampleRateHz) {
|
|||||||
|
|
||||||
for (std::vector<PlayInstance>::iterator iter = plays_.begin(); iter != plays_.end(); ) {
|
for (std::vector<PlayInstance>::iterator iter = plays_.begin(); iter != plays_.end(); ) {
|
||||||
auto sample = samples_[(int)iter->sound].get();
|
auto sample = samples_[(int)iter->sound].get();
|
||||||
|
if (!sample) {
|
||||||
|
// Remove playback instance if sample invalid.
|
||||||
|
iter = plays_.erase(iter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t rateOfSample = sample->rateInHz_;
|
int64_t rateOfSample = sample->rateInHz_;
|
||||||
int64_t stride = (rateOfSample << 32) / sampleRateHz;
|
int64_t stride = (rateOfSample << 32) / sampleRateHz;
|
||||||
|
|
||||||
for (int i = 0; i < sz * 2; i += 2) {
|
for (int i = 0; i < sz * 2; i += 2) {
|
||||||
if (!sample || (iter->offset >> 32) >= sample->length_ - 2) {
|
if ((iter->offset >> 32) >= sample->length_ - 2) {
|
||||||
iter->done = true;
|
iter->done = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -415,15 +420,16 @@ void SoundEffectMixer::Mix(int16_t *buffer, int sz, int sampleRateHz) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundEffectMixer::Play(UI::UISound sfx) {
|
void SoundEffectMixer::Play(UI::UISound sfx, float volume) {
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
plays_.push_back(PlayInstance{ sfx, 0, 64, false });
|
plays_.push_back(PlayInstance{ sfx, 0, (int)(255.0f * volume), false });
|
||||||
}
|
}
|
||||||
|
|
||||||
Sample *SoundEffectMixer::LoadSample(const std::string &path) {
|
Sample *SoundEffectMixer::LoadSample(const std::string &path) {
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
uint8_t *data = g_VFS.ReadFile(path.c_str(), &bytes);
|
uint8_t *data = g_VFS.ReadFile(path.c_str(), &bytes);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
WARN_LOG(AUDIO, "Failed to load sample '%s'", path.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,8 +457,10 @@ void SoundEffectMixer::LoadSamples() {
|
|||||||
samples_[(size_t)UI::UISound::CONFIRM] = std::unique_ptr<Sample>(LoadSample("sfx_confirm.wav"));
|
samples_[(size_t)UI::UISound::CONFIRM] = std::unique_ptr<Sample>(LoadSample("sfx_confirm.wav"));
|
||||||
samples_[(size_t)UI::UISound::TOGGLE_ON] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_on.wav"));
|
samples_[(size_t)UI::UISound::TOGGLE_ON] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_on.wav"));
|
||||||
samples_[(size_t)UI::UISound::TOGGLE_OFF] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_off.wav"));
|
samples_[(size_t)UI::UISound::TOGGLE_OFF] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_off.wav"));
|
||||||
|
samples_[(size_t)UI::UISound::ACHIEVEMENT_UNLOCKED] = std::unique_ptr<Sample>(LoadSample("sfx_achievement_unlocked.wav"));
|
||||||
|
samples_[(size_t)UI::UISound::LEADERBOARD_SUBMITTED] = std::unique_ptr<Sample>(LoadSample("sfx_leaderbord_submitted.wav"));
|
||||||
|
|
||||||
UI::SetSoundCallback([](UI::UISound sound) {
|
UI::SetSoundCallback([](UI::UISound sound, float volume) {
|
||||||
g_BackgroundAudio.SFX().Play(sound);
|
g_BackgroundAudio.SFX().Play(sound, volume);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
void LoadSamples();
|
void LoadSamples();
|
||||||
|
|
||||||
void Mix(int16_t *buffer, int sz, int sampleRateHz);
|
void Mix(int16_t *buffer, int sz, int sampleRateHz);
|
||||||
void Play(UI::UISound sfx);
|
void Play(UI::UISound sfx, float volume);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Sample>> samples_;
|
std::vector<std::unique_ptr<Sample>> samples_;
|
||||||
|
|
||||||
|
@ -544,6 +544,16 @@ void EmuScreen::sendMessage(const char *message, const char *value) {
|
|||||||
screenManager()->push(new GamePauseScreen(gamePath_));
|
screenManager()->push(new GamePauseScreen(gamePath_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(message, "play_sound")) {
|
||||||
|
if (g_Config.bAchievementsSoundEffects) {
|
||||||
|
// TODO: Handle this some nicer way.
|
||||||
|
if (!strcmp(value, "achievement_unlocked")) {
|
||||||
|
UI::PlayUISound(UI::UISound::ACHIEVEMENT_UNLOCKED, 0.6f);
|
||||||
|
}
|
||||||
|
if (!strcmp(value, "leaderboard_submitted")) {
|
||||||
|
UI::PlayUISound(UI::UISound::LEADERBOARD_SUBMITTED, 0.6f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
|
|||||||
});
|
});
|
||||||
viewGroup->Add(new CheckBox(&g_Config.bAchievementsChallengeMode, ac->T("Challenge Mode (no savestates)")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
|
viewGroup->Add(new CheckBox(&g_Config.bAchievementsChallengeMode, ac->T("Challenge Mode (no savestates)")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
|
||||||
viewGroup->Add(new CheckBox(&g_Config.bAchievementsEncoreMode, ac->T("Encore Mode")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
|
viewGroup->Add(new CheckBox(&g_Config.bAchievementsEncoreMode, ac->T("Encore Mode")))->SetEnabledPtr(&g_Config.bAchievementsEnable);
|
||||||
// viewGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects")))->SetEnabledPtr(&g_Config.bAchievementsEnable); // not yet implemented
|
viewGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects")))->SetEnabledPtr(&g_Config.bAchievementsEnable); // not yet implemented
|
||||||
|
|
||||||
viewGroup->Add(new ItemHeader(di->T("Links")));
|
viewGroup->Add(new ItemHeader(di->T("Links")));
|
||||||
viewGroup->Add(new Choice(ac->T("RetroAchievements website")))->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn {
|
viewGroup->Add(new Choice(ac->T("RetroAchievements website")))->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn {
|
||||||
|
BIN
assets/sfx_achievement_unlocked.wav
Normal file
BIN
assets/sfx_achievement_unlocked.wav
Normal file
Binary file not shown.
BIN
assets/sfx_leaderbord_submitted.wav
Normal file
BIN
assets/sfx_leaderbord_submitted.wav
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user