Implement Discord rich presence (#3711)
This commit is contained in:
parent
652f14506b
commit
1484b4d8cf
17 changed files with 383 additions and 43 deletions
2
.github/workflows/Linux_x86_64_SDL1.yml
vendored
2
.github/workflows/Linux_x86_64_SDL1.yml
vendored
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DUSE_SDL1=ON
|
||||
run: cmake -S. -Bbuild .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DUSE_SDL1=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
2
.github/workflows/MacOSX.yml
vendored
2
.github/workflows/MacOSX.yml
vendored
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild -DMACOSX_STANDALONE_APP_BUNDLE=ON
|
||||
run: cmake -S. -Bbuild -DMACOSX_STANDALONE_APP_BUNDLE=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
2
.github/workflows/Windows_x64.yml
vendored
2
.github/workflows/Windows_x64.yml
vendored
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc64.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc64.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
2
.github/workflows/Windows_x86.yml
vendored
2
.github/workflows/Windows_x86.yml
vendored
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
36
3rdParty/discord/CMakeLists.txt
vendored
Normal file
36
3rdParty/discord/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
include(functions/FetchContent_MakeAvailableExcludeFromAll)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(discordsrc
|
||||
URL https://dl-game-sdk.discordapp.net/2.5.6/discord_game_sdk.zip
|
||||
URL_HASH MD5=f86f15957cc9fbf04e3db10462027d58
|
||||
)
|
||||
FetchContent_MakeAvailableExcludeFromAll(discordsrc)
|
||||
|
||||
file(GLOB discord_SRCS ${discordsrc_SOURCE_DIR}/cpp/*.cpp)
|
||||
add_library(discord STATIC ${discord_SRCS})
|
||||
target_include_directories(discord INTERFACE "${discordsrc_SOURCE_DIR}/..")
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
set(DISCORD_LIB_DIR "${discordsrc_SOURCE_DIR}/lib/x86")
|
||||
else()
|
||||
set(DISCORD_LIB_DIR "${discordsrc_SOURCE_DIR}/lib/x86_64")
|
||||
endif()
|
||||
set(DISCORD_SHARED_LIB "${DISCORD_LIB_DIR}/discord_game_sdk${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
|
||||
if(WIN32 AND NOT MSVC)
|
||||
add_library(discord_game_sdk SHARED "discord_game_sdk_fake.cpp")
|
||||
set_target_properties(discord_game_sdk PROPERTIES PREFIX "")
|
||||
else()
|
||||
find_library(DISCORD_LIB discord_game_sdk${CMAKE_SHARED_LIBRARY_SUFFIX} ${DISCORD_LIB_DIR})
|
||||
|
||||
add_library(discord_game_sdk SHARED IMPORTED GLOBAL)
|
||||
set_property(TARGET discord_game_sdk PROPERTY IMPORTED_IMPLIB ${DISCORD_LIB})
|
||||
set_property(TARGET discord_game_sdk PROPERTY IMPORTED_LOCATION ${DISCORD_SHARED_LIB})
|
||||
endif()
|
||||
|
||||
file(COPY ${DISCORD_SHARED_LIB} DESTINATION "${CMAKE_BINARY_DIR}")
|
||||
|
||||
if(CPACK)
|
||||
install(FILES ${DISCORD_SHARED_LIB} DESTINATION ".")
|
||||
endif()
|
||||
4
3rdParty/discord/discord_game_sdk_fake.cpp
vendored
Normal file
4
3rdParty/discord/discord_game_sdk_fake.cpp
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
extern "C" {
|
||||
__declspec(dllexport) int DiscordCreate(int, void *, void *) { return 0; }
|
||||
__declspec(dllexport) int DiscordVersion(int, void *) { return 0; }
|
||||
}
|
||||
|
|
@ -131,3 +131,7 @@ endif()
|
|||
if(NOT NONET AND NOT DISABLE_ZERO_TIER)
|
||||
add_subdirectory(3rdParty/libzt)
|
||||
endif()
|
||||
|
||||
if(DISCORD_INTEGRATION)
|
||||
add_subdirectory(3rdParty/discord)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ cmake_dependent_option(PACKET_ENCRYPTION "Encrypt network packets" ON "NOT NONET
|
|||
option(NOSOUND "Disable sound support" OFF)
|
||||
option(RUN_TESTS "Build and run tests" OFF)
|
||||
option(ENABLE_CODECOVERAGE "Instrument code for code coverage (only enabled with RUN_TESTS)" OFF)
|
||||
option(DISCORD_INTEGRATION "Build with Discord SDK for rich presence support" OFF)
|
||||
|
||||
option(DISABLE_STREAMING_MUSIC "Disable streaming music (to work around broken platform implementations)" OFF)
|
||||
mark_as_advanced(DISABLE_STREAMING_MUSIC)
|
||||
|
|
@ -408,6 +409,12 @@ if(NINTENDO_3DS)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(DISCORD_INTEGRATION)
|
||||
list(APPEND libdevilutionx_SRCS
|
||||
Source/discord/discord.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(RUN_TESTS)
|
||||
set(devilutionxtest_SRCS
|
||||
test/appfat_test.cpp
|
||||
|
|
@ -493,6 +500,11 @@ if(RUN_TESTS)
|
|||
gtest_add_tests(devilutionx-tests "" AUTO)
|
||||
endif()
|
||||
|
||||
if(DISCORD_INTEGRATION)
|
||||
target_compile_definitions(libdevilutionx PRIVATE DISCORD)
|
||||
target_link_libraries(libdevilutionx PRIVATE discord discord_game_sdk)
|
||||
endif()
|
||||
|
||||
if(GPERF)
|
||||
find_package(Gperftools REQUIRED)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,14 @@
|
|||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"enableClangTidyCodeAnalysis": true
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-UnitTests",
|
||||
|
|
@ -19,7 +26,14 @@
|
|||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"cmakeCommandArgs": "-DRUN_TESTS=ON",
|
||||
"enableClangTidyCodeAnalysis": true
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-SDL1",
|
||||
|
|
@ -30,7 +44,14 @@
|
|||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"cmakeCommandArgs": "-DUSE_SDL1=ON",
|
||||
"enableClangTidyCodeAnalysis": true
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
|
|
@ -41,7 +62,14 @@
|
|||
"cmakeCommandArgs": "-DCPACK=ON",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"enableClangTidyCodeAnalysis": true
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Debug",
|
||||
|
|
@ -51,7 +79,14 @@
|
|||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"enableClangTidyCodeAnalysis": true
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Debug-UnitTests",
|
||||
|
|
@ -62,7 +97,14 @@
|
|||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"cmakeCommandArgs": "-DRUN_TESTS=ON",
|
||||
"enableClangTidyCodeAnalysis": true
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Release",
|
||||
|
|
@ -73,7 +115,14 @@
|
|||
"cmakeCommandArgs": "-DCPACK=ON",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"enableClangTidyCodeAnalysis": true
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-WSL-GCC",
|
||||
|
|
@ -87,7 +136,13 @@
|
|||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "linux_x64" ],
|
||||
"wslPath": "${defaultWSLPath}",
|
||||
"variables": []
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "DiabloUI/scrollbar.h"
|
||||
#include "controls/controller.h"
|
||||
#include "controls/menu_controls.h"
|
||||
#include "discord/discord.h"
|
||||
#include "dx.h"
|
||||
#include "hwcursor.hpp"
|
||||
#include "palette.h"
|
||||
|
|
@ -760,6 +761,8 @@ void UiPollAndRender()
|
|||
// so defer until after render and fade-in
|
||||
ctr_vkbdFlush();
|
||||
#endif
|
||||
|
||||
discord_manager::UpdateMenu();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "DiabloUI/diabloui.h"
|
||||
#include "control.h"
|
||||
#include "controls/menu_controls.h"
|
||||
#include "discord/discord.h"
|
||||
#include "utils/language.h"
|
||||
|
||||
namespace devilution {
|
||||
|
|
@ -53,6 +54,8 @@ void UiTitleDialog()
|
|||
UiRenderItems(vecTitleScreen);
|
||||
UiFadeIn();
|
||||
|
||||
discord_manager::UpdateMenu();
|
||||
|
||||
while (SDL_PollEvent(&event) != 0) {
|
||||
if (GetMenuAction(event) != MenuAction_NONE) {
|
||||
endMenu = true;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "controls/touch/gamepad.h"
|
||||
#include "controls/touch/renderers.h"
|
||||
#include "diablo.h"
|
||||
#include "discord/discord.h"
|
||||
#include "doom.h"
|
||||
#include "drlg_l1.h"
|
||||
#include "drlg_l2.h"
|
||||
|
|
@ -705,6 +706,7 @@ void RunGameLoop(interface_mode uMsg)
|
|||
gbGameLoopStartup = true;
|
||||
nthread_ignore_mutex(false);
|
||||
|
||||
discord_manager::StartGame();
|
||||
#ifdef GPERF_HEAP_FIRST_GAME_ITERATION
|
||||
unsigned run_game_iteration = 0;
|
||||
#endif
|
||||
|
|
@ -737,6 +739,9 @@ void RunGameLoop(interface_mode uMsg)
|
|||
bool runGameLoop = demo::IsRunning() ? demo::GetRunGameLoop(drawGame, processInput) : nthread_has_500ms_passed();
|
||||
if (demo::IsRecording())
|
||||
demo::RecordGameLoopResult(runGameLoop);
|
||||
|
||||
discord_manager::UpdateGame();
|
||||
|
||||
if (!runGameLoop) {
|
||||
if (processInput)
|
||||
ProcessInput();
|
||||
|
|
|
|||
193
Source/discord/discord.cpp
Normal file
193
Source/discord/discord.cpp
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#include "discord.h"
|
||||
|
||||
#include <discordsrc-src/cpp/discord.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "gendung.h"
|
||||
#include "init.h"
|
||||
#include "multi.h"
|
||||
#include "panels/charpanel.hpp"
|
||||
#include "player.h"
|
||||
#include "setmaps.h"
|
||||
#include "utils/language.h"
|
||||
|
||||
namespace devilution {
|
||||
namespace discord_manager {
|
||||
|
||||
// App ID used for DevilutionX's Diablo (classic Diablo's is 496571953147150354)
|
||||
constexpr discord::ClientId DiscordDevilutionxAppId = 795760213524742205;
|
||||
|
||||
constexpr auto IgnoreResult = [](discord::Result result) {};
|
||||
|
||||
discord::Core *discord_core = []() -> discord::Core * {
|
||||
discord::Core *core;
|
||||
discord::Result result = discord::Core::Create(DiscordDevilutionxAppId, DiscordCreateFlags_NoRequireDiscord, &core);
|
||||
if (result != discord::Result::Ok) {
|
||||
core = nullptr;
|
||||
}
|
||||
return core;
|
||||
}();
|
||||
|
||||
struct PlayerData {
|
||||
dungeon_type dungeonArea;
|
||||
_setlevels questMap;
|
||||
Uint8 dungeonLevel;
|
||||
Sint8 playerLevel;
|
||||
int playerGfx;
|
||||
|
||||
// Why??? This is POD
|
||||
bool operator!=(const PlayerData &other) const
|
||||
{
|
||||
return std::tie(dungeonArea, dungeonLevel, playerLevel, playerGfx) != std::tie(other.dungeonArea, other.dungeonLevel, other.playerLevel, other.playerGfx);
|
||||
}
|
||||
};
|
||||
|
||||
bool want_menu_update = true;
|
||||
PlayerData tracked_data;
|
||||
Sint64 start_time = 0;
|
||||
|
||||
std::string GetLocationString()
|
||||
{
|
||||
// Quest Level Name
|
||||
if (setlevel) {
|
||||
return _(QuestLevelNames[setlvlnum]);
|
||||
}
|
||||
|
||||
// Dungeon Name
|
||||
constexpr std::array<const char *, DTYPE_LAST + 1> DungeonStrs = { N_("Town"), N_("Cathedral"), N_("Catacombs"), N_("Caves"), N_("Hell"), N_("Nest"), N_("Crypt") };
|
||||
const char *dungeonStr = _(/* TRANSLATORS: type of dungeon (i.e. Cathedral, Caves)*/ "None");
|
||||
if (tracked_data.dungeonArea != DTYPE_NONE) {
|
||||
dungeonStr = _(DungeonStrs[tracked_data.dungeonArea]);
|
||||
}
|
||||
|
||||
// Dungeon Level
|
||||
if (tracked_data.dungeonLevel > 0) {
|
||||
int level = tracked_data.dungeonLevel;
|
||||
if (tracked_data.dungeonArea == DTYPE_NEST)
|
||||
level -= 16;
|
||||
else if (tracked_data.dungeonArea == DTYPE_CRYPT)
|
||||
level -= 20;
|
||||
|
||||
return fmt::format(_(/* TRANSLATORS: dungeon type and floor number i.e. "Cathedral 3"*/ "{} {}"), dungeonStr, level);
|
||||
}
|
||||
return dungeonStr;
|
||||
}
|
||||
|
||||
std::string GetCharacterString()
|
||||
{
|
||||
const char *charClassStr = ClassStrTbl[static_cast<int>(Players[MyPlayerId]._pClass)];
|
||||
return fmt::format(_(/* TRANSLATORS: Discord character, i.e. "Lv 6 Warrior" */ "Lv {} {}"), tracked_data.playerLevel, charClassStr);
|
||||
}
|
||||
|
||||
std::string GetDetailString()
|
||||
{
|
||||
return fmt::format("{} - {}", GetCharacterString(), GetLocationString());
|
||||
}
|
||||
|
||||
std::string GetStateString()
|
||||
{
|
||||
constexpr std::array<const char *, 3> DifficultyStrs = { N_("Normal"), N_("Nightmare"), N_("Hell") };
|
||||
const char *difficultyStr = _(DifficultyStrs[sgGameInitInfo.nDifficulty]);
|
||||
return fmt::format(_(/* TRANSLATORS: Discord state i.e. "Nightmare difficulty" */ "{} difficulty"), difficultyStr);
|
||||
}
|
||||
|
||||
std::string GetTooltipString()
|
||||
{
|
||||
return fmt::format("{} - {}", Players[MyPlayerId]._pName, GetCharacterString());
|
||||
}
|
||||
|
||||
std::string GetPlayerAssetString()
|
||||
{
|
||||
char heroChar = CharChar[static_cast<int>(Players[MyPlayerId]._pClass)];
|
||||
char armourChar = ArmourChar[tracked_data.playerGfx >> 4];
|
||||
char wpnChar = WepChar[tracked_data.playerGfx & 0xF];
|
||||
|
||||
std::string result = fmt::format("{}{}{}as", heroChar, armourChar, wpnChar);
|
||||
std::transform(std::begin(result), std::end(result), std::begin(result), [](char c) { return static_cast<char>(std::tolower(c)); });
|
||||
return result;
|
||||
}
|
||||
|
||||
void ResetStartTime()
|
||||
{
|
||||
start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
const char *GetIconAsset()
|
||||
{
|
||||
return gbIsHellfire ? "hellfire" : "icon";
|
||||
}
|
||||
|
||||
void UpdateGame()
|
||||
{
|
||||
if (discord_core == nullptr)
|
||||
return;
|
||||
|
||||
auto newData = PlayerData {
|
||||
leveltype, setlvlnum, currlevel, Players[MyPlayerId]._pLevel, Players[MyPlayerId]._pgfxnum
|
||||
};
|
||||
if (newData != tracked_data) {
|
||||
tracked_data = newData;
|
||||
|
||||
// Update status strings
|
||||
discord::Activity activity = {};
|
||||
activity.SetName(PROJECT_NAME);
|
||||
activity.SetState(GetStateString().c_str());
|
||||
activity.SetDetails(GetDetailString().c_str());
|
||||
activity.SetInstance(true);
|
||||
|
||||
activity.GetTimestamps().SetStart(start_time);
|
||||
|
||||
// Set image assets
|
||||
activity.GetAssets().SetLargeImage(GetPlayerAssetString().c_str());
|
||||
activity.GetAssets().SetLargeText(GetTooltipString().c_str());
|
||||
activity.GetAssets().SetSmallImage(GetIconAsset());
|
||||
activity.GetAssets().SetSmallText(gszProductName);
|
||||
|
||||
discord_core->ActivityManager().UpdateActivity(activity, IgnoreResult);
|
||||
}
|
||||
discord_core->RunCallbacks();
|
||||
}
|
||||
|
||||
void StartGame()
|
||||
{
|
||||
tracked_data = PlayerData { dungeon_type::DTYPE_NONE, _setlevels::SL_NONE, 0, 0, 0 };
|
||||
want_menu_update = true;
|
||||
ResetStartTime();
|
||||
}
|
||||
|
||||
void UpdateMenu(bool forced)
|
||||
{
|
||||
if (discord_core == nullptr)
|
||||
return;
|
||||
|
||||
if (want_menu_update || forced) {
|
||||
if (!forced) {
|
||||
ResetStartTime();
|
||||
}
|
||||
want_menu_update = false;
|
||||
|
||||
discord::Activity activity = {};
|
||||
activity.SetName(PROJECT_NAME);
|
||||
activity.SetState(_(/* TRANSLATORS: Discord activity, not in game */ "In Menu"));
|
||||
|
||||
activity.GetTimestamps().SetStart(start_time);
|
||||
|
||||
activity.GetAssets().SetLargeImage(GetIconAsset());
|
||||
activity.GetAssets().SetLargeText(gszProductName);
|
||||
|
||||
discord_core->ActivityManager().UpdateActivity(activity, IgnoreResult);
|
||||
}
|
||||
discord_core->RunCallbacks();
|
||||
}
|
||||
|
||||
} // namespace discord_manager
|
||||
} // namespace devilution
|
||||
25
Source/discord/discord.h
Normal file
25
Source/discord/discord.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
namespace devilution {
|
||||
namespace discord_manager {
|
||||
|
||||
#ifdef DISCORD
|
||||
void UpdateGame();
|
||||
void StartGame();
|
||||
void UpdateMenu(bool forced = false);
|
||||
#else
|
||||
constexpr void UpdateGame()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr void StartGame()
|
||||
{
|
||||
}
|
||||
|
||||
constexpr void UpdateMenu(bool forced = false)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace discord_manager
|
||||
} // namespace devilution
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
#include <SimpleIni.h>
|
||||
|
||||
#include "diablo.h"
|
||||
#include "discord/discord.h"
|
||||
#include "engine/demomode.h"
|
||||
#include "options.h"
|
||||
#include "qol/monhealthbar.h"
|
||||
|
|
@ -278,6 +279,7 @@ void OptionLanguageCodeChanged()
|
|||
void OptionGameModeChanged()
|
||||
{
|
||||
gbIsHellfire = *sgOptions.StartUp.gameMode == StartUpGameMode::Hellfire;
|
||||
discord_manager::UpdateMenu(true);
|
||||
}
|
||||
|
||||
void OptionSharewareChanged()
|
||||
|
|
|
|||
|
|
@ -162,37 +162,6 @@ struct DirectionSettings {
|
|||
void (*walkModeHandler)(int, const DirectionSettings &);
|
||||
};
|
||||
|
||||
/** Maps from armor animation to letter used in graphic files. */
|
||||
const char ArmourChar[4] = {
|
||||
'L', // light
|
||||
'M', // medium
|
||||
'H', // heavy
|
||||
0
|
||||
};
|
||||
/** Maps from weapon animation to letter used in graphic files. */
|
||||
const char WepChar[10] = {
|
||||
'N', // unarmed
|
||||
'U', // no weapon + shield
|
||||
'S', // sword + no shield
|
||||
'D', // sword + shield
|
||||
'B', // bow
|
||||
'A', // axe
|
||||
'M', // blunt + no shield
|
||||
'H', // blunt + shield
|
||||
'T', // staff
|
||||
0
|
||||
};
|
||||
/** Maps from player class to letter used in graphic files. */
|
||||
const char CharChar[] = {
|
||||
'W', // warrior
|
||||
'R', // rogue
|
||||
'S', // sorcerer
|
||||
'M', // monk
|
||||
'B',
|
||||
'C',
|
||||
0
|
||||
};
|
||||
|
||||
/** Specifies the frame of each animation for which an action is triggered, for each player class. */
|
||||
const int PlrGFXAnimLens[enum_size<HeroClass>::value][11] = {
|
||||
{ 10, 16, 8, 2, 20, 20, 6, 20, 8, 9, 14 },
|
||||
|
|
|
|||
|
|
@ -146,6 +146,35 @@ enum action_id : int8_t {
|
|||
// clang-format on
|
||||
};
|
||||
|
||||
/** Maps from armor animation to letter used in graphic files. */
|
||||
constexpr std::array<char, 4> ArmourChar = {
|
||||
'L', // light
|
||||
'M', // medium
|
||||
'H', // heavy
|
||||
};
|
||||
/** Maps from weapon animation to letter used in graphic files. */
|
||||
constexpr std::array<char, 9> WepChar = {
|
||||
'N', // unarmed
|
||||
'U', // no weapon + shield
|
||||
'S', // sword + no shield
|
||||
'D', // sword + shield
|
||||
'B', // bow
|
||||
'A', // axe
|
||||
'M', // blunt + no shield
|
||||
'H', // blunt + shield
|
||||
'T', // staff
|
||||
};
|
||||
|
||||
/** Maps from player class to letter used in graphic files. */
|
||||
constexpr std::array<char, 6> CharChar = {
|
||||
'W', // warrior
|
||||
'R', // rogue
|
||||
'S', // sorcerer
|
||||
'M', // monk
|
||||
'B',
|
||||
'C',
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Contains Data (CelSprites) for a player graphic (player_graphic)
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue