mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-21 08:55:04 -05:00
parent
a6b4e0b7fd
commit
86044a1c50
17
.github/workflows/generate-builds.yml
vendored
17
.github/workflows/generate-builds.yml
vendored
@ -32,17 +32,6 @@ jobs:
|
|||||||
make -j 10
|
make -j 10
|
||||||
sudo make install
|
sudo make install
|
||||||
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
||||||
- name: Install latest SDL_net
|
|
||||||
if: ${{ !vars.LINUX_RUNNER }}
|
|
||||||
run: |
|
|
||||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
|
||||||
wget https://www.libsdl.org/projects/SDL_net/release/SDL2_net-2.2.0.tar.gz
|
|
||||||
tar -xzf SDL2_net-2.2.0.tar.gz
|
|
||||||
cd SDL2_net-2.2.0
|
|
||||||
./configure
|
|
||||||
make -j 10
|
|
||||||
sudo make install
|
|
||||||
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
|
||||||
- name: Generate soh.otr
|
- name: Generate soh.otr
|
||||||
run: |
|
run: |
|
||||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||||
@ -102,7 +91,7 @@ jobs:
|
|||||||
- name: Build SoH
|
- name: Build SoH
|
||||||
run: |
|
run: |
|
||||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||||
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DBUILD_REMOTE_CONTROL=1
|
||||||
cmake --build build-cmake --config Release --parallel 10
|
cmake --build build-cmake --config Release --parallel 10
|
||||||
mv soh.otr build-cmake/soh
|
mv soh.otr build-cmake/soh
|
||||||
(cd build-cmake && cpack)
|
(cd build-cmake && cpack)
|
||||||
@ -171,7 +160,7 @@ jobs:
|
|||||||
- name: Build SoH
|
- name: Build SoH
|
||||||
run: |
|
run: |
|
||||||
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
|
||||||
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
|
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_REMOTE_CONTROL=1
|
||||||
cmake --build build-cmake --config Release -j3
|
cmake --build build-cmake --config Release -j3
|
||||||
(cd build-cmake && cpack -G External)
|
(cd build-cmake && cpack -G External)
|
||||||
|
|
||||||
@ -297,7 +286,7 @@ jobs:
|
|||||||
VCPKG_ROOT: ${{github.workspace}}/vcpkg
|
VCPKG_ROOT: ${{github.workspace}}/vcpkg
|
||||||
run: |
|
run: |
|
||||||
set $env:PATH="$env:USERPROFILE/.cargo/bin;$env:PATH"
|
set $env:PATH="$env:USERPROFILE/.cargo/bin;$env:PATH"
|
||||||
cmake -S . -B build-windows -G Ninja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
cmake -S . -B build-windows -G Ninja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DBUILD_REMOTE_CONTROL=1
|
||||||
cmake --build build-windows --config Release --parallel 10
|
cmake --build build-windows --config Release --parallel 10
|
||||||
|
|
||||||
mkdir soh-windows
|
mkdir soh-windows
|
||||||
|
2
.github/workflows/macports-deps.txt
vendored
2
.github/workflows/macports-deps.txt
vendored
@ -1 +1 @@
|
|||||||
libsdl2 +universal libpng +universal glew +universal
|
libsdl2 +universal libsdl2_net +universal libpng +universal glew +universal
|
||||||
|
@ -13,12 +13,6 @@ set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
|||||||
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
|
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
|
||||||
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/utf-8>)
|
add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/utf-8>)
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME MATCHES "Windows|Linux")
|
|
||||||
if(NOT DEFINED BUILD_CROWD_CONTROL)
|
|
||||||
set(BUILD_CROWD_CONTROL ON)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
include(CMake/automate-vcpkg.cmake)
|
include(CMake/automate-vcpkg.cmake)
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/gfx.*")
|
|||||||
# handle crowd control removals
|
# handle crowd control removals
|
||||||
list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.cs")
|
list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.cs")
|
||||||
list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.ccpak")
|
list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.ccpak")
|
||||||
if (!BUILD_CROWD_CONTROL)
|
if (!BUILD_REMOTE_CONTROL)
|
||||||
list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/crowd-control/*")
|
list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/crowd-control/*")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -354,7 +354,7 @@ endif()
|
|||||||
find_package(SDL2)
|
find_package(SDL2)
|
||||||
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
||||||
|
|
||||||
if (BUILD_CROWD_CONTROL)
|
if (BUILD_REMOTE_CONTROL)
|
||||||
find_package(SDL2_net)
|
find_package(SDL2_net)
|
||||||
set(SDL2-NET-INCLUDE ${SDL_NET_INCLUDE_DIRS})
|
set(SDL2-NET-INCLUDE ${SDL_NET_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
@ -408,9 +408,9 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
|||||||
"$<$<CONFIG:Release>:"
|
"$<$<CONFIG:Release>:"
|
||||||
"NDEBUG"
|
"NDEBUG"
|
||||||
">"
|
">"
|
||||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>"
|
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
|
||||||
"INCLUDE_GAME_PRINTF;"
|
"INCLUDE_GAME_PRINTF;"
|
||||||
"ENABLE_CROWD_CONTROL;"
|
"ENABLE_REMOTE_CONTROL;"
|
||||||
"UNICODE;"
|
"UNICODE;"
|
||||||
"_UNICODE"
|
"_UNICODE"
|
||||||
STORMLIB_NO_AUTO_LINK
|
STORMLIB_NO_AUTO_LINK
|
||||||
@ -455,7 +455,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
|
|||||||
"$<$<CONFIG:Release>:"
|
"$<$<CONFIG:Release>:"
|
||||||
"NDEBUG"
|
"NDEBUG"
|
||||||
">"
|
">"
|
||||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>"
|
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:ENABLE_REMOTE_CONTROL>"
|
||||||
"SPDLOG_ACTIVE_LEVEL=0;"
|
"SPDLOG_ACTIVE_LEVEL=0;"
|
||||||
"_CONSOLE;"
|
"_CONSOLE;"
|
||||||
"_CRT_SECURE_NO_WARNINGS;"
|
"_CRT_SECURE_NO_WARNINGS;"
|
||||||
@ -689,7 +689,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
|||||||
"glu32;"
|
"glu32;"
|
||||||
"SDL2::SDL2;"
|
"SDL2::SDL2;"
|
||||||
"SDL2::SDL2main;"
|
"SDL2::SDL2main;"
|
||||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net-static>"
|
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net-static>"
|
||||||
"glfw;"
|
"glfw;"
|
||||||
"winmm;"
|
"winmm;"
|
||||||
"imm32;"
|
"imm32;"
|
||||||
@ -742,7 +742,7 @@ else()
|
|||||||
"ZAPDUtils;"
|
"ZAPDUtils;"
|
||||||
"ZAPDLib;"
|
"ZAPDLib;"
|
||||||
SDL2::SDL2
|
SDL2::SDL2
|
||||||
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net>"
|
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net>"
|
||||||
${CMAKE_DL_LIBS}
|
${CMAKE_DL_LIBS}
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#ifdef ENABLE_CROWD_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
|
||||||
#include "CrowdControl.h"
|
#include "CrowdControl.h"
|
||||||
#include "CrowdControlTypes.h"
|
#include "CrowdControlTypes.h"
|
||||||
@ -17,25 +17,17 @@ extern "C" {
|
|||||||
extern PlayState* gPlayState;
|
extern PlayState* gPlayState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrowdControl::Init() {
|
|
||||||
SDLNet_Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CrowdControl::Shutdown() {
|
|
||||||
SDLNet_Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CrowdControl::Enable() {
|
void CrowdControl::Enable() {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDLNet_ResolveHost(&ip, "127.0.0.1", 43384) == -1) {
|
|
||||||
SPDLOG_ERROR("[CrowdControl] SDLNet_ResolveHost: {}", SDLNet_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
isEnabled = true;
|
isEnabled = true;
|
||||||
ccThreadReceive = std::thread(&CrowdControl::ListenToServer, this);
|
GameInteractor::Instance->EnableRemoteInteractor();
|
||||||
|
GameInteractor::Instance->RegisterRemoteJsonHandler([&](nlohmann::json payload) {
|
||||||
|
HandleRemoteData(payload);
|
||||||
|
});
|
||||||
|
|
||||||
ccThreadProcess = std::thread(&CrowdControl::ProcessActiveEffects, this);
|
ccThreadProcess = std::thread(&CrowdControl::ProcessActiveEffects, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,87 +37,42 @@ void CrowdControl::Disable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isEnabled = false;
|
isEnabled = false;
|
||||||
ccThreadReceive.join();
|
|
||||||
ccThreadProcess.join();
|
ccThreadProcess.join();
|
||||||
|
GameInteractor::Instance->DisableRemoteInteractor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrowdControl::ListenToServer() {
|
void CrowdControl::HandleRemoteData(nlohmann::json payload) {
|
||||||
while (isEnabled) {
|
Effect* incomingEffect = ParseMessage(payload);
|
||||||
while (!connected && isEnabled) {
|
if (!incomingEffect) {
|
||||||
SPDLOG_TRACE("[CrowdControl] Attempting to make connection to server...");
|
return;
|
||||||
tcpsock = SDLNet_TCP_Open(&ip);
|
}
|
||||||
|
|
||||||
if (tcpsock) {
|
// If effect is not a timed effect, execute and return result.
|
||||||
connected = true;
|
if (!incomingEffect->timeRemaining) {
|
||||||
SPDLOG_TRACE("[CrowdControl] Connection to server established!");
|
EffectResult result = CrowdControl::ExecuteEffect(incomingEffect);
|
||||||
|
EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, result);
|
||||||
|
} else {
|
||||||
|
// If another timed effect is already active that conflicts with the incoming effect.
|
||||||
|
bool isConflictingEffectActive = false;
|
||||||
|
for (Effect* effect : activeEffects) {
|
||||||
|
if (effect != incomingEffect && effect->category == incomingEffect->category && effect->id < incomingEffect->id) {
|
||||||
|
isConflictingEffectActive = true;
|
||||||
|
EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, EffectResult::Retry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(1);
|
if (!isConflictingEffectActive) {
|
||||||
if (tcpsock) {
|
// Check if effect can be applied, if it can't, let CC know.
|
||||||
SDLNet_TCP_AddSocket(socketSet, tcpsock);
|
EffectResult result = CrowdControl::CanApplyEffect(incomingEffect);
|
||||||
}
|
if (result == EffectResult::Retry || result == EffectResult::Failure) {
|
||||||
|
EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, result);
|
||||||
// Listen to socket messages
|
return;
|
||||||
while (connected && tcpsock && isEnabled) {
|
|
||||||
// we check first if socket has data, to not block in the TCP_Recv
|
|
||||||
int socketsReady = SDLNet_CheckSockets(socketSet, 0);
|
|
||||||
|
|
||||||
if (socketsReady == -1) {
|
|
||||||
SPDLOG_ERROR("[CrowdControl] SDLNet_CheckSockets: {}", SDLNet_GetError());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socketsReady == 0) {
|
activeEffectsMutex.lock();
|
||||||
continue;
|
activeEffects.push_back(incomingEffect);
|
||||||
}
|
activeEffectsMutex.unlock();
|
||||||
|
|
||||||
int len = SDLNet_TCP_Recv(tcpsock, &received, sizeof(received));
|
|
||||||
if (!len || !tcpsock || len == -1) {
|
|
||||||
SPDLOG_ERROR("[CrowdControl] SDLNet_TCP_Recv: {}", SDLNet_GetError());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Effect* incomingEffect = ParseMessage(received);
|
|
||||||
if (!incomingEffect) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If effect is not a timed effect, execute and return result.
|
|
||||||
if (!incomingEffect->timeRemaining) {
|
|
||||||
EffectResult result = CrowdControl::ExecuteEffect(incomingEffect);
|
|
||||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result);
|
|
||||||
} else {
|
|
||||||
// If another timed effect is already active that conflicts with the incoming effect.
|
|
||||||
bool isConflictingEffectActive = false;
|
|
||||||
for (Effect* effect : activeEffects) {
|
|
||||||
if (effect != incomingEffect && effect->category == incomingEffect->category && effect->id < incomingEffect->id) {
|
|
||||||
isConflictingEffectActive = true;
|
|
||||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, EffectResult::Retry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isConflictingEffectActive) {
|
|
||||||
// Check if effect can be applied, if it can't, let CC know.
|
|
||||||
EffectResult result = CrowdControl::CanApplyEffect(incomingEffect);
|
|
||||||
if (result == EffectResult::Retry || result == EffectResult::Failure) {
|
|
||||||
EmitMessage(tcpsock, incomingEffect->id, incomingEffect->timeRemaining, result);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
activeEffectsMutex.lock();
|
|
||||||
activeEffects.push_back(incomingEffect);
|
|
||||||
activeEffectsMutex.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connected) {
|
|
||||||
SDLNet_TCP_Close(tcpsock);
|
|
||||||
connected = false;
|
|
||||||
SPDLOG_TRACE("[CrowdControl] Ending Listen thread...");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,13 +94,13 @@ void CrowdControl::ProcessActiveEffects() {
|
|||||||
if (effect->timeRemaining <= 0) {
|
if (effect->timeRemaining <= 0) {
|
||||||
it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect),
|
it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect),
|
||||||
activeEffects.end());
|
activeEffects.end());
|
||||||
GameInteractor::RemoveEffect(effect->giEffect);
|
GameInteractor::RemoveEffect(dynamic_cast<RemovableGameInteractionEffect*>(effect->giEffect));
|
||||||
delete effect;
|
delete effect;
|
||||||
} else {
|
} else {
|
||||||
// If we have a success after previously being paused, tell CC to resume timer.
|
// If we have a success after previously being paused, tell CC to resume timer.
|
||||||
if (effect->isPaused) {
|
if (effect->isPaused) {
|
||||||
effect->isPaused = false;
|
effect->isPaused = false;
|
||||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Resumed);
|
EmitMessage(effect->id, effect->timeRemaining, EffectResult::Resumed);
|
||||||
// If not paused before, subtract time from the timer and send a Success event if
|
// If not paused before, subtract time from the timer and send a Success event if
|
||||||
// the result is different from the last time this was ran.
|
// the result is different from the last time this was ran.
|
||||||
// Timed events are put on a thread that runs once per second.
|
// Timed events are put on a thread that runs once per second.
|
||||||
@ -161,7 +108,7 @@ void CrowdControl::ProcessActiveEffects() {
|
|||||||
effect->timeRemaining -= 1000;
|
effect->timeRemaining -= 1000;
|
||||||
if (result != effect->lastExecutionResult) {
|
if (result != effect->lastExecutionResult) {
|
||||||
effect->lastExecutionResult = result;
|
effect->lastExecutionResult = result;
|
||||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Success);
|
EmitMessage(effect->id, effect->timeRemaining, EffectResult::Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
@ -169,7 +116,7 @@ void CrowdControl::ProcessActiveEffects() {
|
|||||||
} else { // Timed effects only do Success or Retry
|
} else { // Timed effects only do Success or Retry
|
||||||
if (!effect->isPaused && effect->timeRemaining > 0) {
|
if (!effect->isPaused && effect->timeRemaining > 0) {
|
||||||
effect->isPaused = true;
|
effect->isPaused = true;
|
||||||
EmitMessage(tcpsock, effect->id, effect->timeRemaining, EffectResult::Paused);
|
EmitMessage(effect->id, effect->timeRemaining, EffectResult::Paused);
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
@ -182,7 +129,7 @@ void CrowdControl::ProcessActiveEffects() {
|
|||||||
SPDLOG_TRACE("[CrowdControl] Ending Process thread...");
|
SPDLOG_TRACE("[CrowdControl] Ending Process thread...");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrowdControl::EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, EffectResult status) {
|
void CrowdControl::EmitMessage(uint32_t eventId, long timeRemaining, EffectResult status) {
|
||||||
nlohmann::json payload;
|
nlohmann::json payload;
|
||||||
|
|
||||||
payload["id"] = eventId;
|
payload["id"] = eventId;
|
||||||
@ -190,8 +137,9 @@ void CrowdControl::EmitMessage(TCPsocket socket, uint32_t eventId, long timeRema
|
|||||||
payload["timeRemaining"] = timeRemaining;
|
payload["timeRemaining"] = timeRemaining;
|
||||||
payload["status"] = status;
|
payload["status"] = status;
|
||||||
|
|
||||||
std::string jsonPayload = payload.dump();
|
SPDLOG_INFO("[CrowdControl] Sending payload:\n{}", payload.dump());
|
||||||
SDLNet_TCP_Send(socket, jsonPayload.c_str(), jsonPayload.size() + 1);
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) {
|
CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) {
|
||||||
@ -229,13 +177,14 @@ CrowdControl::EffectResult CrowdControl::TranslateGiEnum(GameInteractionEffectQu
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
|
||||||
nlohmann::json dataReceived = nlohmann::json::parse(payload, nullptr, false);
|
if (!dataReceived.contains("id") || !dataReceived.contains("type")) {
|
||||||
if (dataReceived.is_discarded()) {
|
SPDLOG_ERROR("[CrowdControl] Invalid payload received:\n{}", dataReceived);
|
||||||
SPDLOG_ERROR("Error parsing JSON");
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPDLOG_INFO("[CrowdControl] Received payload:\n{}", dataReceived.dump());
|
||||||
|
|
||||||
Effect* effect = new Effect();
|
Effect* effect = new Effect();
|
||||||
effect->lastExecutionResult = EffectResult::Initiate;
|
effect->lastExecutionResult = EffectResult::Initiate;
|
||||||
effect->id = dataReceived["id"];
|
effect->id = dataReceived["id"];
|
||||||
@ -333,13 +282,13 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
|||||||
effect->category = kEffectCatDamageTaken;
|
effect->category = kEffectCatDamageTaken;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||||
effect->giEffect->parameters[0] = 2;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeDoubleDamage:
|
case kEffectTakeDoubleDamage:
|
||||||
effect->category = kEffectCatDamageTaken;
|
effect->category = kEffectCatDamageTaken;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||||
effect->giEffect->parameters[0] = -2;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2;
|
||||||
break;
|
break;
|
||||||
case kEffectOneHitKo:
|
case kEffectOneHitKo:
|
||||||
effect->category = kEffectCatDamageTaken;
|
effect->category = kEffectCatDamageTaken;
|
||||||
@ -356,37 +305,37 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
|||||||
effect->category = kEffectCatSpeed;
|
effect->category = kEffectCatSpeed;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||||
effect->giEffect->parameters[0] = 2;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2;
|
||||||
break;
|
break;
|
||||||
case kEffectDecreaseSpeed:
|
case kEffectDecreaseSpeed:
|
||||||
effect->category = kEffectCatSpeed;
|
effect->category = kEffectCatSpeed;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||||
effect->giEffect->parameters[0] = -2;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2;
|
||||||
break;
|
break;
|
||||||
case kEffectLowGravity:
|
case kEffectLowGravity:
|
||||||
effect->category = kEffectCatGravity;
|
effect->category = kEffectCatGravity;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyGravity();
|
effect->giEffect = new GameInteractionEffect::ModifyGravity();
|
||||||
effect->giEffect->parameters[0] = GI_GRAVITY_LEVEL_LIGHT;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_GRAVITY_LEVEL_LIGHT;
|
||||||
break;
|
break;
|
||||||
case kEffectHighGravity:
|
case kEffectHighGravity:
|
||||||
effect->category = kEffectCatGravity;
|
effect->category = kEffectCatGravity;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyGravity();
|
effect->giEffect = new GameInteractionEffect::ModifyGravity();
|
||||||
effect->giEffect->parameters[0] = GI_GRAVITY_LEVEL_HEAVY;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_GRAVITY_LEVEL_HEAVY;
|
||||||
break;
|
break;
|
||||||
case kEffectForceIronBoots:
|
case kEffectForceIronBoots:
|
||||||
effect->category = kEffectCatBoots;
|
effect->category = kEffectCatBoots;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
||||||
effect->giEffect->parameters[0] = EQUIP_VALUE_BOOTS_IRON;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = EQUIP_VALUE_BOOTS_IRON;
|
||||||
break;
|
break;
|
||||||
case kEffectForceHoverBoots:
|
case kEffectForceHoverBoots:
|
||||||
effect->category = kEffectCatBoots;
|
effect->category = kEffectCatBoots;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
||||||
effect->giEffect->parameters[0] = EQUIP_VALUE_BOOTS_HOVER;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = EQUIP_VALUE_BOOTS_HOVER;
|
||||||
break;
|
break;
|
||||||
case kEffectSlipperyFloor:
|
case kEffectSlipperyFloor:
|
||||||
effect->category = kEffectCatSlipperyFloor;
|
effect->category = kEffectCatSlipperyFloor;
|
||||||
@ -412,23 +361,23 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
|||||||
// Hurt or Heal Link
|
// Hurt or Heal Link
|
||||||
case kEffectEmptyHeart:
|
case kEffectEmptyHeart:
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
break;
|
break;
|
||||||
case kEffectFillHeart:
|
case kEffectFillHeart:
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
effect->giEffect = new GameInteractionEffect::ModifyHealth();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
break;
|
break;
|
||||||
case kEffectKnockbackLinkWeak:
|
case kEffectKnockbackLinkWeak:
|
||||||
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
||||||
effect->giEffect->parameters[0] = 1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 1;
|
||||||
break;
|
break;
|
||||||
case kEffectKnockbackLinkStrong:
|
case kEffectKnockbackLinkStrong:
|
||||||
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
||||||
effect->giEffect->parameters[0] = 3;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 3;
|
||||||
break;
|
break;
|
||||||
case kEffectKnockbackLinkMega:
|
case kEffectKnockbackLinkMega:
|
||||||
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
effect->giEffect = new GameInteractionEffect::KnockbackPlayer();
|
||||||
effect->giEffect->parameters[0] = 6;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 6;
|
||||||
break;
|
break;
|
||||||
case kEffectBurnLink:
|
case kEffectBurnLink:
|
||||||
effect->giEffect = new GameInteractionEffect::BurnPlayer();
|
effect->giEffect = new GameInteractionEffect::BurnPlayer();
|
||||||
@ -441,109 +390,109 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
|||||||
break;
|
break;
|
||||||
case kEffectKillLink:
|
case kEffectKillLink:
|
||||||
effect->giEffect = new GameInteractionEffect::SetPlayerHealth();
|
effect->giEffect = new GameInteractionEffect::SetPlayerHealth();
|
||||||
effect->giEffect->parameters[0] = 0;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Give Items and Consumables
|
// Give Items and Consumables
|
||||||
case kEffectAddHeartContainer:
|
case kEffectAddHeartContainer:
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
||||||
effect->giEffect->parameters[0] = 1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 1;
|
||||||
break;
|
break;
|
||||||
case kEffectFillMagic:
|
case kEffectFillMagic:
|
||||||
effect->giEffect = new GameInteractionEffect::FillMagic();
|
effect->giEffect = new GameInteractionEffect::FillMagic();
|
||||||
break;
|
break;
|
||||||
case kEffectAddRupees:
|
case kEffectAddRupees:
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
break;
|
break;
|
||||||
case kEffectGiveDekuShield:
|
case kEffectGiveDekuShield:
|
||||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||||
effect->giEffect->parameters[0] = ITEM_SHIELD_DEKU;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = ITEM_SHIELD_DEKU;
|
||||||
break;
|
break;
|
||||||
case kEffectGiveHylianShield:
|
case kEffectGiveHylianShield:
|
||||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||||
effect->giEffect->parameters[0] = ITEM_SHIELD_HYLIAN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = ITEM_SHIELD_HYLIAN;
|
||||||
break;
|
break;
|
||||||
case kEffectRefillSticks:
|
case kEffectRefillSticks:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
effect->giEffect->parameters[1] = ITEM_STICK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_STICK;
|
||||||
break;
|
break;
|
||||||
case kEffectRefillNuts:
|
case kEffectRefillNuts:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
effect->giEffect->parameters[1] = ITEM_NUT;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_NUT;
|
||||||
break;
|
break;
|
||||||
case kEffectRefillBombs:
|
case kEffectRefillBombs:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
effect->giEffect->parameters[1] = ITEM_BOMB;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMB;
|
||||||
break;
|
break;
|
||||||
case kEffectRefillSeeds:
|
case kEffectRefillSeeds:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
effect->giEffect->parameters[1] = ITEM_SLINGSHOT;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT;
|
||||||
break;
|
break;
|
||||||
case kEffectRefillArrows:
|
case kEffectRefillArrows:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
effect->giEffect->parameters[1] = ITEM_BOW;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOW;
|
||||||
break;
|
break;
|
||||||
case kEffectRefillBombchus:
|
case kEffectRefillBombchus:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter;
|
||||||
effect->giEffect->parameters[1] = ITEM_BOMBCHU;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMBCHU;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Take Items and Consumables
|
// Take Items and Consumables
|
||||||
case kEffectRemoveHeartContainer:
|
case kEffectRemoveHeartContainer:
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
effect->giEffect = new GameInteractionEffect::ModifyHeartContainers();
|
||||||
effect->giEffect->parameters[0] = -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -1;
|
||||||
break;
|
break;
|
||||||
case kEffectEmptyMagic:
|
case kEffectEmptyMagic:
|
||||||
effect->giEffect = new GameInteractionEffect::EmptyMagic();
|
effect->giEffect = new GameInteractionEffect::EmptyMagic();
|
||||||
break;
|
break;
|
||||||
case kEffectRemoveRupees:
|
case kEffectRemoveRupees:
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
effect->giEffect = new GameInteractionEffect::ModifyRupees();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeDekuShield:
|
case kEffectTakeDekuShield:
|
||||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||||
effect->giEffect->parameters[0] = -ITEM_SHIELD_DEKU;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -ITEM_SHIELD_DEKU;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeHylianShield:
|
case kEffectTakeHylianShield:
|
||||||
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
effect->giEffect = new GameInteractionEffect::GiveOrTakeShield();
|
||||||
effect->giEffect->parameters[0] = -ITEM_SHIELD_HYLIAN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -ITEM_SHIELD_HYLIAN;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeSticks:
|
case kEffectTakeSticks:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
effect->giEffect->parameters[1] = ITEM_STICK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_STICK;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeNuts:
|
case kEffectTakeNuts:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
effect->giEffect->parameters[1] = ITEM_NUT;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_NUT;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeBombs:
|
case kEffectTakeBombs:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
effect->giEffect->parameters[1] = ITEM_BOMB;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMB;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeSeeds:
|
case kEffectTakeSeeds:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
effect->giEffect->parameters[1] = ITEM_SLINGSHOT;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeArrows:
|
case kEffectTakeArrows:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
effect->giEffect->parameters[1] = ITEM_BOW;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOW;
|
||||||
break;
|
break;
|
||||||
case kEffectTakeBombchus:
|
case kEffectTakeBombchus:
|
||||||
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->giEffect->parameters[0] = receivedParameter * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = receivedParameter * -1;
|
||||||
effect->giEffect->parameters[1] = ITEM_BOMBCHU;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = ITEM_BOMBCHU;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Link Size Modifiers
|
// Link Size Modifiers
|
||||||
@ -551,25 +500,25 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
|||||||
effect->category = kEffectCatLinkSize;
|
effect->category = kEffectCatLinkSize;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
effect->giEffect->parameters[0] = GI_LINK_SIZE_GIANT;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_GIANT;
|
||||||
break;
|
break;
|
||||||
case kEffectMinishLink:
|
case kEffectMinishLink:
|
||||||
effect->category = kEffectCatLinkSize;
|
effect->category = kEffectCatLinkSize;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
effect->giEffect->parameters[0] = GI_LINK_SIZE_MINISH;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_MINISH;
|
||||||
break;
|
break;
|
||||||
case kEffectPaperLink:
|
case kEffectPaperLink:
|
||||||
effect->category = kEffectCatLinkSize;
|
effect->category = kEffectCatLinkSize;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
effect->giEffect->parameters[0] = GI_LINK_SIZE_PAPER;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_PAPER;
|
||||||
break;
|
break;
|
||||||
case kEffectSquishedLink:
|
case kEffectSquishedLink:
|
||||||
effect->category = kEffectCatLinkSize;
|
effect->category = kEffectCatLinkSize;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
effect->giEffect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
effect->giEffect->parameters[0] = GI_LINK_SIZE_SQUISHED;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_LINK_SIZE_SQUISHED;
|
||||||
break;
|
break;
|
||||||
case kEffectInvisibleLink:
|
case kEffectInvisibleLink:
|
||||||
effect->category = kEffectCatLinkSize;
|
effect->category = kEffectCatLinkSize;
|
||||||
@ -585,11 +534,11 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
|||||||
break;
|
break;
|
||||||
case kEffectSetTimeToDawn:
|
case kEffectSetTimeToDawn:
|
||||||
effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
|
effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
|
||||||
effect->giEffect->parameters[0] = GI_TIMEOFDAY_DAWN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DAWN;
|
||||||
break;
|
break;
|
||||||
case kEffectSetTimeToDusk:
|
case kEffectSetTimeToDusk:
|
||||||
effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
|
effect->giEffect = new GameInteractionEffect::SetTimeOfDay();
|
||||||
effect->giEffect->parameters[0] = GI_TIMEOFDAY_DUSK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DUSK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Visual Effects
|
// Visual Effects
|
||||||
@ -632,186 +581,186 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
|||||||
effect->category = kEffectCatRandomButtons;
|
effect->category = kEffectCatRandomButtons;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::PressRandomButton();
|
effect->giEffect = new GameInteractionEffect::PressRandomButton();
|
||||||
effect->giEffect->parameters[0] = 30;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 30;
|
||||||
break;
|
break;
|
||||||
case kEffectClearCbuttons:
|
case kEffectClearCbuttons:
|
||||||
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
|
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
|
||||||
effect->giEffect->parameters[0] = GI_BUTTONS_CBUTTONS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_BUTTONS_CBUTTONS;
|
||||||
break;
|
break;
|
||||||
case kEffectClearDpad:
|
case kEffectClearDpad:
|
||||||
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
|
effect->giEffect = new GameInteractionEffect::ClearAssignedButtons();
|
||||||
effect->giEffect->parameters[0] = GI_BUTTONS_DPAD;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_BUTTONS_DPAD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Teleport Player
|
// Teleport Player
|
||||||
case kEffectTpLinksHouse:
|
case kEffectTpLinksHouse:
|
||||||
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
||||||
effect->giEffect->parameters[0] = GI_TP_DEST_LINKSHOUSE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_LINKSHOUSE;
|
||||||
break;
|
break;
|
||||||
case kEffectTpMinuet:
|
case kEffectTpMinuet:
|
||||||
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
||||||
effect->giEffect->parameters[0] = GI_TP_DEST_MINUET;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_MINUET;
|
||||||
break;
|
break;
|
||||||
case kEffectTpBolero:
|
case kEffectTpBolero:
|
||||||
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
||||||
effect->giEffect->parameters[0] = GI_TP_DEST_BOLERO;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_BOLERO;
|
||||||
break;
|
break;
|
||||||
case kEffectTpSerenade:
|
case kEffectTpSerenade:
|
||||||
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
||||||
effect->giEffect->parameters[0] = GI_TP_DEST_SERENADE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_SERENADE;
|
||||||
break;
|
break;
|
||||||
case kEffectTpRequiem:
|
case kEffectTpRequiem:
|
||||||
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
||||||
effect->giEffect->parameters[0] = GI_TP_DEST_REQUIEM;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_REQUIEM;
|
||||||
break;
|
break;
|
||||||
case kEffectTpNocturne:
|
case kEffectTpNocturne:
|
||||||
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
||||||
effect->giEffect->parameters[0] = GI_TP_DEST_NOCTURNE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_NOCTURNE;
|
||||||
break;
|
break;
|
||||||
case kEffectTpPrelude:
|
case kEffectTpPrelude:
|
||||||
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
effect->giEffect = new GameInteractionEffect::TeleportPlayer();
|
||||||
effect->giEffect->parameters[0] = GI_TP_DEST_PRELUDE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_PRELUDE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Tunic Color (Bidding War)
|
// Tunic Color (Bidding War)
|
||||||
case kEffectTunicRed:
|
case kEffectTunicRed:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_RED;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicGreen:
|
case kEffectTunicGreen:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_GREEN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicBlue:
|
case kEffectTunicBlue:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BLUE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicOrange:
|
case kEffectTunicOrange:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_ORANGE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicYellow:
|
case kEffectTunicYellow:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_YELLOW;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicPurple:
|
case kEffectTunicPurple:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_PURPLE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicPink:
|
case kEffectTunicPink:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_PINK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicBrown:
|
case kEffectTunicBrown:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BROWN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
|
||||||
break;
|
break;
|
||||||
case kEffectTunicBlack:
|
case kEffectTunicBlack:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_TUNICS;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BLACK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Navi Color (Bidding War)
|
// Navi Color (Bidding War)
|
||||||
case kEffectNaviRed:
|
case kEffectNaviRed:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_RED;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviGreen:
|
case kEffectNaviGreen:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_GREEN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviBlue:
|
case kEffectNaviBlue:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BLUE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviOrange:
|
case kEffectNaviOrange:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_ORANGE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviYellow:
|
case kEffectNaviYellow:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_YELLOW;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviPurple:
|
case kEffectNaviPurple:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_PURPLE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviPink:
|
case kEffectNaviPink:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_PINK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviBrown:
|
case kEffectNaviBrown:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BROWN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
|
||||||
break;
|
break;
|
||||||
case kEffectNaviBlack:
|
case kEffectNaviBlack:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_NAVI;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BLACK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Link's Hair Color (Bidding War)
|
// Link's Hair Color (Bidding War)
|
||||||
case kEffectHairRed:
|
case kEffectHairRed:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_RED;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
|
||||||
break;
|
break;
|
||||||
case kEffectHairGreen:
|
case kEffectHairGreen:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_GREEN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
|
||||||
break;
|
break;
|
||||||
case kEffectHairBlue:
|
case kEffectHairBlue:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BLUE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
|
||||||
break;
|
break;
|
||||||
case kEffectHairOrange:
|
case kEffectHairOrange:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_ORANGE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
|
||||||
break;
|
break;
|
||||||
case kEffectHairYellow:
|
case kEffectHairYellow:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_YELLOW;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
|
||||||
break;
|
break;
|
||||||
case kEffectHairPurple:
|
case kEffectHairPurple:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_PURPLE;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
|
||||||
break;
|
break;
|
||||||
case kEffectHairPink:
|
case kEffectHairPink:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_PINK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
|
||||||
break;
|
break;
|
||||||
case kEffectHairBrown:
|
case kEffectHairBrown:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BROWN;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
|
||||||
break;
|
break;
|
||||||
case kEffectHairBlack:
|
case kEffectHairBlack:
|
||||||
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
effect->giEffect->parameters[0] = GI_COSMETICS_HAIR;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
|
||||||
effect->giEffect->parameters[1] = GI_COLOR_BLACK;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#ifdef ENABLE_CROWD_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
|
||||||
#ifndef _CROWDCONTROL_C
|
#ifndef _CROWDCONTROL_C
|
||||||
#define _CROWDCONTROL_C
|
#define _CROWDCONTROL_C
|
||||||
@ -73,33 +73,24 @@ class CrowdControl {
|
|||||||
EffectResult lastExecutionResult;
|
EffectResult lastExecutionResult;
|
||||||
} Effect;
|
} Effect;
|
||||||
|
|
||||||
std::thread ccThreadReceive;
|
|
||||||
std::thread ccThreadProcess;
|
std::thread ccThreadProcess;
|
||||||
|
|
||||||
TCPsocket tcpsock;
|
|
||||||
IPaddress ip;
|
|
||||||
|
|
||||||
bool isEnabled;
|
bool isEnabled;
|
||||||
bool connected;
|
|
||||||
|
|
||||||
char received[512];
|
|
||||||
|
|
||||||
std::vector<Effect*> activeEffects;
|
std::vector<Effect*> activeEffects;
|
||||||
std::mutex activeEffectsMutex;
|
std::mutex activeEffectsMutex;
|
||||||
|
|
||||||
void ListenToServer();
|
void HandleRemoteData(nlohmann::json payload);
|
||||||
void ProcessActiveEffects();
|
void ProcessActiveEffects();
|
||||||
|
|
||||||
void EmitMessage(TCPsocket socket, uint32_t eventId, long timeRemaining, EffectResult status);
|
void EmitMessage(uint32_t eventId, long timeRemaining, EffectResult status);
|
||||||
Effect* ParseMessage(char payload[512]);
|
Effect* ParseMessage(nlohmann::json payload);
|
||||||
EffectResult ExecuteEffect(Effect* effect);
|
EffectResult ExecuteEffect(Effect* effect);
|
||||||
EffectResult CanApplyEffect(Effect *effect);
|
EffectResult CanApplyEffect(Effect *effect);
|
||||||
EffectResult TranslateGiEnum(GameInteractionEffectQueryResult giResult);
|
EffectResult TranslateGiEnum(GameInteractionEffectQueryResult giResult);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CrowdControl* Instance;
|
static CrowdControl* Instance;
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
void Enable();
|
void Enable();
|
||||||
void Disable();
|
void Disable();
|
||||||
};
|
};
|
||||||
|
@ -99,7 +99,7 @@ static bool ActorSpawnHandler(std::shared_ptr<LUS::Console> Console, const std::
|
|||||||
|
|
||||||
static bool KillPlayerHandler(std::shared_ptr<LUS::Console> Console, const std::vector<std::string>&, std::string* output) {
|
static bool KillPlayerHandler(std::shared_ptr<LUS::Console> Console, const std::vector<std::string>&, std::string* output) {
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::SetPlayerHealth();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::SetPlayerHealth();
|
||||||
effect->parameters[0] = 0;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = 0;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
INFO_MESSAGE("[SOH] You've met with a terrible fate, haven't you?");
|
INFO_MESSAGE("[SOH] You've met with a terrible fate, haven't you?");
|
||||||
@ -130,7 +130,7 @@ static bool SetPlayerHealthHandler(std::shared_ptr<LUS::Console> Console, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::SetPlayerHealth();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::SetPlayerHealth();
|
||||||
effect->parameters[0] = health;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = health;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
INFO_MESSAGE("[SOH] Player health updated to %d", health);
|
INFO_MESSAGE("[SOH] Player health updated to %d", health);
|
||||||
@ -247,8 +247,8 @@ static bool AddAmmoHandler(std::shared_ptr<LUS::Console> Console, const std::vec
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::AddOrTakeAmmo();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->parameters[0] = amount;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = amount;
|
||||||
effect->parameters[1] = it->second;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[1] = it->second;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
|
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -287,8 +287,8 @@ static bool TakeAmmoHandler(std::shared_ptr<LUS::Console> Console, const std::ve
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::AddOrTakeAmmo();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
effect->parameters[0] = -amount;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = -amount;
|
||||||
effect->parameters[1] = it->second;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[1] = it->second;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
|
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -577,7 +577,7 @@ static bool InvisibleHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::InvisibleLink();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::InvisibleLink();
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -604,8 +604,8 @@ static bool GiantLinkHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyLinkSize();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
effect->parameters[0] = GI_LINK_SIZE_GIANT;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = GI_LINK_SIZE_GIANT;
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -632,8 +632,8 @@ static bool MinishLinkHandler(std::shared_ptr<LUS::Console> Console, const std::
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyLinkSize();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
effect->parameters[0] = GI_LINK_SIZE_MINISH;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = GI_LINK_SIZE_MINISH;
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -666,7 +666,7 @@ static bool AddHeartContainerHandler(std::shared_ptr<LUS::Console> Console, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyHeartContainers();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyHeartContainers();
|
||||||
effect->parameters[0] = hearts;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = hearts;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
INFO_MESSAGE("[SOH] Added %d heart containers", hearts);
|
INFO_MESSAGE("[SOH] Added %d heart containers", hearts);
|
||||||
@ -697,7 +697,7 @@ static bool RemoveHeartContainerHandler(std::shared_ptr<LUS::Console> Console, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyHeartContainers();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyHeartContainers();
|
||||||
effect->parameters[0] = -hearts;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = -hearts;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
INFO_MESSAGE("[SOH] Removed %d heart containers", hearts);
|
INFO_MESSAGE("[SOH] Removed %d heart containers", hearts);
|
||||||
@ -717,7 +717,7 @@ static bool GravityHandler(std::shared_ptr<LUS::Console> Console, const std::vec
|
|||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyGravity();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyGravity();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
effect->parameters[0] = LUS::Math::clamp(std::stoi(args[1], nullptr, 10), GI_GRAVITY_LEVEL_LIGHT, GI_GRAVITY_LEVEL_HEAVY);
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = LUS::Math::clamp(std::stoi(args[1], nullptr, 10), GI_GRAVITY_LEVEL_LIGHT, GI_GRAVITY_LEVEL_HEAVY);
|
||||||
} catch (std::invalid_argument const& ex) {
|
} catch (std::invalid_argument const& ex) {
|
||||||
ERROR_MESSAGE("[SOH] Gravity value must be a number.");
|
ERROR_MESSAGE("[SOH] Gravity value must be a number.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -747,7 +747,7 @@ static bool NoUIHandler(std::shared_ptr<LUS::Console> Console, const std::vector
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::NoUI();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::NoUI();
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
|
|
||||||
@ -782,7 +782,7 @@ static bool DefenseModifierHandler(std::shared_ptr<LUS::Console> Console, const
|
|||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyDefenseModifier();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
effect->parameters[0] = std::stoi(args[1], nullptr, 10);
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||||
} catch (std::invalid_argument const& ex) {
|
} catch (std::invalid_argument const& ex) {
|
||||||
ERROR_MESSAGE("[SOH] Defense modifier value must be a number.");
|
ERROR_MESSAGE("[SOH] Defense modifier value must be a number.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -790,7 +790,7 @@ static bool DefenseModifierHandler(std::shared_ptr<LUS::Console> Console, const
|
|||||||
|
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
INFO_MESSAGE("[SOH] Defense modifier set to %d", effect->parameters[0]);
|
INFO_MESSAGE("[SOH] Defense modifier set to %d", dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0]);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
INFO_MESSAGE("[SOH] Command failed: Could not set defense modifier.");
|
INFO_MESSAGE("[SOH] Command failed: Could not set defense modifier.");
|
||||||
@ -812,7 +812,7 @@ static bool DamageHandler(std::shared_ptr<LUS::Console> Console, const std::vect
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
effect->parameters[0] = -value;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = -value;
|
||||||
} catch (std::invalid_argument const& ex) {
|
} catch (std::invalid_argument const& ex) {
|
||||||
ERROR_MESSAGE("[SOH] Damage value must be a number.");
|
ERROR_MESSAGE("[SOH] Damage value must be a number.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -842,7 +842,7 @@ static bool HealHandler(std::shared_ptr<LUS::Console> Console, const std::vector
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
effect->parameters[0] = value;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = value;
|
||||||
} catch (std::invalid_argument const& ex) {
|
} catch (std::invalid_argument const& ex) {
|
||||||
ERROR_MESSAGE("[SOH] Damage value must be a number.");
|
ERROR_MESSAGE("[SOH] Damage value must be a number.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -898,7 +898,7 @@ static bool NoZHandler(std::shared_ptr<LUS::Console> Console, const std::vector<
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::DisableZTargeting();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::DisableZTargeting();
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
|
|
||||||
@ -926,7 +926,7 @@ static bool OneHitKOHandler(std::shared_ptr<LUS::Console> Console, const std::ve
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::OneHitKO();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::OneHitKO();
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
|
|
||||||
@ -954,7 +954,7 @@ static bool PacifistHandler(std::shared_ptr<LUS::Console> Console, const std::ve
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::PacifistMode();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::PacifistMode();
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
|
|
||||||
@ -982,8 +982,8 @@ static bool PaperLinkHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyLinkSize();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
effect->parameters[0] = GI_LINK_SIZE_PAPER;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = GI_LINK_SIZE_PAPER;
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
|
|
||||||
@ -1011,7 +1011,7 @@ static bool RainstormHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::WeatherRainstorm();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::WeatherRainstorm();
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
|
|
||||||
@ -1039,7 +1039,7 @@ static bool ReverseControlsHandler(std::shared_ptr<LUS::Console> Console, const
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ReverseControls();
|
RemovableGameInteractionEffect* effect = new GameInteractionEffect::ReverseControls();
|
||||||
GameInteractionEffectQueryResult result =
|
GameInteractionEffectQueryResult result =
|
||||||
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
state ? GameInteractor::ApplyEffect(effect) : GameInteractor::RemoveEffect(effect);
|
||||||
|
|
||||||
@ -1062,7 +1062,7 @@ static bool UpdateRupeesHandler(std::shared_ptr<LUS::Console> Console, const std
|
|||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyRupees();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyRupees();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
effect->parameters[0] = std::stoi(args[1], nullptr, 10);
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||||
} catch (std::invalid_argument const& ex) {
|
} catch (std::invalid_argument const& ex) {
|
||||||
ERROR_MESSAGE("[SOH] Rupee value must be a number.");
|
ERROR_MESSAGE("[SOH] Rupee value must be a number.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -1086,7 +1086,7 @@ static bool SpeedModifierHandler(std::shared_ptr<LUS::Console> Console, const st
|
|||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
effect->parameters[0] = std::stoi(args[1], nullptr, 10);
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10);
|
||||||
} catch (std::invalid_argument const& ex) {
|
} catch (std::invalid_argument const& ex) {
|
||||||
ERROR_MESSAGE("[SOH] Speed modifier value must be a number.");
|
ERROR_MESSAGE("[SOH] Speed modifier value must be a number.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -1121,7 +1121,7 @@ static bool BootsHandler(std::shared_ptr<LUS::Console> Console, const std::vecto
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::ForceEquipBoots();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::ForceEquipBoots();
|
||||||
effect->parameters[0] = it->second;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = it->second;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
|
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -1152,7 +1152,7 @@ static bool GiveShieldHandler(std::shared_ptr<LUS::Console> Console, const std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::GiveOrTakeShield();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::GiveOrTakeShield();
|
||||||
effect->parameters[0] = it->second;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = it->second;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
|
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -1177,7 +1177,7 @@ static bool TakeShieldHandler(std::shared_ptr<LUS::Console> Console, const std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectBase* effect = new GameInteractionEffect::GiveOrTakeShield();
|
GameInteractionEffectBase* effect = new GameInteractionEffect::GiveOrTakeShield();
|
||||||
effect->parameters[0] = it->second * -1;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = it->second * -1;
|
||||||
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
GameInteractionEffectQueryResult result = GameInteractor::ApplyEffect(effect);
|
||||||
|
|
||||||
if (result == GameInteractionEffectQueryResult::Possible) {
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
@ -1203,7 +1203,7 @@ static bool KnockbackHandler(std::shared_ptr<LUS::Console> Console, const std::v
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
effect->parameters[0] = value;
|
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = value;
|
||||||
} catch (std::invalid_argument const& ex) {
|
} catch (std::invalid_argument const& ex) {
|
||||||
ERROR_MESSAGE("[SOH] Knockback value must be a number.");
|
ERROR_MESSAGE("[SOH] Knockback value must be a number.");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -31,11 +31,11 @@ GameInteractionEffectQueryResult GameInteractionEffectBase::Apply() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// For most effects, CanBeRemoved is the same as CanBeApplied. When its not: please override `CanBeRemoved`.
|
/// For most effects, CanBeRemoved is the same as CanBeApplied. When its not: please override `CanBeRemoved`.
|
||||||
GameInteractionEffectQueryResult GameInteractionEffectBase::CanBeRemoved() {
|
GameInteractionEffectQueryResult RemovableGameInteractionEffect::CanBeRemoved() {
|
||||||
return CanBeApplied();
|
return CanBeApplied();
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectQueryResult GameInteractionEffectBase::Remove() {
|
GameInteractionEffectQueryResult RemovableGameInteractionEffect::Remove() {
|
||||||
GameInteractionEffectQueryResult result = CanBeRemoved();
|
GameInteractionEffectQueryResult result = CanBeRemoved();
|
||||||
if (result != GameInteractionEffectQueryResult::Possible) {
|
if (result != GameInteractionEffectQueryResult::Possible) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -15,38 +15,46 @@ enum GameInteractionEffectQueryResult {
|
|||||||
class GameInteractionEffectBase {
|
class GameInteractionEffectBase {
|
||||||
public:
|
public:
|
||||||
virtual GameInteractionEffectQueryResult CanBeApplied() = 0;
|
virtual GameInteractionEffectQueryResult CanBeApplied() = 0;
|
||||||
virtual GameInteractionEffectQueryResult CanBeRemoved();
|
|
||||||
GameInteractionEffectQueryResult Apply();
|
GameInteractionEffectQueryResult Apply();
|
||||||
GameInteractionEffectQueryResult Remove();
|
protected:
|
||||||
int32_t parameters[3];
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void _Apply() = 0;
|
virtual void _Apply() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RemovableGameInteractionEffect: public GameInteractionEffectBase {
|
||||||
|
public:
|
||||||
|
virtual GameInteractionEffectQueryResult CanBeRemoved();
|
||||||
|
GameInteractionEffectQueryResult Remove();
|
||||||
|
protected:
|
||||||
virtual void _Remove() {};
|
virtual void _Remove() {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ParameterizedGameInteractionEffect {
|
||||||
|
public:
|
||||||
|
int32_t parameters[3];
|
||||||
|
};
|
||||||
|
|
||||||
namespace GameInteractionEffect {
|
namespace GameInteractionEffect {
|
||||||
class SetSceneFlag: public GameInteractionEffectBase {
|
class SetSceneFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnsetSceneFlag: public GameInteractionEffectBase {
|
class UnsetSceneFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFlag: public GameInteractionEffectBase {
|
class SetFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnsetFlag: public GameInteractionEffectBase {
|
class UnsetFlag: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyHeartContainers: public GameInteractionEffectBase {
|
class ModifyHeartContainers: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
@ -61,29 +69,29 @@ namespace GameInteractionEffect {
|
|||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyRupees: public GameInteractionEffectBase {
|
class ModifyRupees: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoUI: public GameInteractionEffectBase {
|
class NoUI: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyGravity: public GameInteractionEffectBase {
|
class ModifyGravity: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyHealth: public GameInteractionEffectBase {
|
class ModifyHealth: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetPlayerHealth: public GameInteractionEffectBase {
|
class SetPlayerHealth: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
@ -103,98 +111,98 @@ namespace GameInteractionEffect {
|
|||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class KnockbackPlayer: public GameInteractionEffectBase {
|
class KnockbackPlayer: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyLinkSize: public GameInteractionEffectBase {
|
class ModifyLinkSize: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InvisibleLink : public GameInteractionEffectBase {
|
class InvisibleLink : public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PacifistMode : public GameInteractionEffectBase {
|
class PacifistMode : public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DisableZTargeting: public GameInteractionEffectBase {
|
class DisableZTargeting: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WeatherRainstorm: public GameInteractionEffectBase {
|
class WeatherRainstorm: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReverseControls: public GameInteractionEffectBase {
|
class ReverseControls: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ForceEquipBoots: public GameInteractionEffectBase {
|
class ForceEquipBoots: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyRunSpeedModifier: public GameInteractionEffectBase {
|
class ModifyRunSpeedModifier: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OneHitKO : public GameInteractionEffectBase {
|
class OneHitKO : public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyDefenseModifier: public GameInteractionEffectBase {
|
class ModifyDefenseModifier: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GiveOrTakeShield: public GameInteractionEffectBase {
|
class GiveOrTakeShield: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TeleportPlayer: public GameInteractionEffectBase {
|
class TeleportPlayer: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ClearAssignedButtons: public GameInteractionEffectBase {
|
class ClearAssignedButtons: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetTimeOfDay: public GameInteractionEffectBase {
|
class SetTimeOfDay: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetCollisionViewer: public GameInteractionEffectBase {
|
class SetCollisionViewer: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetCosmeticsColor: public GameInteractionEffectBase {
|
class SetCosmeticsColor: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
@ -204,52 +212,52 @@ namespace GameInteractionEffect {
|
|||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PressButton: public GameInteractionEffectBase {
|
class PressButton: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PressRandomButton: public GameInteractionEffectBase {
|
class PressRandomButton: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddOrTakeAmmo: public GameInteractionEffectBase {
|
class AddOrTakeAmmo: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomBombFuseTimer: public GameInteractionEffectBase {
|
class RandomBombFuseTimer: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DisableLedgeGrabs: public GameInteractionEffectBase {
|
class DisableLedgeGrabs: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomWind: public GameInteractionEffectBase {
|
class RandomWind: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomBonks: public GameInteractionEffectBase {
|
class RandomBonks: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerInvincibility: public GameInteractionEffectBase {
|
class PlayerInvincibility: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SlipperyFloor: public GameInteractionEffectBase {
|
class SlipperyFloor: public RemovableGameInteractionEffect {
|
||||||
GameInteractionEffectQueryResult CanBeApplied() override;
|
GameInteractionEffectQueryResult CanBeApplied() override;
|
||||||
void _Apply() override;
|
void _Apply() override;
|
||||||
void _Remove() override;
|
void _Remove() override;
|
||||||
|
@ -31,7 +31,7 @@ GameInteractionEffectQueryResult GameInteractor::ApplyEffect(GameInteractionEffe
|
|||||||
return effect->Apply();
|
return effect->Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
GameInteractionEffectQueryResult GameInteractor::RemoveEffect(GameInteractionEffectBase* effect) {
|
GameInteractionEffectQueryResult GameInteractor::RemoveEffect(RemovableGameInteractionEffect* effect) {
|
||||||
return effect->Remove();
|
return effect->Remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,11 @@
|
|||||||
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
|
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
|
||||||
#include <z64.h>
|
#include <z64.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GI_SCHEME_SAIL,
|
||||||
|
GI_SCHEME_CROWD_CONTROL,
|
||||||
|
} GIScheme;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* 0x00 */ GI_LINK_SIZE_NORMAL,
|
/* 0x00 */ GI_LINK_SIZE_NORMAL,
|
||||||
/* 0x01 */ GI_LINK_SIZE_GIANT,
|
/* 0x01 */ GI_LINK_SIZE_GIANT,
|
||||||
@ -92,10 +97,15 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
|
|||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
#include <SDL2/SDL_net.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEFINE_HOOK(name, type) \
|
#define DEFINE_HOOK(name, type) \
|
||||||
struct name { \
|
struct name { \
|
||||||
typedef std::function<type> fn; \
|
typedef std::function<type> fn; \
|
||||||
@ -132,10 +142,24 @@ public:
|
|||||||
static void SetPacifistMode(bool active);
|
static void SetPacifistMode(bool active);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
bool isRemoteInteractorEnabled;
|
||||||
|
bool isRemoteInteractorConnected;
|
||||||
|
|
||||||
|
void EnableRemoteInteractor();
|
||||||
|
void DisableRemoteInteractor();
|
||||||
|
void RegisterRemoteDataHandler(std::function<void(char payload[512])> method);
|
||||||
|
void RegisterRemoteJsonHandler(std::function<void(nlohmann::json)> method);
|
||||||
|
void RegisterRemoteConnectedHandler(std::function<void()> method);
|
||||||
|
void RegisterRemoteDisconnectedHandler(std::function<void()> method);
|
||||||
|
void TransmitDataToRemote(const char* payload);
|
||||||
|
void TransmitJsonToRemote(nlohmann::json packet);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Effects
|
// Effects
|
||||||
static GameInteractionEffectQueryResult CanApplyEffect(GameInteractionEffectBase* effect);
|
static GameInteractionEffectQueryResult CanApplyEffect(GameInteractionEffectBase* effect);
|
||||||
static GameInteractionEffectQueryResult ApplyEffect(GameInteractionEffectBase* effect);
|
static GameInteractionEffectQueryResult ApplyEffect(GameInteractionEffectBase* effect);
|
||||||
static GameInteractionEffectQueryResult RemoveEffect(GameInteractionEffectBase* effect);
|
static GameInteractionEffectQueryResult RemoveEffect(RemovableGameInteractionEffect* effect);
|
||||||
|
|
||||||
// Game Hooks
|
// Game Hooks
|
||||||
template <typename H> struct RegisteredGameHooks { inline static std::vector<typename H::fn> functions; };
|
template <typename H> struct RegisteredGameHooks { inline static std::vector<typename H::fn> functions; };
|
||||||
@ -238,6 +262,21 @@ public:
|
|||||||
static GameInteractionEffectQueryResult SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams);
|
static GameInteractionEffectQueryResult SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams);
|
||||||
static GameInteractionEffectQueryResult SpawnActor(uint32_t actorId, int32_t actorParams);
|
static GameInteractionEffectQueryResult SpawnActor(uint32_t actorId, int32_t actorParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
IPaddress remoteIP;
|
||||||
|
TCPsocket remoteSocket;
|
||||||
|
std::thread remoteThreadReceive;
|
||||||
|
std::function<void(char payload[512])> remoteDataHandler;
|
||||||
|
std::function<void(nlohmann::json)> remoteJsonHandler;
|
||||||
|
std::function<void()> remoteConnectedHandler;
|
||||||
|
std::function<void()> remoteDisconnectedHandler;
|
||||||
|
|
||||||
|
void ReceiveFromServer();
|
||||||
|
void HandleRemoteData(char payload[512]);
|
||||||
|
void HandleRemoteJson(std::string payload);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
182
soh/soh/Enhancements/game-interactor/GameInteractor_Remote.cpp
Normal file
182
soh/soh/Enhancements/game-interactor/GameInteractor_Remote.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
|
||||||
|
#include "GameInteractor.h"
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <ImGui/imgui.h>
|
||||||
|
#include <ImGui/imgui_internal.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <libultraship/libultraship.h>
|
||||||
|
|
||||||
|
// MARK: - Remote
|
||||||
|
|
||||||
|
void GameInteractor::EnableRemoteInteractor() {
|
||||||
|
if (isRemoteInteractorEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDLNet_ResolveHost(&remoteIP, CVarGetString("gRemote.IP", "127.0.0.1"), CVarGetInteger("gRemote.Port", 43384)) == -1) {
|
||||||
|
SPDLOG_ERROR("[GameInteractor] SDLNet_ResolveHost: {}", SDLNet_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
isRemoteInteractorEnabled = true;
|
||||||
|
|
||||||
|
// First check if there is a thread running, if so, join it
|
||||||
|
if (remoteThreadReceive.joinable()) {
|
||||||
|
remoteThreadReceive.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteThreadReceive = std::thread(&GameInteractor::ReceiveFromServer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw data handler
|
||||||
|
*
|
||||||
|
* If you are developing a new remote, you should probably use the json methods instead. This
|
||||||
|
* method requires you to parse the data and ensure packets are complete manually, we cannot
|
||||||
|
* gaurentee that the data will be complete, or that it will only contain one packet with this
|
||||||
|
*/
|
||||||
|
void GameInteractor::RegisterRemoteDataHandler(std::function<void(char payload[512])> method) {
|
||||||
|
remoteDataHandler = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Json handler
|
||||||
|
*
|
||||||
|
* This method will be called when a complete json packet is received. All json packets must
|
||||||
|
* be delimited by a null terminator (\0).
|
||||||
|
*/
|
||||||
|
void GameInteractor::RegisterRemoteJsonHandler(std::function<void(nlohmann::json)> method) {
|
||||||
|
remoteJsonHandler = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractor::RegisterRemoteConnectedHandler(std::function<void()> method) {
|
||||||
|
remoteConnectedHandler = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractor::RegisterRemoteDisconnectedHandler(std::function<void()> method) {
|
||||||
|
remoteDisconnectedHandler = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractor::DisableRemoteInteractor() {
|
||||||
|
if (!isRemoteInteractorEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isRemoteInteractorEnabled = false;
|
||||||
|
remoteThreadReceive.join();
|
||||||
|
remoteDataHandler = nullptr;
|
||||||
|
remoteJsonHandler = nullptr;
|
||||||
|
remoteConnectedHandler = nullptr;
|
||||||
|
remoteDisconnectedHandler = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractor::TransmitDataToRemote(const char* payload) {
|
||||||
|
SDLNet_TCP_Send(remoteSocket, payload, strlen(payload) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends a newline character to the end of the json payload and sends it to the remote
|
||||||
|
void GameInteractor::TransmitJsonToRemote(nlohmann::json payload) {
|
||||||
|
TransmitDataToRemote(payload.dump().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
std::string receivedData;
|
||||||
|
|
||||||
|
void GameInteractor::ReceiveFromServer() {
|
||||||
|
while (isRemoteInteractorEnabled) {
|
||||||
|
while (!isRemoteInteractorConnected && isRemoteInteractorEnabled) {
|
||||||
|
SPDLOG_TRACE("[GameInteractor] Attempting to make connection to server...");
|
||||||
|
remoteSocket = SDLNet_TCP_Open(&remoteIP);
|
||||||
|
|
||||||
|
if (remoteSocket) {
|
||||||
|
isRemoteInteractorConnected = true;
|
||||||
|
SPDLOG_INFO("[GameInteractor] Connection to server established!");
|
||||||
|
|
||||||
|
if (remoteConnectedHandler) {
|
||||||
|
remoteConnectedHandler();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(1);
|
||||||
|
if (remoteSocket) {
|
||||||
|
SDLNet_TCP_AddSocket(socketSet, remoteSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen to socket messages
|
||||||
|
while (isRemoteInteractorConnected && remoteSocket && isRemoteInteractorEnabled) {
|
||||||
|
// we check first if socket has data, to not block in the TCP_Recv
|
||||||
|
int socketsReady = SDLNet_CheckSockets(socketSet, 0);
|
||||||
|
|
||||||
|
if (socketsReady == -1) {
|
||||||
|
SPDLOG_ERROR("[GameInteractor] SDLNet_CheckSockets: {}", SDLNet_GetError());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socketsReady == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char remoteDataReceived[512];
|
||||||
|
memset(remoteDataReceived, 0, sizeof(remoteDataReceived));
|
||||||
|
int len = SDLNet_TCP_Recv(remoteSocket, &remoteDataReceived, sizeof(remoteDataReceived));
|
||||||
|
if (!len || !remoteSocket || len == -1) {
|
||||||
|
SPDLOG_ERROR("[GameInteractor] SDLNet_TCP_Recv: {}", SDLNet_GetError());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleRemoteData(remoteDataReceived);
|
||||||
|
|
||||||
|
receivedData.append(remoteDataReceived, len);
|
||||||
|
|
||||||
|
// Proess all complete packets
|
||||||
|
size_t delimiterPos = receivedData.find('\0');
|
||||||
|
while (delimiterPos != std::string::npos) {
|
||||||
|
// Extract the complete packet until the delimiter
|
||||||
|
std::string packet = receivedData.substr(0, delimiterPos);
|
||||||
|
// Remove the packet (including the delimiter) from the received data
|
||||||
|
receivedData.erase(0, delimiterPos + 1);
|
||||||
|
HandleRemoteJson(packet);
|
||||||
|
// Find the next delimiter
|
||||||
|
delimiterPos = receivedData.find('\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRemoteInteractorConnected) {
|
||||||
|
SDLNet_TCP_Close(remoteSocket);
|
||||||
|
isRemoteInteractorConnected = false;
|
||||||
|
if (remoteDisconnectedHandler) {
|
||||||
|
remoteDisconnectedHandler();
|
||||||
|
}
|
||||||
|
SPDLOG_INFO("[GameInteractor] Ending receiving thread...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractor::HandleRemoteData(char payload[512]) {
|
||||||
|
if (remoteDataHandler) {
|
||||||
|
remoteDataHandler(payload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractor::HandleRemoteJson(std::string payload) {
|
||||||
|
nlohmann::json jsonPayload;
|
||||||
|
try {
|
||||||
|
jsonPayload = nlohmann::json::parse(payload);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
SPDLOG_ERROR("[GameInteractor] Failed to parse json: \n{}\n{}\n", payload, e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remoteJsonHandler) {
|
||||||
|
remoteJsonHandler(jsonPayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
471
soh/soh/Enhancements/game-interactor/GameInteractor_Sail.cpp
Normal file
471
soh/soh/Enhancements/game-interactor/GameInteractor_Sail.cpp
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
|
||||||
|
#include "GameInteractor_Sail.h"
|
||||||
|
#include <libultraship/bridge.h>
|
||||||
|
#include <libultraship/libultraship.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
template <class DstType, class SrcType>
|
||||||
|
bool IsType(const SrcType* src) {
|
||||||
|
return dynamic_cast<const DstType*>(src) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractorSail::Enable() {
|
||||||
|
if (isEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEnabled = true;
|
||||||
|
GameInteractor::Instance->EnableRemoteInteractor();
|
||||||
|
GameInteractor::Instance->RegisterRemoteJsonHandler([&](nlohmann::json payload) {
|
||||||
|
HandleRemoteJson(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterRemoteConnectedHandler([&]() {
|
||||||
|
RegisterHooks();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractorSail::Disable() {
|
||||||
|
if (!isEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEnabled = false;
|
||||||
|
GameInteractor::Instance->DisableRemoteInteractor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInteractorSail::HandleRemoteJson(nlohmann::json payload) {
|
||||||
|
SPDLOG_INFO("[GameInteractorSail] Received payload: \n{}", payload.dump());
|
||||||
|
|
||||||
|
nlohmann::json responsePayload;
|
||||||
|
responsePayload["type"] = "result";
|
||||||
|
responsePayload["status"] = "failure";
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!payload.contains("id")) {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Received payload without ID");
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
responsePayload["id"] = payload["id"];
|
||||||
|
|
||||||
|
if (!payload.contains("type")) {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Received payload without type");
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string payloadType = payload["type"].get<std::string>();
|
||||||
|
|
||||||
|
if (payloadType == "command") {
|
||||||
|
if (!payload.contains("command")) {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Received command payload without command");
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string command = payload["command"].get<std::string>();
|
||||||
|
std::reinterpret_pointer_cast<LUS::ConsoleWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->Dispatch(command);
|
||||||
|
responsePayload["status"] = "success";
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
} else if (payloadType == "effect") {
|
||||||
|
if (!payload.contains("effect") || !payload["effect"].contains("type")) {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Received effect payload without effect type");
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string effectType = payload["effect"]["type"].get<std::string>();
|
||||||
|
|
||||||
|
// Special case for "command" effect, so we can also run commands from the `simple_twitch_sail` script
|
||||||
|
if (effectType == "command") {
|
||||||
|
if (!payload["effect"].contains("command")) {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Received command effect payload without command");
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string command = payload["effect"]["command"].get<std::string>();
|
||||||
|
std::reinterpret_pointer_cast<LUS::ConsoleWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->Dispatch(command);
|
||||||
|
responsePayload["status"] = "success";
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectType != "apply" && effectType != "remove") {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Received effect payload with unknown effect type: {}", effectType);
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GameInteractor::IsSaveLoaded()) {
|
||||||
|
responsePayload["status"] = "try_again";
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameInteractionEffectBase* giEffect = EffectFromJson(payload["effect"]);
|
||||||
|
if (giEffect) {
|
||||||
|
GameInteractionEffectQueryResult result;
|
||||||
|
if (effectType == "remove") {
|
||||||
|
if (IsType<RemovableGameInteractionEffect>(giEffect)) {
|
||||||
|
result = dynamic_cast<RemovableGameInteractionEffect*>(giEffect)->Remove();
|
||||||
|
} else {
|
||||||
|
result = GameInteractionEffectQueryResult::NotPossible;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = giEffect->Apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == GameInteractionEffectQueryResult::Possible) {
|
||||||
|
responsePayload["status"] = "success";
|
||||||
|
} else if (result == GameInteractionEffectQueryResult::TemporarilyNotPossible) {
|
||||||
|
responsePayload["status"] = "try_again";
|
||||||
|
}
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Unknown payload type: {}", payloadType);
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, something went wrong, send the failure response
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Failed to handle remote JSON, sending failure response");
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(responsePayload);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Exception handling remote JSON: {}", e.what());
|
||||||
|
} catch (...) {
|
||||||
|
SPDLOG_ERROR("[GameInteractorSail] Unknown exception handling remote JSON");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameInteractionEffectBase* GameInteractorSail::EffectFromJson(nlohmann::json payload) {
|
||||||
|
if (!payload.contains("name")) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = payload["name"].get<std::string>();
|
||||||
|
|
||||||
|
if (name == "SetSceneFlag") {
|
||||||
|
auto effect = new GameInteractionEffect::SetSceneFlag();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
effect->parameters[1] = payload["parameters"][1].get<int32_t>();
|
||||||
|
effect->parameters[2] = payload["parameters"][2].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "UnsetSceneFlag") {
|
||||||
|
auto effect = new GameInteractionEffect::UnsetSceneFlag();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
effect->parameters[1] = payload["parameters"][1].get<int32_t>();
|
||||||
|
effect->parameters[2] = payload["parameters"][2].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "SetFlag") {
|
||||||
|
auto effect = new GameInteractionEffect::SetFlag();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
effect->parameters[1] = payload["parameters"][1].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "UnsetFlag") {
|
||||||
|
auto effect = new GameInteractionEffect::UnsetFlag();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
effect->parameters[1] = payload["parameters"][1].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "ModifyHeartContainers") {
|
||||||
|
auto effect = new GameInteractionEffect::ModifyHeartContainers();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "FillMagic") {
|
||||||
|
return new GameInteractionEffect::FillMagic();
|
||||||
|
} else if (name == "EmptyMagic") {
|
||||||
|
return new GameInteractionEffect::EmptyMagic();
|
||||||
|
} else if (name == "ModifyRupees") {
|
||||||
|
auto effect = new GameInteractionEffect::ModifyRupees();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "NoUI") {
|
||||||
|
return new GameInteractionEffect::NoUI();
|
||||||
|
} else if (name == "ModifyGravity") {
|
||||||
|
auto effect = new GameInteractionEffect::ModifyGravity();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "ModifyHealth") {
|
||||||
|
auto effect = new GameInteractionEffect::ModifyHealth();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "SetPlayerHealth") {
|
||||||
|
auto effect = new GameInteractionEffect::SetPlayerHealth();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "FreezePlayer") {
|
||||||
|
return new GameInteractionEffect::FreezePlayer();
|
||||||
|
} else if (name == "BurnPlayer") {
|
||||||
|
return new GameInteractionEffect::BurnPlayer();
|
||||||
|
} else if (name == "ElectrocutePlayer") {
|
||||||
|
return new GameInteractionEffect::ElectrocutePlayer();
|
||||||
|
} else if (name == "KnockbackPlayer") {
|
||||||
|
auto effect = new GameInteractionEffect::KnockbackPlayer();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "ModifyLinkSize") {
|
||||||
|
auto effect = new GameInteractionEffect::ModifyLinkSize();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "InvisibleLink") {
|
||||||
|
return new GameInteractionEffect::InvisibleLink();
|
||||||
|
} else if (name == "PacifistMode") {
|
||||||
|
return new GameInteractionEffect::PacifistMode();
|
||||||
|
} else if (name == "DisableZTargeting") {
|
||||||
|
return new GameInteractionEffect::DisableZTargeting();
|
||||||
|
} else if (name == "WeatherRainstorm") {
|
||||||
|
return new GameInteractionEffect::WeatherRainstorm();
|
||||||
|
} else if (name == "ReverseControls") {
|
||||||
|
return new GameInteractionEffect::ReverseControls();
|
||||||
|
} else if (name == "ForceEquipBoots") {
|
||||||
|
auto effect = new GameInteractionEffect::ForceEquipBoots();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "ModifyRunSpeedModifier") {
|
||||||
|
auto effect = new GameInteractionEffect::ModifyRunSpeedModifier();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "OneHitKO") {
|
||||||
|
return new GameInteractionEffect::OneHitKO();
|
||||||
|
} else if (name == "ModifyDefenseModifier") {
|
||||||
|
auto effect = new GameInteractionEffect::ModifyDefenseModifier();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "GiveOrTakeShield") {
|
||||||
|
auto effect = new GameInteractionEffect::GiveOrTakeShield();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "TeleportPlayer") {
|
||||||
|
auto effect = new GameInteractionEffect::TeleportPlayer();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "ClearAssignedButtons") {
|
||||||
|
auto effect = new GameInteractionEffect::ClearAssignedButtons();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "SetTimeOfDay") {
|
||||||
|
auto effect = new GameInteractionEffect::SetTimeOfDay();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "SetCollisionViewer") {
|
||||||
|
return new GameInteractionEffect::SetCollisionViewer();
|
||||||
|
} else if (name == "SetCosmeticsColor") {
|
||||||
|
auto effect = new GameInteractionEffect::SetCosmeticsColor();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
effect->parameters[1] = payload["parameters"][1].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "RandomizeCosmetics") {
|
||||||
|
return new GameInteractionEffect::RandomizeCosmetics();
|
||||||
|
} else if (name == "PressButton") {
|
||||||
|
auto effect = new GameInteractionEffect::PressButton();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "PressRandomButton") {
|
||||||
|
auto effect = new GameInteractionEffect::PressRandomButton();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "AddOrTakeAmmo") {
|
||||||
|
auto effect = new GameInteractionEffect::AddOrTakeAmmo();
|
||||||
|
if (payload.contains("parameters")) {
|
||||||
|
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
|
||||||
|
effect->parameters[1] = payload["parameters"][1].get<int32_t>();
|
||||||
|
}
|
||||||
|
return effect;
|
||||||
|
} else if (name == "RandomBombFuseTimer") {
|
||||||
|
return new GameInteractionEffect::RandomBombFuseTimer();
|
||||||
|
} else if (name == "DisableLedgeGrabs") {
|
||||||
|
return new GameInteractionEffect::DisableLedgeGrabs();
|
||||||
|
} else if (name == "RandomWind") {
|
||||||
|
return new GameInteractionEffect::RandomWind();
|
||||||
|
} else if (name == "RandomBonks") {
|
||||||
|
return new GameInteractionEffect::RandomBonks();
|
||||||
|
} else if (name == "PlayerInvincibility") {
|
||||||
|
return new GameInteractionEffect::PlayerInvincibility();
|
||||||
|
} else if (name == "SlipperyFloor") {
|
||||||
|
return new GameInteractionEffect::SlipperyFloor();
|
||||||
|
} else {
|
||||||
|
SPDLOG_INFO("[GameInteractorSail] Unknown effect name: {}", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround until we have a way to unregister hooks
|
||||||
|
static bool hasRegisteredHooks = false;
|
||||||
|
|
||||||
|
void GameInteractorSail::RegisterHooks() {
|
||||||
|
if (hasRegisteredHooks) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hasRegisteredHooks = true;
|
||||||
|
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnTransitionEnd>([](int32_t sceneNum) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnTransitionEnd";
|
||||||
|
payload["hook"]["sceneNum"] = sceneNum;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>([](int32_t fileNum) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnLoadGame";
|
||||||
|
payload["hook"]["fileNum"] = fileNum;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnExitGame>([](int32_t fileNum) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnExitGame";
|
||||||
|
payload["hook"]["fileNum"] = fileNum;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>([](GetItemEntry itemEntry) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnItemReceive";
|
||||||
|
payload["hook"]["tableId"] = itemEntry.tableId;
|
||||||
|
payload["hook"]["getItemId"] = itemEntry.getItemId;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnEnemyDefeat>([](void* refActor) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
Actor* actor = (Actor*)refActor;
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnEnemyDefeat";
|
||||||
|
payload["hook"]["actorId"] = actor->id;
|
||||||
|
payload["hook"]["params"] = actor->params;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](void* refActor) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
Actor* actor = (Actor*)refActor;
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnActorInit";
|
||||||
|
payload["hook"]["actorId"] = actor->id;
|
||||||
|
payload["hook"]["params"] = actor->params;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>([](int16_t flagType, int16_t flag) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnFlagSet";
|
||||||
|
payload["hook"]["flagType"] = flagType;
|
||||||
|
payload["hook"]["flag"] = flag;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagUnset>([](int16_t flagType, int16_t flag) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnFlagUnset";
|
||||||
|
payload["hook"]["flagType"] = flagType;
|
||||||
|
payload["hook"]["flag"] = flag;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagSet>([](int16_t sceneNum, int16_t flagType, int16_t flag) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnSceneFlagSet";
|
||||||
|
payload["hook"]["flagType"] = flagType;
|
||||||
|
payload["hook"]["flag"] = flag;
|
||||||
|
payload["hook"]["sceneNum"] = sceneNum;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagUnset>([](int16_t sceneNum, int16_t flagType, int16_t flag) {
|
||||||
|
if (!GameInteractor::Instance->isRemoteInteractorConnected || !GameInteractor::IsSaveLoaded()) return;
|
||||||
|
|
||||||
|
nlohmann::json payload;
|
||||||
|
payload["id"] = std::rand();
|
||||||
|
payload["type"] = "hook";
|
||||||
|
payload["hook"]["type"] = "OnSceneFlagUnset";
|
||||||
|
payload["hook"]["flagType"] = flagType;
|
||||||
|
payload["hook"]["flag"] = flag;
|
||||||
|
payload["hook"]["sceneNum"] = sceneNum;
|
||||||
|
|
||||||
|
GameInteractor::Instance->TransmitJsonToRemote(payload);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
29
soh/soh/Enhancements/game-interactor/GameInteractor_Sail.h
Normal file
29
soh/soh/Enhancements/game-interactor/GameInteractor_Sail.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <SDL2/SDL_net.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <thread>
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
#include "./GameInteractor.h"
|
||||||
|
|
||||||
|
class GameInteractorSail {
|
||||||
|
private:
|
||||||
|
bool isEnabled;
|
||||||
|
|
||||||
|
void HandleRemoteJson(nlohmann::json payload);
|
||||||
|
GameInteractionEffectBase* EffectFromJson(nlohmann::json payload);
|
||||||
|
void RegisterHooks();
|
||||||
|
public:
|
||||||
|
static GameInteractorSail* Instance;
|
||||||
|
void Enable();
|
||||||
|
void Disable();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -81,9 +81,11 @@
|
|||||||
#include "SohGui.hpp"
|
#include "SohGui.hpp"
|
||||||
#include "ActorDB.h"
|
#include "ActorDB.h"
|
||||||
|
|
||||||
#ifdef ENABLE_CROWD_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
#include "Enhancements/crowd-control/CrowdControl.h"
|
#include "Enhancements/crowd-control/CrowdControl.h"
|
||||||
|
#include "Enhancements/game-interactor/GameInteractor_Sail.h"
|
||||||
CrowdControl* CrowdControl::Instance;
|
CrowdControl* CrowdControl::Instance;
|
||||||
|
GameInteractorSail* GameInteractorSail::Instance;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Enhancements/mods.h"
|
#include "Enhancements/mods.h"
|
||||||
@ -1097,7 +1099,12 @@ extern "C" void InitOTR() {
|
|||||||
SpeechSynthesizer::Instance = new SAPISpeechSynthesizer();
|
SpeechSynthesizer::Instance = new SAPISpeechSynthesizer();
|
||||||
SpeechSynthesizer::Instance->Init();
|
SpeechSynthesizer::Instance->Init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
CrowdControl::Instance = new CrowdControl();
|
||||||
|
GameInteractorSail::Instance = new GameInteractorSail();
|
||||||
|
#endif
|
||||||
|
|
||||||
clearMtx = (uintptr_t)&gMtxClear;
|
clearMtx = (uintptr_t)&gMtxClear;
|
||||||
OTRMessage_Init();
|
OTRMessage_Init();
|
||||||
OTRAudio_Init();
|
OTRAudio_Init();
|
||||||
@ -1117,13 +1124,17 @@ extern "C" void InitOTR() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
srand(now);
|
srand(now);
|
||||||
#ifdef ENABLE_CROWD_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
CrowdControl::Instance = new CrowdControl();
|
SDLNet_Init();
|
||||||
CrowdControl::Instance->Init();
|
if (CVarGetInteger("gRemote.Enabled", 0)) {
|
||||||
if (CVarGetInteger("gCrowdControl", 0)) {
|
switch (CVarGetInteger("gRemote.Scheme", GI_SCHEME_SAIL)) {
|
||||||
CrowdControl::Instance->Enable();
|
case GI_SCHEME_SAIL:
|
||||||
} else {
|
GameInteractorSail::Instance->Enable();
|
||||||
CrowdControl::Instance->Disable();
|
break;
|
||||||
|
case GI_SCHEME_CROWD_CONTROL:
|
||||||
|
CrowdControl::Instance->Enable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1140,9 +1151,18 @@ extern "C" void SaveManager_ThreadPoolWait() {
|
|||||||
extern "C" void DeinitOTR() {
|
extern "C" void DeinitOTR() {
|
||||||
SaveManager_ThreadPoolWait();
|
SaveManager_ThreadPoolWait();
|
||||||
OTRAudio_Exit();
|
OTRAudio_Exit();
|
||||||
#ifdef ENABLE_CROWD_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
CrowdControl::Instance->Disable();
|
if (CVarGetInteger("gRemote.Enabled", 0)) {
|
||||||
CrowdControl::Instance->Shutdown();
|
switch (CVarGetInteger("gRemote.Scheme", GI_SCHEME_SAIL)) {
|
||||||
|
case GI_SCHEME_SAIL:
|
||||||
|
GameInteractorSail::Instance->Disable();
|
||||||
|
break;
|
||||||
|
case GI_SCHEME_CROWD_CONTROL:
|
||||||
|
CrowdControl::Instance->Disable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDLNet_Quit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Destroying gui here because we have shared ptrs to LUS objects which output to SPDLOG which is destroyed before these shared ptrs.
|
// Destroying gui here because we have shared ptrs to LUS objects which output to SPDLOG which is destroyed before these shared ptrs.
|
||||||
|
@ -31,8 +31,9 @@
|
|||||||
#include "soh/resource/type/Skeleton.h"
|
#include "soh/resource/type/Skeleton.h"
|
||||||
#include "libultraship/libultraship.h"
|
#include "libultraship/libultraship.h"
|
||||||
|
|
||||||
#ifdef ENABLE_CROWD_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
#include "Enhancements/crowd-control/CrowdControl.h"
|
#include "Enhancements/crowd-control/CrowdControl.h"
|
||||||
|
#include "Enhancements/game-interactor/GameInteractor_Sail.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Enhancements/game-interactor/GameInteractor.h"
|
#include "Enhancements/game-interactor/GameInteractor.h"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "SohMenuBar.h"
|
#include "SohMenuBar.h"
|
||||||
#include "ImGui/imgui.h"
|
#include "ImGui/imgui.h"
|
||||||
|
#include "regex"
|
||||||
#include "public/bridge/consolevariablebridge.h"
|
#include "public/bridge/consolevariablebridge.h"
|
||||||
#include <libultraship/libultraship.h>
|
#include <libultraship/libultraship.h>
|
||||||
#include "UIWidgets.hpp"
|
#include "UIWidgets.hpp"
|
||||||
@ -10,8 +11,9 @@
|
|||||||
#include "soh/Enhancements/presets.h"
|
#include "soh/Enhancements/presets.h"
|
||||||
#include "soh/Enhancements/mods.h"
|
#include "soh/Enhancements/mods.h"
|
||||||
#include "Enhancements/cosmetics/authenticGfxPatches.h"
|
#include "Enhancements/cosmetics/authenticGfxPatches.h"
|
||||||
#ifdef ENABLE_CROWD_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
#include "Enhancements/crowd-control/CrowdControl.h"
|
#include "Enhancements/crowd-control/CrowdControl.h"
|
||||||
|
#include "Enhancements/game-interactor/GameInteractor_Sail.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -1116,17 +1118,6 @@ void DrawEnhancementsMenu() {
|
|||||||
UIWidgets::Spacer(0);
|
UIWidgets::Spacer(0);
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Extra Modes")) {
|
if (ImGui::BeginMenu("Extra Modes")) {
|
||||||
#ifdef ENABLE_CROWD_CONTROL
|
|
||||||
if (UIWidgets::PaddedEnhancementCheckbox("Crowd Control", "gCrowdControl", false, false)) {
|
|
||||||
if (CVarGetInteger("gCrowdControl", 0)) {
|
|
||||||
CrowdControl::Instance->Enable();
|
|
||||||
} else {
|
|
||||||
CrowdControl::Instance->Disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UIWidgets::Tooltip("Will attempt to connect to the Crowd Control server. Check out crowdcontrol.live for more information.");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UIWidgets::PaddedText("Mirrored World", true, false);
|
UIWidgets::PaddedText("Mirrored World", true, false);
|
||||||
if (UIWidgets::EnhancementCombobox("gMirroredWorldMode", mirroredWorldModes, MIRRORED_WORLD_OFF) && gPlayState != NULL) {
|
if (UIWidgets::EnhancementCombobox("gMirroredWorldMode", mirroredWorldModes, MIRRORED_WORLD_OFF) && gPlayState != NULL) {
|
||||||
UpdateMirrorModeState(gPlayState->sceneNum);
|
UpdateMirrorModeState(gPlayState->sceneNum);
|
||||||
@ -1520,6 +1511,135 @@ void DrawDeveloperToolsMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isStringEmpty(std::string str) {
|
||||||
|
// Remove spaces at the beginning of the string
|
||||||
|
std::string::size_type start = str.find_first_not_of(' ');
|
||||||
|
// Remove spaces at the end of the string
|
||||||
|
std::string::size_type end = str.find_last_not_of(' ');
|
||||||
|
|
||||||
|
// Check if the string is empty after stripping spaces
|
||||||
|
if (start == std::string::npos || end == std::string::npos)
|
||||||
|
return true; // The string is empty
|
||||||
|
else
|
||||||
|
return false; // The string is not empty
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
void DrawRemoteControlMenu() {
|
||||||
|
if (ImGui::BeginMenu("Network")) {
|
||||||
|
static std::string ip = CVarGetString("gRemote.IP", "127.0.0.1");
|
||||||
|
static uint16_t port = CVarGetInteger("gRemote.Port", 43384);
|
||||||
|
bool isFormValid = !isStringEmpty(CVarGetString("gRemote.IP", "127.0.0.1")) && port > 1024 && port < 65535;
|
||||||
|
|
||||||
|
const char* remoteOptions[2] = { "Sail", "Crowd Control"};
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(GameInteractor::Instance->isRemoteInteractorEnabled);
|
||||||
|
ImGui::Text("Remote Interaction Scheme");
|
||||||
|
if (UIWidgets::EnhancementCombobox("gRemote.Scheme", remoteOptions, GI_SCHEME_SAIL)) {
|
||||||
|
switch (CVarGetInteger("gRemote.Scheme", GI_SCHEME_SAIL)) {
|
||||||
|
case GI_SCHEME_SAIL:
|
||||||
|
case GI_SCHEME_CROWD_CONTROL:
|
||||||
|
CVarSetString("gRemote.IP", "127.0.0.1");
|
||||||
|
CVarSetInteger("gRemote.Port", 43384);
|
||||||
|
ip = "127.0.0.1";
|
||||||
|
port = 43384;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
|
}
|
||||||
|
switch (CVarGetInteger("gRemote.Scheme", GI_SCHEME_SAIL)) {
|
||||||
|
case GI_SCHEME_SAIL:
|
||||||
|
UIWidgets::InsertHelpHoverText(
|
||||||
|
"Sail is a networking protocol designed to facilitate remote "
|
||||||
|
"control of the Ship of Harkinian client. It is intended to "
|
||||||
|
"be utilized alongside a Sail server, for which we provide a "
|
||||||
|
"few straightforward implementations on our GitHub. The current "
|
||||||
|
"implementations available allow integration with Twitch chat "
|
||||||
|
"and SAMMI Bot, feel free to contribute your own!\n"
|
||||||
|
"\n"
|
||||||
|
"Click the question mark to copy the link to the Sail Github "
|
||||||
|
"page to your clipboard."
|
||||||
|
);
|
||||||
|
if (ImGui::IsItemClicked()) {
|
||||||
|
ImGui::SetClipboardText("https://github.com/HarbourMasters/sail");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GI_SCHEME_CROWD_CONTROL:
|
||||||
|
UIWidgets::InsertHelpHoverText(
|
||||||
|
"Crowd Control is a platform that allows viewers to interact "
|
||||||
|
"with a streamer's game in real time.\n"
|
||||||
|
"\n"
|
||||||
|
"Click the question mark to copy the link to the Crowd Control "
|
||||||
|
"website to your clipboard."
|
||||||
|
);
|
||||||
|
if (ImGui::IsItemClicked()) {
|
||||||
|
ImGui::SetClipboardText("https://crowdcontrol.live");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text("Remote IP & Port");
|
||||||
|
if (ImGui::InputText("##gRemote.IP", (char*)ip.c_str(), ip.capacity() + 1)) {
|
||||||
|
CVarSetString("gRemote.IP", ip.c_str());
|
||||||
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushItemWidth(ImGui::GetFontSize() * 5);
|
||||||
|
if (ImGui::InputScalar("##gRemote.Port", ImGuiDataType_U16, &port)) {
|
||||||
|
CVarSetInteger("gRemote.Port", port);
|
||||||
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(!isFormValid);
|
||||||
|
const char* buttonLabel = GameInteractor::Instance->isRemoteInteractorEnabled ? "Disable" : "Enable";
|
||||||
|
if (ImGui::Button(buttonLabel, ImVec2(-1.0f, 0.0f))) {
|
||||||
|
if (GameInteractor::Instance->isRemoteInteractorEnabled) {
|
||||||
|
CVarSetInteger("gRemote.Enabled", 0);
|
||||||
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
|
switch (CVarGetInteger("gRemote.Scheme", GI_SCHEME_SAIL)) {
|
||||||
|
case GI_SCHEME_SAIL:
|
||||||
|
GameInteractorSail::Instance->Disable();
|
||||||
|
break;
|
||||||
|
case GI_SCHEME_CROWD_CONTROL:
|
||||||
|
CrowdControl::Instance->Disable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CVarSetInteger("gRemote.Enabled", 1);
|
||||||
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||||
|
switch (CVarGetInteger("gRemote.Scheme", GI_SCHEME_SAIL)) {
|
||||||
|
case GI_SCHEME_SAIL:
|
||||||
|
GameInteractorSail::Instance->Enable();
|
||||||
|
break;
|
||||||
|
case GI_SCHEME_CROWD_CONTROL:
|
||||||
|
CrowdControl::Instance->Enable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
if (GameInteractor::Instance->isRemoteInteractorEnabled) {
|
||||||
|
ImGui::Spacing();
|
||||||
|
if (GameInteractor::Instance->isRemoteInteractorConnected) {
|
||||||
|
ImGui::Text("Connected");
|
||||||
|
} else {
|
||||||
|
ImGui::Text("Connecting...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Dummy(ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
extern std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow;
|
extern std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow;
|
||||||
extern std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
|
extern std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
|
||||||
extern std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
|
extern std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
|
||||||
@ -1658,6 +1778,12 @@ void SohMenuBar::DrawElement() {
|
|||||||
|
|
||||||
ImGui::SetCursorPosY(0.0f);
|
ImGui::SetCursorPosY(0.0f);
|
||||||
|
|
||||||
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
|
DrawRemoteControlMenu();
|
||||||
|
|
||||||
|
ImGui::SetCursorPosY(0.0f);
|
||||||
|
#endif
|
||||||
|
|
||||||
DrawRandomizerMenu();
|
DrawRandomizerMenu();
|
||||||
|
|
||||||
ImGui::PopStyleVar(1);
|
ImGui::PopStyleVar(1);
|
||||||
|
Loading…
Reference in New Issue
Block a user