mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-28 20:32:18 -05:00
Feature: Crowd Control Integration (#1568)
* Start effects * Disable input to game when typing in console * Add gravity support * noUI placeholder * Add rest of effects to console * Remove z_play code * Add rupee modification * Add OneHit KO (#27) * few fix and paper Link * Better method and now use the reset flag * Revert "Better method and now use the reset flag" This reverts commit2aafcc1df2
. * Revert "few fix and paper Link" This reverts commit65e76dcfee
. * Paper Link & few fixes (#28) * Implement pacifist mode (#30) * Implement cucco storm (#31) * Add no UI functionality (#32) * Enable CrowdControl on windows (#33) * Use std::format and implement wallmaster * Implement defense modifier * Implement no_z and clean up * Implement reverse controls * Some fixes while testing CC connection * Implement speed modifier and fix defese modifier * Fail magic effects if magic is not acquired * Fix queue system * Implement rainstorm * Some cleanup * Use IS_ZERO to handle very low near zero values * Split some effects * Fix emptying magic * Don’t run cucco on pre-rendered backgrounds * Use correct method for updating ruppees * Fix decreasing speed * Remove old SDL stuff * Remove old fixes * Enable Crowd Control for both debug and release * Add missing returns * Cleanup event firing * Further clean up on event firing * Fix some bugs * CC fixes and enemy spawning (#35) * Fix icetraps * Fix title screen * Fix pause screen * Fix death screen timer & Code cleanup * Fix timer during textboxes * Code cleanup * Add: Multiple enemy spawning * More enemies + more code cleanup (#36) * Enums for returning effect states * Add more enemies * Update CrowdControl.cpp * Remove enums from enemies * Fix up flow for events (#37) # Conflicts: # soh/soh/Enhancements/crowd-control/CrowdControl.cpp * Fix spawn position of likelike * CC temp enemy fixes (#38) * Check for pause in pacifist and allow button presses (#39) * Fix Pacifist mode (#41) * First attempt pacifier fix * Real fix for pacifist mode * Comment * Remove cutscene and long delay from cucco_storm (#40) * Some PR Fixes * Use standard types * Handle JSON parsing error and free memory * Add CC configuration file * Add: Giving deku shield option. Fix: Giant Lonk (#42) * Small stalfos fix (#43) * Syntax Improvements (#44) * Revert bools to uint32_t * Add comment about bools * Fix cucco storm, fix empty heart (#45) * Protect commands vector with mutex * prefix effects with chaosEffect (#46) Co-authored-by: briaguya <briaguya@alice> Co-authored-by: Baoulettes <perlouzerie@hotmail.fr> Co-authored-by: aMannus <mannusmenting@gmail.com> Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com> Co-authored-by: briaguya <briaguya@alice>
This commit is contained in:
parent
87125ae334
commit
083ceb4423
@ -22,7 +22,7 @@ set(VCPKG_TRIPLET x64-windows-static)
|
|||||||
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
||||||
|
|
||||||
vcpkg_bootstrap()
|
vcpkg_bootstrap()
|
||||||
vcpkg_install_packages(zlib bzip2 libpng SDL2 GLEW glfw3)
|
vcpkg_install_packages(zlib bzip2 libpng SDL2 SDL2-net GLEW glfw3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -243,6 +243,13 @@ set(Header_Files__soh__Enhancements__item_tables
|
|||||||
|
|
||||||
source_group("Header Files\\soh\\Enhancements\\item-tables" FILES ${Header_Files__soh__Enhancements__item_tables})
|
source_group("Header Files\\soh\\Enhancements\\item-tables" FILES ${Header_Files__soh__Enhancements__item_tables})
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
|
set(Header_Files__soh__Enhancements__crowd_control
|
||||||
|
"soh/Enhancements/crowd-control/CrowdControl.h"
|
||||||
|
)
|
||||||
|
source_group("Header Files\\soh\\Enhancements\\crowd-control" FILES ${Header_Files__soh__Enhancements__crowd_control})
|
||||||
|
endif()
|
||||||
|
|
||||||
set(Source_Files__soh
|
set(Source_Files__soh
|
||||||
"soh/GbiWrap.cpp"
|
"soh/GbiWrap.cpp"
|
||||||
"soh/OTRAudio.h"
|
"soh/OTRAudio.h"
|
||||||
@ -378,6 +385,13 @@ set(Source_Files__soh__Enhancements__item_tables
|
|||||||
|
|
||||||
source_group("Source Files\\soh\\Enhancements\\item-tables" FILES ${Source_Files__soh__Enhancements__item_tables})
|
source_group("Source Files\\soh\\Enhancements\\item-tables" FILES ${Source_Files__soh__Enhancements__item_tables})
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
|
set(Source_Files__soh__Enhancements__crowd_control
|
||||||
|
"soh/Enhancements/crowd-control/CrowdControl.cpp"
|
||||||
|
)
|
||||||
|
source_group("Source Files\\soh\\Enhancements\\crowd-control" FILES ${Source_Files__soh__Enhancements__crowd_control})
|
||||||
|
endif()
|
||||||
|
|
||||||
set(Source_Files__src__boot
|
set(Source_Files__src__boot
|
||||||
"src/boot/assert.c"
|
"src/boot/assert.c"
|
||||||
"src/boot/boot_main.c"
|
"src/boot/boot_main.c"
|
||||||
@ -1588,6 +1602,7 @@ set(ALL_FILES
|
|||||||
${Header_Files__soh__Enhancements__randomizer__3drando}
|
${Header_Files__soh__Enhancements__randomizer__3drando}
|
||||||
${Header_Files__soh__Enhancements__item_tables}
|
${Header_Files__soh__Enhancements__item_tables}
|
||||||
${Header_Files__soh__Enhancements__custom_message}
|
${Header_Files__soh__Enhancements__custom_message}
|
||||||
|
${Header_Files__soh__Enhancements__crowd_control}
|
||||||
${Source_Files__soh}
|
${Source_Files__soh}
|
||||||
${Source_Files__soh__Enhancements}
|
${Source_Files__soh__Enhancements}
|
||||||
${Source_Files__soh__Enhancements__controls}
|
${Source_Files__soh__Enhancements__controls}
|
||||||
@ -1599,6 +1614,7 @@ set(ALL_FILES
|
|||||||
${Source_Files__soh__Enhancements__randomizer__3drando__location_access}
|
${Source_Files__soh__Enhancements__randomizer__3drando__location_access}
|
||||||
${Source_Files__soh__Enhancements__item_tables}
|
${Source_Files__soh__Enhancements__item_tables}
|
||||||
${Source_Files__soh__Enhancements__custom_message}
|
${Source_Files__soh__Enhancements__custom_message}
|
||||||
|
${Source_Files__soh__Enhancements__crowd_control}
|
||||||
${Source_Files__src__boot}
|
${Source_Files__src__boot}
|
||||||
${Source_Files__src__buffers}
|
${Source_Files__src__buffers}
|
||||||
${Source_Files__src__code}
|
${Source_Files__src__code}
|
||||||
@ -1680,6 +1696,11 @@ endif()
|
|||||||
find_package(SDL2)
|
find_package(SDL2)
|
||||||
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
|
find_package(SDL2-net)
|
||||||
|
set(SDL2-NET-INCLUDE ${SDL_NET_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE assets
|
target_include_directories(${PROJECT_NAME} PRIVATE assets
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/
|
${CMAKE_CURRENT_SOURCE_DIR}/include/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/
|
${CMAKE_CURRENT_SOURCE_DIR}/src/
|
||||||
@ -1690,6 +1711,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/Fast3D/U64/PR
|
${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/Fast3D/U64/PR
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils
|
${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils
|
||||||
${SDL2-INCLUDE}
|
${SDL2-INCLUDE}
|
||||||
|
${SDL2-NET-INCLUDE}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/assets/
|
${CMAKE_CURRENT_SOURCE_DIR}/assets/
|
||||||
.
|
.
|
||||||
)
|
)
|
||||||
@ -1700,12 +1722,13 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
|||||||
"$<$<CONFIG:Debug>:"
|
"$<$<CONFIG:Debug>:"
|
||||||
"_DEBUG;"
|
"_DEBUG;"
|
||||||
"_CRT_SECURE_NO_WARNINGS;"
|
"_CRT_SECURE_NO_WARNINGS;"
|
||||||
"ENABLE_DX11"
|
"ENABLE_DX11;"
|
||||||
">"
|
">"
|
||||||
"$<$<CONFIG:Release>:"
|
"$<$<CONFIG:Release>:"
|
||||||
"NDEBUG"
|
"NDEBUG"
|
||||||
">"
|
">"
|
||||||
"INCLUDE_GAME_PRINTF;"
|
"INCLUDE_GAME_PRINTF;"
|
||||||
|
"ENABLE_CROWD_CONTROL;"
|
||||||
"UNICODE;"
|
"UNICODE;"
|
||||||
"_UNICODE"
|
"_UNICODE"
|
||||||
STORMLIB_NO_AUTO_LINK
|
STORMLIB_NO_AUTO_LINK
|
||||||
@ -1941,6 +1964,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
|||||||
"glu32;"
|
"glu32;"
|
||||||
"SDL2::SDL2;"
|
"SDL2::SDL2;"
|
||||||
"SDL2::SDL2main;"
|
"SDL2::SDL2main;"
|
||||||
|
"SDL2::SDL2_net;"
|
||||||
"glfw;"
|
"glfw;"
|
||||||
"winmm;"
|
"winmm;"
|
||||||
"imm32;"
|
"imm32;"
|
||||||
|
@ -1076,6 +1076,8 @@ void Interface_SetDoAction(GlobalContext* globalCtx, u16 action);
|
|||||||
void Interface_SetNaviCall(GlobalContext* globalCtx, u16 naviCallState);
|
void Interface_SetNaviCall(GlobalContext* globalCtx, u16 naviCallState);
|
||||||
void Interface_LoadActionLabelB(GlobalContext* globalCtx, u16 action);
|
void Interface_LoadActionLabelB(GlobalContext* globalCtx, u16 action);
|
||||||
s32 Health_ChangeBy(GlobalContext* globalCtx, s16 healthChange);
|
s32 Health_ChangeBy(GlobalContext* globalCtx, s16 healthChange);
|
||||||
|
void Health_GiveHearts(s16 hearts);
|
||||||
|
void Health_RemoveHearts(s16 hearts);
|
||||||
void Rupees_ChangeBy(s16 rupeeChange);
|
void Rupees_ChangeBy(s16 rupeeChange);
|
||||||
void Inventory_ChangeAmmo(s16 item, s16 ammoChange);
|
void Inventory_ChangeAmmo(s16 item, s16 ammoChange);
|
||||||
void Magic_Fill(GlobalContext* globalCtx);
|
void Magic_Fill(GlobalContext* globalCtx);
|
||||||
@ -1091,6 +1093,7 @@ f32 Path_OrientAndGetDistSq(Actor* actor, Path* path, s16 waypoint, s16* yaw);
|
|||||||
void Path_CopyLastPoint(Path* path, Vec3f* dest);
|
void Path_CopyLastPoint(Path* path, Vec3f* dest);
|
||||||
void FrameAdvance_Init(FrameAdvanceContext* frameAdvCtx);
|
void FrameAdvance_Init(FrameAdvanceContext* frameAdvCtx);
|
||||||
s32 FrameAdvance_Update(FrameAdvanceContext* frameAdvCtx, Input* input);
|
s32 FrameAdvance_Update(FrameAdvanceContext* frameAdvCtx, Input* input);
|
||||||
|
u8 PlayerGrounded(Player* player);
|
||||||
void Player_SetBootData(GlobalContext* globalCtx, Player* player);
|
void Player_SetBootData(GlobalContext* globalCtx, Player* player);
|
||||||
s32 Player_InBlockingCsMode(GlobalContext* globalCtx, Player* player);
|
s32 Player_InBlockingCsMode(GlobalContext* globalCtx, Player* player);
|
||||||
s32 Player_InCsMode(GlobalContext* globalCtx);
|
s32 Player_InCsMode(GlobalContext* globalCtx);
|
||||||
@ -1103,6 +1106,7 @@ void Player_SetModelGroup(Player* player, s32 modelGroup);
|
|||||||
void func_8008EC70(Player* player);
|
void func_8008EC70(Player* player);
|
||||||
void Player_SetEquipmentData(GlobalContext* globalCtx, Player* player);
|
void Player_SetEquipmentData(GlobalContext* globalCtx, Player* player);
|
||||||
void Player_UpdateBottleHeld(GlobalContext* globalCtx, Player* player, s32 item, s32 actionParam);
|
void Player_UpdateBottleHeld(GlobalContext* globalCtx, Player* player, s32 item, s32 actionParam);
|
||||||
|
void func_80837C0C(GlobalContext* globalCtx, Player* this, s32 arg2, f32 arg3, f32 arg4, s16 arg5, s32 arg6);
|
||||||
void func_8008EDF0(Player* player);
|
void func_8008EDF0(Player* player);
|
||||||
void func_8008EE08(Player* player);
|
void func_8008EE08(Player* player);
|
||||||
void func_8008EEAC(GlobalContext* globalCtx, Actor* actor);
|
void func_8008EEAC(GlobalContext* globalCtx, Actor* actor);
|
||||||
|
538
soh/soh/Enhancements/crowd-control/CrowdControl.cpp
Normal file
538
soh/soh/Enhancements/crowd-control/CrowdControl.cpp
Normal file
@ -0,0 +1,538 @@
|
|||||||
|
#ifdef ENABLE_CROWD_CONTROL
|
||||||
|
|
||||||
|
#include "CrowdControl.h"
|
||||||
|
#include <libultraship/Cvar.h>
|
||||||
|
#include <libultraship/Console.h>
|
||||||
|
#include <libultraship/ImGuiImpl.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <z64.h>
|
||||||
|
#include "variables.h"
|
||||||
|
#include "functions.h"
|
||||||
|
#include "macros.h"
|
||||||
|
extern GlobalContext* gGlobalCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "../debugconsole.h"
|
||||||
|
|
||||||
|
#define CMD_EXECUTE SohImGui::GetConsole()->Dispatch
|
||||||
|
|
||||||
|
void CrowdControl::InitCrowdControl() {
|
||||||
|
SDLNet_Init();
|
||||||
|
|
||||||
|
if (SDLNet_ResolveHost(&ip, "127.0.0.1", 43384) == -1) {
|
||||||
|
printf("SDLNet_ResolveHost: %s\n", SDLNet_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
ccThreadReceive = std::thread(&CrowdControl::ReceiveFromCrowdControl, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrowdControl::RunCrowdControl(CCPacket* packet) {
|
||||||
|
bool paused = false;
|
||||||
|
EffectResult lastResult = EffectResult::NotReady;
|
||||||
|
bool isTimed = packet->timeRemaining > 0;
|
||||||
|
|
||||||
|
while (connected) {
|
||||||
|
EffectResult effectResult = ExecuteEffect(packet->effectType.c_str(), packet->effectValue, 0);
|
||||||
|
if (effectResult == EffectResult::Success) {
|
||||||
|
// If we have a success after being previously paused, we fire the Resumed event
|
||||||
|
if (paused && packet->timeRemaining > 0) {
|
||||||
|
paused = false;
|
||||||
|
nlohmann::json dataSend;
|
||||||
|
dataSend["id"] = packet->packetId;
|
||||||
|
dataSend["type"] = 0;
|
||||||
|
dataSend["timeRemaining"] = packet->timeRemaining;
|
||||||
|
dataSend["status"] = EffectResult::Resumed;
|
||||||
|
|
||||||
|
std::string jsonResponse = dataSend.dump();
|
||||||
|
SDLNet_TCP_Send(tcpsock, jsonResponse.c_str(), jsonResponse.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If time remaining has reached 0 or was 0, we have finished let's remove the command and end the thread
|
||||||
|
if (packet->timeRemaining <= 0) {
|
||||||
|
receivedCommandsMutex.lock();
|
||||||
|
receivedCommands.erase(std::remove(receivedCommands.begin(), receivedCommands.end(), packet), receivedCommands.end());
|
||||||
|
receivedCommandsMutex.unlock();
|
||||||
|
RemoveEffect(packet->effectType.c_str());
|
||||||
|
|
||||||
|
// If not timed, let's fire the one and only success
|
||||||
|
if (!isTimed) {
|
||||||
|
nlohmann::json dataSend;
|
||||||
|
dataSend["id"] = packet->packetId;
|
||||||
|
dataSend["type"] = 0;
|
||||||
|
dataSend["timeRemaining"] = packet->timeRemaining;
|
||||||
|
dataSend["status"] = EffectResult::Success;
|
||||||
|
|
||||||
|
std::string jsonResponse = dataSend.dump();
|
||||||
|
SDLNet_TCP_Send(tcpsock, jsonResponse.c_str(), jsonResponse.size() + 1);
|
||||||
|
|
||||||
|
delete packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrement remaining time by the second that elapsed between thread runs
|
||||||
|
packet->timeRemaining -= 1000;
|
||||||
|
// We don't want to emit repeated events, so ensure we only emit changes in events
|
||||||
|
if (effectResult != lastResult) {
|
||||||
|
lastResult = effectResult;
|
||||||
|
|
||||||
|
nlohmann::json dataSend;
|
||||||
|
dataSend["id"] = packet->packetId;
|
||||||
|
dataSend["type"] = 0;
|
||||||
|
dataSend["timeRemaining"] = packet->timeRemaining;
|
||||||
|
dataSend["status"] = effectResult;
|
||||||
|
|
||||||
|
std::string jsonResponse = dataSend.dump();
|
||||||
|
SDLNet_TCP_Send(tcpsock, jsonResponse.c_str(), jsonResponse.size() + 1);
|
||||||
|
}
|
||||||
|
} else if (effectResult == EffectResult::Retry && paused == false && packet->timeRemaining > 0) {
|
||||||
|
paused = true;
|
||||||
|
nlohmann::json dataSend;
|
||||||
|
dataSend["id"] = packet->packetId;
|
||||||
|
dataSend["type"] = 0;
|
||||||
|
dataSend["timeRemaining"] = packet->timeRemaining;
|
||||||
|
dataSend["status"] = EffectResult::Paused;
|
||||||
|
|
||||||
|
std::string jsonResponse = dataSend.dump();
|
||||||
|
SDLNet_TCP_Send(tcpsock, jsonResponse.c_str(), jsonResponse.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrowdControl::ReceiveFromCrowdControl()
|
||||||
|
{
|
||||||
|
printf("Waiting for a connection from Crowd Control...");
|
||||||
|
|
||||||
|
while (!connected && CVar_GetS32("gCrowdControl", 0)) {
|
||||||
|
tcpsock = SDLNet_TCP_Open(&ip);
|
||||||
|
|
||||||
|
if (tcpsock) {
|
||||||
|
connected = true;
|
||||||
|
printf("Connected to Crowd Control!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (connected && CVar_GetS32("gCrowdControl", 0) && tcpsock) {
|
||||||
|
int len = SDLNet_TCP_Recv(tcpsock, &received, sizeof(received));
|
||||||
|
|
||||||
|
if (!len || !tcpsock || len == -1) {
|
||||||
|
printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
nlohmann::json dataReceived = nlohmann::json::parse(received);
|
||||||
|
|
||||||
|
CCPacket* packet = new CCPacket();
|
||||||
|
packet->packetId = dataReceived["id"];
|
||||||
|
auto parameters = dataReceived["parameters"];
|
||||||
|
if (parameters.size() > 0) {
|
||||||
|
packet->effectValue = dataReceived["parameters"][0];
|
||||||
|
}
|
||||||
|
packet->effectType = dataReceived["code"].get<std::string>();
|
||||||
|
|
||||||
|
if (packet->effectType == "high_gravity" ||
|
||||||
|
packet->effectType == "low_gravity") {
|
||||||
|
packet->effectCategory = "gravity";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "damage_multiplier"
|
||||||
|
|| packet->effectType == "defense_multiplier"
|
||||||
|
) {
|
||||||
|
packet->effectCategory = "defense";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "giant_link" ||
|
||||||
|
packet->effectType == "minish_link" ||
|
||||||
|
packet->effectType == "invisible" ||
|
||||||
|
packet->effectType == "paper_link") {
|
||||||
|
packet->effectCategory = "link_size";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "freeze" ||
|
||||||
|
packet->effectType == "damage" ||
|
||||||
|
packet->effectType == "heal" ||
|
||||||
|
packet->effectType == "knockback" ||
|
||||||
|
packet->effectType == "electrocute" ||
|
||||||
|
packet->effectType == "burn" ||
|
||||||
|
packet->effectType == "kill") {
|
||||||
|
packet->effectCategory = "link_damage";
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "hover_boots" ||
|
||||||
|
packet->effectType == "iron_boots") {
|
||||||
|
packet->effectCategory = "boots";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "add_heart_container" ||
|
||||||
|
packet->effectType == "remove_heart_container") {
|
||||||
|
packet->effectCategory = "heart_container";
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "no_ui") {
|
||||||
|
packet->effectCategory = "ui";
|
||||||
|
packet->timeRemaining = 60000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "fill_magic" ||
|
||||||
|
packet->effectType == "empty_magic") {
|
||||||
|
packet->effectCategory = "magic";
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "ohko") {
|
||||||
|
packet->effectCategory = "ohko";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "pacifist") {
|
||||||
|
packet->effectCategory = "pacifist";
|
||||||
|
packet->timeRemaining = 15000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "rainstorm") {
|
||||||
|
packet->effectCategory = "weather";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "reverse") {
|
||||||
|
packet->effectCategory = "controls";
|
||||||
|
packet->timeRemaining = 60000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "add_rupees"
|
||||||
|
|| packet->effectType == "remove_rupees"
|
||||||
|
) {
|
||||||
|
packet->effectCategory = "rupees";
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "increase_speed"
|
||||||
|
|| packet->effectType == "decrease_speed"
|
||||||
|
) {
|
||||||
|
packet->effectCategory = "speed";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "no_z") {
|
||||||
|
packet->effectCategory = "no_z";
|
||||||
|
packet->timeRemaining = 30000;
|
||||||
|
}
|
||||||
|
else if (packet->effectType == "spawn_wallmaster" ||
|
||||||
|
packet->effectType == "spawn_arwing" ||
|
||||||
|
packet->effectType == "spawn_darklink" ||
|
||||||
|
packet->effectType == "spawn_stalfos" ||
|
||||||
|
packet->effectType == "spawn_wolfos" ||
|
||||||
|
packet->effectType == "spawn_freezard" ||
|
||||||
|
packet->effectType == "spawn_keese" ||
|
||||||
|
packet->effectType == "spawn_icekeese" ||
|
||||||
|
packet->effectType == "spawn_firekeese" ||
|
||||||
|
packet->effectType == "spawn_tektite" ||
|
||||||
|
packet->effectType == "spawn_likelike" ||
|
||||||
|
packet->effectType == "cucco_storm") {
|
||||||
|
packet->effectCategory = "spawn";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
packet->effectCategory = "none";
|
||||||
|
packet->timeRemaining = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if running effect is possible
|
||||||
|
EffectResult effectResult = ExecuteEffect(packet->effectType.c_str(), packet->effectValue, 1);
|
||||||
|
if (effectResult == EffectResult::Retry || effectResult == EffectResult::Failure) {
|
||||||
|
nlohmann::json dataSend;
|
||||||
|
dataSend["id"] = packet->packetId;
|
||||||
|
dataSend["type"] = 0;
|
||||||
|
dataSend["timeRemaining"] = packet->timeRemaining;
|
||||||
|
dataSend["status"] = effectResult;
|
||||||
|
|
||||||
|
std::string jsonResponse = dataSend.dump();
|
||||||
|
SDLNet_TCP_Send(tcpsock, jsonResponse.c_str(), jsonResponse.size() + 1);
|
||||||
|
} else {
|
||||||
|
bool anotherEffectOfCategoryActive = false;
|
||||||
|
for (CCPacket* pack : receivedCommands) {
|
||||||
|
if (pack != packet && pack->effectCategory == packet->effectCategory && pack->packetId < packet->packetId) {
|
||||||
|
anotherEffectOfCategoryActive = true;
|
||||||
|
|
||||||
|
nlohmann::json dataSend;
|
||||||
|
dataSend["id"] = packet->packetId;
|
||||||
|
dataSend["type"] = 0;
|
||||||
|
dataSend["timeRemaining"] = packet->timeRemaining;
|
||||||
|
dataSend["status"] = EffectResult::Retry;
|
||||||
|
|
||||||
|
std::string jsonResponse = dataSend.dump();
|
||||||
|
SDLNet_TCP_Send(tcpsock, jsonResponse.c_str(), jsonResponse.size() + 1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anotherEffectOfCategoryActive != true) {
|
||||||
|
receivedCommandsMutex.lock();
|
||||||
|
receivedCommands.push_back(packet);
|
||||||
|
receivedCommandsMutex.unlock();
|
||||||
|
std::thread t = std::thread(&CrowdControl::RunCrowdControl, this, packet);
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (nlohmann::json::parse_error& e) {
|
||||||
|
printf("Error parsing JSON: %s\n", e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
SDLNet_TCP_Close(tcpsock);
|
||||||
|
SDLNet_Quit();
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CrowdControl::EffectResult CrowdControl::ExecuteEffect(std::string effectId, uint32_t value, bool dryRun) {
|
||||||
|
// Don't execute effect and don't advance timer when the player is not in a proper loaded savefile
|
||||||
|
// and when they're busy dying.
|
||||||
|
if (gGlobalCtx == NULL || gGlobalCtx->gameOverCtx.state > 0 || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2) {
|
||||||
|
return EffectResult::Retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
|
||||||
|
if (player != NULL) {
|
||||||
|
if (effectId == "add_heart_container") {
|
||||||
|
if (gSaveContext.healthCapacity >= 0x140) {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("add_heart_container");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "remove_heart_container") {
|
||||||
|
if ((gSaveContext.healthCapacity - 0x10) <= 0) {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("remove_heart_container");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "fill_magic") {
|
||||||
|
if (!gSaveContext.magicAcquired) {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gSaveContext.magic >= (gSaveContext.doubleMagic + 1) + 0x30) {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("fill_magic");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "empty_magic") {
|
||||||
|
if (!gSaveContext.magicAcquired || gSaveContext.magic <= 0) {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("empty_magic");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "add_rupees") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("update_rupees {}", value));
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "remove_rupees") {
|
||||||
|
if (gSaveContext.rupees - value < 0) {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("update_rupees -{}", value));
|
||||||
|
return EffectResult::Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player != NULL && !Player_InBlockingCsMode(gGlobalCtx, player) && gGlobalCtx->pauseCtx.state == 0
|
||||||
|
&& gGlobalCtx->msgCtx.msgMode == 0) {
|
||||||
|
if (effectId == "high_gravity") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("gravity 2");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "low_gravity") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("gravity 0");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "kill"
|
||||||
|
|| effectId == "freeze"
|
||||||
|
|| effectId == "burn"
|
||||||
|
|| effectId == "electrocute"
|
||||||
|
|| effectId == "cucco_storm"
|
||||||
|
) {
|
||||||
|
if (PlayerGrounded(player)) {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("{}", effectId));
|
||||||
|
return EffectResult::Success;
|
||||||
|
}
|
||||||
|
return EffectResult::Failure;
|
||||||
|
} else if (effectId == "heal"
|
||||||
|
|| effectId == "knockback"
|
||||||
|
) {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("{} {}", effectId, value));
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "giant_link"
|
||||||
|
|| effectId == "minish_link"
|
||||||
|
|| effectId == "no_ui"
|
||||||
|
|| effectId == "invisible"
|
||||||
|
|| effectId == "paper_link"
|
||||||
|
|| effectId == "no_z"
|
||||||
|
|| effectId == "ohko"
|
||||||
|
|| effectId == "pacifist"
|
||||||
|
|| effectId == "rainstorm"
|
||||||
|
) {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("{} 1", effectId));
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "reverse") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("reverse_controls 1");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "iron_boots") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("boots iron");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "hover_boots") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("boots hover");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "give_dekushield") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("givedekushield");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "spawn_wallmaster"
|
||||||
|
|| effectId == "spawn_arwing"
|
||||||
|
|| effectId == "spawn_darklink"
|
||||||
|
|| effectId == "spawn_stalfos"
|
||||||
|
|| effectId == "spawn_wolfos"
|
||||||
|
|| effectId == "spawn_freezard"
|
||||||
|
|| effectId == "spawn_keese"
|
||||||
|
|| effectId == "spawn_icekeese"
|
||||||
|
|| effectId == "spawn_firekeese"
|
||||||
|
|| effectId == "spawn_tektite"
|
||||||
|
|| effectId == "spawn_likelike"
|
||||||
|
) {
|
||||||
|
if (dryRun == 0) {
|
||||||
|
if (CrowdControl::SpawnEnemy(effectId)) {
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "increase_speed") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("speed_modifier 2");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "decrease_speed") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE("speed_modifier -2");
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "damage_multiplier") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("defense_modifier -{}", value));
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "defense_multiplier") {
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("defense_modifier {}", value));
|
||||||
|
return EffectResult::Success;
|
||||||
|
} else if (effectId == "damage") {
|
||||||
|
if ((gSaveContext.healthCapacity - 0x10) <= 0) {
|
||||||
|
return EffectResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryRun == 0) CMD_EXECUTE(std::format("{} {}", effectId, value));
|
||||||
|
return EffectResult::Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EffectResult::Retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CrowdControl::SpawnEnemy(std::string effectId) {
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
|
||||||
|
int enemyId = 0;
|
||||||
|
int enemyParams = 0;
|
||||||
|
float posXOffset = 0;
|
||||||
|
float posYOffset = 0;
|
||||||
|
float posZOffset = 0;
|
||||||
|
|
||||||
|
if (effectId == "spawn_wallmaster") {
|
||||||
|
enemyId = 17;
|
||||||
|
} else if (effectId == "spawn_arwing") {
|
||||||
|
enemyId = 315;
|
||||||
|
enemyParams = 1;
|
||||||
|
posYOffset = 100;
|
||||||
|
} else if (effectId == "spawn_darklink") {
|
||||||
|
enemyId = 51;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_stalfos") {
|
||||||
|
enemyId = 2;
|
||||||
|
enemyParams = 2;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_wolfos") {
|
||||||
|
enemyId = 431;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_freezard") {
|
||||||
|
enemyId = 289;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_keese") {
|
||||||
|
enemyId = 19;
|
||||||
|
enemyParams = 2;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_icekeese") {
|
||||||
|
enemyId = 19;
|
||||||
|
enemyParams = 4;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_firekeese") {
|
||||||
|
enemyId = 19;
|
||||||
|
enemyParams = 1;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_tektite") {
|
||||||
|
enemyId = 27;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
} else if (effectId == "spawn_likelike") {
|
||||||
|
enemyId = 221;
|
||||||
|
posXOffset = 75;
|
||||||
|
posYOffset = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, enemyId, player->actor.world.pos.x + posXOffset,
|
||||||
|
player->actor.world.pos.y + posYOffset, player->actor.world.pos.z + posZOffset, 0, 0, 0, enemyParams);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrowdControl::RemoveEffect(std::string effectId) {
|
||||||
|
if (gGlobalCtx == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
|
||||||
|
if (player != NULL) {
|
||||||
|
if (effectId == "giant_link"
|
||||||
|
|| effectId == "minish_link"
|
||||||
|
|| effectId == "no_ui"
|
||||||
|
|| effectId == "invisible"
|
||||||
|
|| effectId == "paper_link"
|
||||||
|
|| effectId == "no_z"
|
||||||
|
|| effectId == "ohko"
|
||||||
|
|| effectId == "pacifist"
|
||||||
|
|| effectId == "rainstorm"
|
||||||
|
) {
|
||||||
|
CMD_EXECUTE(std::format("{} 0", effectId));
|
||||||
|
return;
|
||||||
|
} else if (effectId == "iron_boots" || effectId == "hover_boots") {
|
||||||
|
CMD_EXECUTE("boots kokiri");
|
||||||
|
return;
|
||||||
|
} else if (effectId == "high_gravity" || effectId == "low_gravity") {
|
||||||
|
CMD_EXECUTE("gravity 1");
|
||||||
|
return;
|
||||||
|
} else if (effectId == "reverse") {
|
||||||
|
CMD_EXECUTE("reverse_controls 0");
|
||||||
|
return;
|
||||||
|
} else if (effectId == "increase_speed"
|
||||||
|
|| effectId == "decrease_speed"
|
||||||
|
) {
|
||||||
|
CMD_EXECUTE("speed_modifier 0");
|
||||||
|
return;
|
||||||
|
} else if (effectId == "damage_multiplier"
|
||||||
|
|| effectId == "defense_multiplier"
|
||||||
|
) {
|
||||||
|
CMD_EXECUTE("defense_modifier 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
91
soh/soh/Enhancements/crowd-control/CrowdControl.h
Normal file
91
soh/soh/Enhancements/crowd-control/CrowdControl.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#ifdef ENABLE_CROWD_CONTROL
|
||||||
|
|
||||||
|
#ifndef _CROWDCONTROL_C
|
||||||
|
#define _CROWDCONTROL_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <SDL2/SDL_net.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <thread>
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
class CrowdControl {
|
||||||
|
private:
|
||||||
|
typedef struct CCPacket {
|
||||||
|
uint32_t packetId;
|
||||||
|
std::string effectType;
|
||||||
|
uint32_t effectValue;
|
||||||
|
std::string effectCategory;
|
||||||
|
long timeRemaining;
|
||||||
|
} CCPacket;
|
||||||
|
|
||||||
|
enum EffectResult {
|
||||||
|
/// <summary>The effect executed successfully.</summary>
|
||||||
|
Success = 0x00,
|
||||||
|
/// <summary>The effect failed to trigger, but is still available for use. Viewer(s) will be refunded. You probably don't want this.</summary>
|
||||||
|
Failure = 0x01,
|
||||||
|
/// <summary>Same as <see cref="Failure"/> but the effect is no longer available for use for the remainder of the game. You probably don't want this.</summary>
|
||||||
|
Unavailable = 0x02,
|
||||||
|
/// <summary>The effect cannot be triggered right now, try again in a few seconds. This is the "normal" failure response.</summary>
|
||||||
|
Retry = 0x03,
|
||||||
|
/// <summary>INTERNAL USE ONLY. The effect has been queued for execution after the current one ends.</summary>
|
||||||
|
Queue = 0x04,
|
||||||
|
/// <summary>INTERNAL USE ONLY. The effect triggered successfully and is now active until it ends.</summary>
|
||||||
|
Running = 0x05,
|
||||||
|
/// <summary>The timed effect has been paused and is now waiting.</summary>
|
||||||
|
Paused = 0x06,
|
||||||
|
/// <summary>The timed effect has been resumed and is counting down again.</summary>
|
||||||
|
Resumed = 0x07,
|
||||||
|
/// <summary>The timed effect has finished.</summary>
|
||||||
|
Finished = 0x08,
|
||||||
|
/// <summary>The processor isn't ready to start or has shut down.</summary>
|
||||||
|
NotReady = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ResponseType {
|
||||||
|
EffectRequest = 0x00,
|
||||||
|
Login = 0xF0,
|
||||||
|
LoginSuccess = 0xF1,
|
||||||
|
Disconnect = 0xFE,
|
||||||
|
KeepAlive = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Response {
|
||||||
|
int id;
|
||||||
|
EffectResult status;
|
||||||
|
long timeRemaining;
|
||||||
|
ResponseType type = ResponseType::EffectRequest;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread ccThreadReceive;
|
||||||
|
|
||||||
|
TCPsocket tcpsock;
|
||||||
|
IPaddress ip;
|
||||||
|
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
char received[512];
|
||||||
|
|
||||||
|
std::vector<CCPacket*> receivedCommands;
|
||||||
|
std::mutex receivedCommandsMutex;
|
||||||
|
|
||||||
|
void RunCrowdControl(CCPacket* packet);
|
||||||
|
void ReceiveFromCrowdControl();
|
||||||
|
EffectResult ExecuteEffect(std::string effectId, uint32_t value, bool dryRun);
|
||||||
|
bool SpawnEnemy(std::string effectId);
|
||||||
|
void RemoveEffect(std::string effectId);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static CrowdControl* Instance;
|
||||||
|
void InitCrowdControl();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
90
soh/soh/Enhancements/crowd-control/soh.cs
Normal file
90
soh/soh/Enhancements/crowd-control/soh.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using CrowdControl.Common;
|
||||||
|
using CrowdControl.Games.Packs;
|
||||||
|
using ConnectorType = CrowdControl.Common.ConnectorType;
|
||||||
|
|
||||||
|
public class SoH : SimpleTCPPack
|
||||||
|
{
|
||||||
|
public override string Host { get; } = "127.0.0.1";
|
||||||
|
|
||||||
|
public override ushort Port { get; } = 43384;
|
||||||
|
|
||||||
|
public SoH(IPlayer player, Func<CrowdControlBlock, bool> responseHandler, Action<object> statusUpdateHandler) : base(player, responseHandler, statusUpdateHandler) { }
|
||||||
|
|
||||||
|
public override Game Game { get; } = new Game(90, "Ship of Harkinian", "SoH", "PC", ConnectorType.SimpleTCPConnector);
|
||||||
|
|
||||||
|
private Dictionary<string, string> _enemyType = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{"wallmaster", ("Wallmaster")},
|
||||||
|
{"arwing", ("Arwing")},
|
||||||
|
{"darklink", ("Dark Link")},
|
||||||
|
{"stalfos", ("Stalfos")},
|
||||||
|
{"wolfos", ("Wolfos")},
|
||||||
|
{"freezard", ("Freezard")},
|
||||||
|
{"keese", ("Keese")},
|
||||||
|
{"icekeese", ("Ice Keese")},
|
||||||
|
{"firekeese", ("Fire Keese")},
|
||||||
|
{"tektite", ("Tektite")},
|
||||||
|
{"likelike", ("Like-Like")}
|
||||||
|
};
|
||||||
|
|
||||||
|
public override List<Effect> Effects
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
List<Effect> effects = new List<Effect>
|
||||||
|
{
|
||||||
|
new Effect("Add Heart Container", "add_heart_container"),
|
||||||
|
new Effect("Remove Heart Container", "remove_heart_container"),
|
||||||
|
new Effect("Damage Multiplier", "damage_multiplier", new[] { "damdefmulti" }) { Duration = 30 },
|
||||||
|
new Effect("Defense Multiplier", "defense_multiplier", new[] { "damdefmulti" }) { Duration = 30 },
|
||||||
|
new Effect("Freeze Link", "freeze"),
|
||||||
|
new Effect("Giant Lonk", "giant_link") { Duration = 30 },
|
||||||
|
new Effect("Empty Heart", "damage", new[] { "health20" }),
|
||||||
|
new Effect("Fill Heart", "heal", new[] { "health20" }),
|
||||||
|
new Effect("Kill Player", "kill"),
|
||||||
|
new Effect("High Gravity", "high_gravity") { Duration = 30 },
|
||||||
|
new Effect("Hover Boots", "hover_boots") { Duration = 30 },
|
||||||
|
new Effect("Invisible Link", "invisible") { Duration = 30 },
|
||||||
|
new Effect("No UI", "no_ui") { Duration = 60 },
|
||||||
|
new Effect("Low Gravity", "low_gravity") { Duration = 30 },
|
||||||
|
new Effect("Fill Magic", "fill_magic"),
|
||||||
|
new Effect("Empty Magic", "empty_magic"),
|
||||||
|
new Effect("Minish Link", "minish_link") { Duration = 30 },
|
||||||
|
new Effect("No Z Button", "no_z") { Duration = 30 },
|
||||||
|
new Effect("One-Hit KO", "ohko") { Duration = 30 },
|
||||||
|
new Effect("Pacifist", "pacifist") { Duration = 15 },
|
||||||
|
new Effect("Paper Link", "paper_link") { Duration = 30 },
|
||||||
|
new Effect("Rainstorm", "rainstorm") { Duration = 30 },
|
||||||
|
new Effect("Reverse Controls", "reverse") { Duration = 60 },
|
||||||
|
new Effect("Give Rupees", "add_rupees", new[] { "rupees999" }),
|
||||||
|
new Effect("Take Rupees", "remove_rupees", new[] { "rupees999" }),
|
||||||
|
new Effect("Increase Speed", "increase_speed") { Duration = 30 },
|
||||||
|
new Effect("Decrease Speed", "decrease_speed") { Duration = 30 },
|
||||||
|
new Effect("Cucco Swarm", "cucco_storm"),
|
||||||
|
new Effect("Knockback Link", "knockback", new[] { "knockbackstrength" }),
|
||||||
|
new Effect("Burn Link", "burn"),
|
||||||
|
new Effect("Electrocute Link", "electrocute"),
|
||||||
|
new Effect("Iron Boots", "iron_boots") { Duration = 30 },
|
||||||
|
new Effect("Give Deku Shield", "give_dekushield"),
|
||||||
|
new Effect("Spawn Enemy", "spawn_enemy", ItemKind.Folder),
|
||||||
|
};
|
||||||
|
|
||||||
|
effects.AddRange(_enemyType.Select(t => new Effect($"Spawn {t.Value}", $"spawn_{t.Key}", "spawn_enemy")));
|
||||||
|
|
||||||
|
return effects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Slider ranges need to be defined
|
||||||
|
public override List<ItemType> ItemTypes => new List<ItemType>
|
||||||
|
{
|
||||||
|
new ItemType("Rupees", "rupees999", ItemType.Subtype.Slider, "{\"min\":1,\"max\":999}"),
|
||||||
|
new ItemType("Health", "health20", ItemType.Subtype.Slider, "{\"min\":1,\"max\":20}"),
|
||||||
|
new ItemType("Damage/Defense Multiplier", "damdefmulti", ItemType.Subtype.Slider, "{\"min\":1,\"max\":10}"),
|
||||||
|
new ItemType("Knockback Strength", "knockbackstrength", ItemType.Subtype.Slider, "{\"min\":1,\"max\":3}")
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include "debugconsole.h"
|
#include "debugconsole.h"
|
||||||
#include <libultraship/ImGuiImpl.h>
|
#include <libultraship/ImGuiImpl.h>
|
||||||
|
#include <libultraship/Utils.h>
|
||||||
#include "savestates.h"
|
#include "savestates.h"
|
||||||
#include <libultraship/Console.h>
|
#include <libultraship/Console.h>
|
||||||
|
|
||||||
@ -26,9 +27,24 @@ extern GlobalContext* gGlobalCtx;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include <libultraship/Cvar.h>
|
#include <libultraship/Cvar.h>
|
||||||
|
#include "overlays/actors/ovl_En_Niw/z_en_niw.h"
|
||||||
|
|
||||||
#define CMD_REGISTER SohImGui::GetConsole()->AddCommand
|
#define CMD_REGISTER SohImGui::GetConsole()->AddCommand
|
||||||
|
|
||||||
|
uint32_t chaosEffectNoUI;
|
||||||
|
uint32_t chaosEffectGiantLink;
|
||||||
|
uint32_t chaosEffectMinishLink;
|
||||||
|
uint32_t chaosEffectPaperLink;
|
||||||
|
uint32_t chaosEffectResetLinkScale;
|
||||||
|
uint32_t chaosEffectInvisibleLink;
|
||||||
|
uint32_t chaosEffectOneHitKO;
|
||||||
|
uint32_t chaosEffectPacifistMode;
|
||||||
|
int32_t chaosEffectDefenseModifier;
|
||||||
|
uint32_t chaosEffectNoZ;
|
||||||
|
uint32_t chaosEffectReverseControls;
|
||||||
|
uint32_t chaosEffectGravityLevel = GRAVITY_LEVEL_NORMAL;
|
||||||
|
int32_t chaosEffectSpeedModifier;
|
||||||
|
|
||||||
static bool ActorSpawnHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
static bool ActorSpawnHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
if ((args.size() != 9) && (args.size() != 3) && (args.size() != 6)) {
|
if ((args.size() != 9) && (args.size() != 3) && (args.size() != 6)) {
|
||||||
SohImGui::GetConsole()->SendErrorMessage("Not enough arguments passed to actorspawn");
|
SohImGui::GetConsole()->SendErrorMessage("Not enough arguments passed to actorspawn");
|
||||||
@ -58,7 +74,7 @@ static bool ActorSpawnHandler(std::shared_ptr<Ship::Console> Console, const std:
|
|||||||
if (args[8][0] != ',') {
|
if (args[8][0] != ',') {
|
||||||
spawnPoint.rot.z = std::stoi(args[8]);
|
spawnPoint.rot.z = std::stoi(args[8]);
|
||||||
}
|
}
|
||||||
case 5:
|
case 6:
|
||||||
if (args[3][0] != ',') {
|
if (args[3][0] != ',') {
|
||||||
spawnPoint.pos.x = std::stoi(args[3]);
|
spawnPoint.pos.x = std::stoi(args[3]);
|
||||||
}
|
}
|
||||||
@ -78,6 +94,17 @@ static bool ActorSpawnHandler(std::shared_ptr<Ship::Console> Console, const std:
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool GiveDekuShieldHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>&) {
|
||||||
|
// Give Deku Shield to the player, and automatically equip it when they're child and have no shield currently equiped.
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
Item_Give(gGlobalCtx, ITEM_SHIELD_DEKU);
|
||||||
|
if (LINK_IS_CHILD && player->currentShield == PLAYER_SHIELD_NONE) {
|
||||||
|
player->currentShield = PLAYER_SHIELD_DEKU;
|
||||||
|
Inventory_ChangeEquipment(EQUIP_SHIELD, PLAYER_SHIELD_DEKU);
|
||||||
|
}
|
||||||
|
SohImGui::GetConsole()->SendInfoMessage("[SOH] Gave Deku Shield");
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static bool KillPlayerHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>&) {
|
static bool KillPlayerHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>&) {
|
||||||
gSaveContext.health = 0;
|
gSaveContext.health = 0;
|
||||||
@ -111,7 +138,6 @@ static bool SetPlayerHealthHandler(std::shared_ptr<Ship::Console> Console, const
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool LoadSceneHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>&) {
|
static bool LoadSceneHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>&) {
|
||||||
gSaveContext.respawnFlag = 0;
|
gSaveContext.respawnFlag = 0;
|
||||||
gSaveContext.seqId = 0xFF;
|
gSaveContext.seqId = 0xFF;
|
||||||
@ -120,9 +146,10 @@ static bool LoadSceneHandler(std::shared_ptr<Ship::Console> Console, const std::
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool RuppeHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
static bool RupeeHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
if (args.size() < 2)
|
if (args.size() < 2) {
|
||||||
return CMD_FAILED;
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
int rupeeAmount;
|
int rupeeAmount;
|
||||||
try {
|
try {
|
||||||
@ -432,6 +459,431 @@ static bool StateSlotSelectHandler(std::shared_ptr<Ship::Console> Console, const
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool InvisibleHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectInvisibleLink = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
if (!chaosEffectInvisibleLink) {
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
player->actor.shape.shadowDraw = ActorShadow_DrawFeet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Invisible value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool GiantLinkHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectGiantLink = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
if (chaosEffectGiantLink) {
|
||||||
|
chaosEffectPaperLink = 0;
|
||||||
|
chaosEffectMinishLink = 0;
|
||||||
|
} else {
|
||||||
|
chaosEffectResetLinkScale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Giant value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool MinishLinkHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectMinishLink = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
if (chaosEffectMinishLink) {
|
||||||
|
chaosEffectPaperLink = 0;
|
||||||
|
chaosEffectGiantLink = 0;
|
||||||
|
} else {
|
||||||
|
chaosEffectResetLinkScale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Minish value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool AddHeartContainerHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (gSaveContext.healthCapacity >= 0x140)
|
||||||
|
return CMD_FAILED;
|
||||||
|
|
||||||
|
Health_GiveHearts(1);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool RemoveHeartContainerHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if ((gSaveContext.healthCapacity - 0x10) < 3)
|
||||||
|
return CMD_FAILED;
|
||||||
|
|
||||||
|
Health_RemoveHearts(1);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool GravityHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectGravityLevel = Ship::Math::clamp(std::stoi(args[1], nullptr, 10), GRAVITY_LEVEL_LIGHT, GRAVITY_LEVEL_HEAVY);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Minish value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NoUIHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectNoUI = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] No UI value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FreezeHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
gSaveContext.pendingIceTrapCount++;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DefenseModifierHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectDefenseModifier = std::stoi(args[1], nullptr, 10);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Defense modifier value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DamageHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int value = std::stoi(args[1], nullptr, 10);
|
||||||
|
if (value < 0) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Invalid value passed. Value must be greater than 0");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
|
||||||
|
Health_ChangeBy(gGlobalCtx, -value * 0x10);
|
||||||
|
func_80837C0C(gGlobalCtx, player, 0, 0, 0, 0, 0);
|
||||||
|
player->invincibilityTimer = 28;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Damage value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HealHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int value = std::stoi(args[1], nullptr, 10);
|
||||||
|
if (value < 0) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Invalid value passed. Value must be greater than 0");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Health_ChangeBy(gGlobalCtx, value * 0x10);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Heal value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FillMagicHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
Magic_Fill(gGlobalCtx);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool EmptyMagicHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
gSaveContext.magic = 0;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NoZHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectNoZ = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] NoZ value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool OneHitKOHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectOneHitKO = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] One-hit KO value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool PacifistHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectPacifistMode = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
// Force interface to update to make the buttons transparent
|
||||||
|
gSaveContext.unk_13E8 = 50;
|
||||||
|
Interface_Update(gGlobalCtx);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Pacifist value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool PaperLinkHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectPaperLink = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
if (chaosEffectPaperLink) {
|
||||||
|
chaosEffectMinishLink = 0;
|
||||||
|
chaosEffectGiantLink = 0;
|
||||||
|
} else {
|
||||||
|
chaosEffectResetLinkScale = 1;
|
||||||
|
}
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Paper Link value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool RainstormHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uint32_t rainstorm = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
if (rainstorm) {
|
||||||
|
gGlobalCtx->envCtx.unk_F2[0] = 20; // rain intensity target
|
||||||
|
gGlobalCtx->envCtx.gloomySkyMode = 1; // start gloomy sky
|
||||||
|
if ((gWeatherMode != 0) || gGlobalCtx->envCtx.unk_17 != 0) {
|
||||||
|
gGlobalCtx->envCtx.unk_DE = 1;
|
||||||
|
}
|
||||||
|
gGlobalCtx->envCtx.lightningMode = LIGHTNING_MODE_ON;
|
||||||
|
Environment_PlayStormNatureAmbience(gGlobalCtx);
|
||||||
|
} else {
|
||||||
|
gGlobalCtx->envCtx.unk_F2[0] = 0;
|
||||||
|
if (gGlobalCtx->csCtx.state == CS_STATE_IDLE) {
|
||||||
|
Environment_StopStormNatureAmbience(gGlobalCtx);
|
||||||
|
} else if (func_800FA0B4(SEQ_PLAYER_BGM_MAIN) == NA_BGM_NATURE_AMBIENCE) {
|
||||||
|
Audio_SetNatureAmbienceChannelIO(NATURE_CHANNEL_LIGHTNING, CHANNEL_IO_PORT_1, 0);
|
||||||
|
Audio_SetNatureAmbienceChannelIO(NATURE_CHANNEL_RAIN, CHANNEL_IO_PORT_1, 0);
|
||||||
|
}
|
||||||
|
osSyncPrintf("\n\n\nE_wether_flg=[%d]", gWeatherMode);
|
||||||
|
osSyncPrintf("\nrain_evt_trg=[%d]\n\n", gGlobalCtx->envCtx.gloomySkyMode);
|
||||||
|
if (gWeatherMode == 0 && (gGlobalCtx->envCtx.gloomySkyMode == 1)) {
|
||||||
|
gGlobalCtx->envCtx.gloomySkyMode = 2; // end gloomy sky
|
||||||
|
} else {
|
||||||
|
gGlobalCtx->envCtx.gloomySkyMode = 0;
|
||||||
|
gGlobalCtx->envCtx.unk_DE = 0;
|
||||||
|
}
|
||||||
|
gGlobalCtx->envCtx.lightningMode = LIGHTNING_MODE_LAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] rainstorm value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReverseControlsHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectReverseControls = std::stoi(args[1], nullptr, 10) == 0 ? 0 : 1;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Reverse controls value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool UpdateRupeesHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int value = std::stoi(args[1], nullptr, 10);
|
||||||
|
Rupees_ChangeBy(value);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Rupee value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SpeedModifierHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaosEffectSpeedModifier = std::stoi(args[1], nullptr, 10);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Speed modifier value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const static std::map<std::string, uint16_t> boots {
|
||||||
|
{ "kokiri", PLAYER_BOOTS_KOKIRI },
|
||||||
|
{ "iron", PLAYER_BOOTS_IRON },
|
||||||
|
{ "hover", PLAYER_BOOTS_HOVER },
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool BootsHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& it = boots.find(args[1]);
|
||||||
|
if (it == boots.end()) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("Invalid boot type. Options are 'kokiri', 'iron' and 'hover'");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
player->currentBoots = it->second;
|
||||||
|
Inventory_ChangeEquipment(EQUIP_BOOTS, it->second + 1);
|
||||||
|
Player_SetBootData(gGlobalCtx, player);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool KnockbackHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
if (args.size() != 2) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int value = std::stoi(args[1], nullptr, 10);
|
||||||
|
if (value < 0) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Invalid value passed. Value must be greater than 0");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
func_8002F71C(gGlobalCtx, &player->actor, value * 5, player->actor.world.rot.y + 0x8000, value * 5);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
} catch (std::invalid_argument const& ex) {
|
||||||
|
SohImGui::GetConsole()->SendErrorMessage("[SOH] Knockback value must be a number.");
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ElectrocuteHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
if (PlayerGrounded(player)) {
|
||||||
|
func_80837C0C(gGlobalCtx, player, 4, 0, 0, 0, 0);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool BurnHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
if (PlayerGrounded(player)) {
|
||||||
|
for (int i = 0; i < 18; i++) {
|
||||||
|
player->flameTimers[i] = Rand_S16Offset(0, 200);
|
||||||
|
}
|
||||||
|
player->isBurning = true;
|
||||||
|
func_80837C0C(gGlobalCtx, player, 0, 0, 0, 0, 0);
|
||||||
|
return CMD_FAILED;
|
||||||
|
}
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CuccoStormHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
|
Player* player = GET_PLAYER(gGlobalCtx);
|
||||||
|
EnNiw* cucco = (EnNiw*)Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_NIW, player->actor.world.pos.x,
|
||||||
|
player->actor.world.pos.y + 2200, player->actor.world.pos.z, 0, 0, 0, 0);
|
||||||
|
cucco->actionFunc = func_80AB70A0_nocutscene;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#define VARTYPE_INTEGER 0
|
#define VARTYPE_INTEGER 0
|
||||||
#define VARTYPE_FLOAT 1
|
#define VARTYPE_FLOAT 1
|
||||||
#define VARTYPE_STRING 2
|
#define VARTYPE_STRING 2
|
||||||
@ -492,7 +944,6 @@ static bool SetCVarHandler(std::shared_ptr<Ship::Console> Console, const std::ve
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool GetCVarHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
static bool GetCVarHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
|
||||||
if (args.size() < 2)
|
if (args.size() < 2)
|
||||||
return CMD_FAILED;
|
return CMD_FAILED;
|
||||||
@ -520,14 +971,41 @@ static bool GetCVarHandler(std::shared_ptr<Ship::Console> Console, const std::ve
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DebugConsole_Init(void) {
|
void DebugConsole_Init(void) {
|
||||||
|
// Console
|
||||||
|
CMD_REGISTER("file_select", { FileSelectHandler, "Returns to the file select." });
|
||||||
|
CMD_REGISTER("reset", { ResetHandler, "Resets the game." });
|
||||||
|
CMD_REGISTER("quit", { QuitHandler, "Quits the game." });
|
||||||
|
|
||||||
|
// Save States
|
||||||
|
CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." });
|
||||||
|
CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." });
|
||||||
|
CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", {
|
||||||
|
{ "Slot number", Ship::ArgumentType::NUMBER, }
|
||||||
|
}});
|
||||||
|
|
||||||
|
// Map & Location
|
||||||
|
CMD_REGISTER("void", { VoidHandler, "Voids out of the current map." });
|
||||||
|
CMD_REGISTER("reload", { ReloadHandler, "Reloads the current map." });
|
||||||
|
CMD_REGISTER("fw", { FWHandler,"Spawns the player where Farore's Wind is set." });
|
||||||
|
CMD_REGISTER("entrance", { EntranceHandler, "Sends player to the entered entrance (hex)", {
|
||||||
|
{ "entrance", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
// Gameplay
|
||||||
CMD_REGISTER("kill", { KillPlayerHandler, "Commit suicide." });
|
CMD_REGISTER("kill", { KillPlayerHandler, "Commit suicide." });
|
||||||
|
|
||||||
CMD_REGISTER("map", { LoadSceneHandler, "Load up kak?" });
|
CMD_REGISTER("map", { LoadSceneHandler, "Load up kak?" });
|
||||||
CMD_REGISTER("rupee", { RuppeHandler, "Set your rupee counter.", {
|
|
||||||
|
CMD_REGISTER("rupee", { RupeeHandler, "Set your rupee counter.", {
|
||||||
{"amount", Ship::ArgumentType::NUMBER }
|
{"amount", Ship::ArgumentType::NUMBER }
|
||||||
}});
|
}});
|
||||||
CMD_REGISTER("bItem", { BHandler, "Set an item to the B button.", { { "Item ID", Ship::ArgumentType::NUMBER } } });
|
|
||||||
CMD_REGISTER("health", { SetPlayerHealthHandler, "Set the health of the player.", { { "health", Ship::ArgumentType::NUMBER }
|
CMD_REGISTER("bItem", { BHandler, "Set an item to the B button.", {
|
||||||
|
{ "Item ID", Ship::ArgumentType::NUMBER }
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("givedekushield", { GiveDekuShieldHandler, "Gives a deku shield and equips it when Link is a child with no shield equiped." });
|
||||||
|
|
||||||
CMD_REGISTER("spawn", { ActorSpawnHandler, "Spawn an actor.", { { "actor_id", Ship::ArgumentType::NUMBER },
|
CMD_REGISTER("spawn", { ActorSpawnHandler, "Spawn an actor.", { { "actor_id", Ship::ArgumentType::NUMBER },
|
||||||
{ "data", Ship::ArgumentType::NUMBER },
|
{ "data", Ship::ArgumentType::NUMBER },
|
||||||
{ "x", Ship::ArgumentType::PLAYER_POS, true },
|
{ "x", Ship::ArgumentType::PLAYER_POS, true },
|
||||||
@ -537,40 +1015,122 @@ void DebugConsole_Init(void) {
|
|||||||
{ "ry", Ship::ArgumentType::PLAYER_ROT, true },
|
{ "ry", Ship::ArgumentType::PLAYER_ROT, true },
|
||||||
{ "rz", Ship::ArgumentType::PLAYER_ROT, true }
|
{ "rz", Ship::ArgumentType::PLAYER_ROT, true }
|
||||||
}});
|
}});
|
||||||
CMD_REGISTER("pos", { SetPosHandler, "Sets the position of the player.", { { "x", Ship::ArgumentType::PLAYER_POS, true },
|
|
||||||
|
CMD_REGISTER("pos", { SetPosHandler, "Sets the position of the player.", {
|
||||||
|
{ "x", Ship::ArgumentType::PLAYER_POS, true },
|
||||||
{ "y", Ship::ArgumentType::PLAYER_POS, true },
|
{ "y", Ship::ArgumentType::PLAYER_POS, true },
|
||||||
{ "z", Ship::ArgumentType::PLAYER_POS, true }
|
{ "z", Ship::ArgumentType::PLAYER_POS, true }
|
||||||
}});
|
}});
|
||||||
CMD_REGISTER("set", { SetCVarHandler,
|
|
||||||
"Sets a console variable.",
|
|
||||||
{ { "varName", Ship::ArgumentType::TEXT }, { "varValue", Ship::ArgumentType::TEXT } } });
|
|
||||||
CMD_REGISTER("get", { GetCVarHandler, "Gets a console variable.", { { "varName", Ship::ArgumentType::TEXT } } });
|
|
||||||
CMD_REGISTER("reset", { ResetHandler, "Resets the game." });
|
|
||||||
CMD_REGISTER("ammo", { AmmoHandler, "Changes ammo of an item.",
|
|
||||||
{ { "item", Ship::ArgumentType::TEXT }, { "count", Ship::ArgumentType::NUMBER } } });
|
|
||||||
|
|
||||||
CMD_REGISTER("bottle", { BottleHandler,
|
CMD_REGISTER("set", { SetCVarHandler, "Sets a console variable.", {
|
||||||
"Changes item in a bottle slot.",
|
{ "varName", Ship::ArgumentType::TEXT },
|
||||||
{ { "item", Ship::ArgumentType::TEXT }, { "slot", Ship::ArgumentType::NUMBER } } });
|
{ "varValue", Ship::ArgumentType::TEXT }
|
||||||
|
|
||||||
CMD_REGISTER("item", { ItemHandler,
|
|
||||||
"Sets item ID in arg 1 into slot arg 2. No boundary checks. Use with caution.",
|
|
||||||
{ { "slot", Ship::ArgumentType::NUMBER }, { "item id", Ship::ArgumentType::NUMBER } } });
|
|
||||||
CMD_REGISTER("entrance", { EntranceHandler,
|
|
||||||
"Sends player to the entered entrance (hex)",
|
|
||||||
{ { "entrance", Ship::ArgumentType::NUMBER } } });
|
|
||||||
CMD_REGISTER("void", {VoidHandler, "Voids out of the current map.",});
|
|
||||||
CMD_REGISTER("reload", {ReloadHandler, "Reloads the current map.",});
|
|
||||||
CMD_REGISTER("file_select", {FileSelectHandler, "Returns to the file select.",});
|
|
||||||
CMD_REGISTER("fw", {FWHandler,"Spawns the player where Farore's Wind is set.", });
|
|
||||||
CMD_REGISTER("quit", {QuitHandler, "Quits the game.",});
|
|
||||||
|
|
||||||
CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." });
|
|
||||||
CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." });
|
|
||||||
CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", { {
|
|
||||||
"Slot number",
|
|
||||||
Ship::ArgumentType::NUMBER,
|
|
||||||
}
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("get", { GetCVarHandler, "Gets a console variable.", {
|
||||||
|
{ "varName", Ship::ArgumentType::TEXT }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("ammo", { AmmoHandler, "Changes ammo of an item.", {
|
||||||
|
{ "item", Ship::ArgumentType::TEXT },
|
||||||
|
{ "count", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("bottle", { BottleHandler, "Changes item in a bottle slot.", {
|
||||||
|
{ "item", Ship::ArgumentType::TEXT },
|
||||||
|
{ "slot", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("item", { ItemHandler, "Sets item ID in arg 1 into slot arg 2. No boundary checks. Use with caution.", {
|
||||||
|
{ "slot", Ship::ArgumentType::NUMBER },
|
||||||
|
{ "item id", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("invisible", { InvisibleHandler, "Activate Link's Elvish cloak, making him appear invisible.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("giant_link", { GiantLinkHandler, "Turn Link into a giant Lonky boi.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("minish_link", { MinishLinkHandler, "Turn Link into a minish boi.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("add_heart_container", { AddHeartContainerHandler, "Give Link a heart! The maximum amount of hearts is 20!" });
|
||||||
|
|
||||||
|
CMD_REGISTER("remove_heart_container", { RemoveHeartContainerHandler, "Remove a heart from Link. The minimal amount of hearts is 3." });
|
||||||
|
|
||||||
|
CMD_REGISTER("gravity", { GravityHandler, "Set gravity level.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("no_ui", { NoUIHandler, "Disables the UI.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("freeze", { FreezeHandler, "Freezes Link in place" });
|
||||||
|
|
||||||
|
CMD_REGISTER("defense_modifier", { DefenseModifierHandler, "Sets the defense modifier.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("damage", { DamageHandler, "Deal damage to Link.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("heal", { HealHandler, "Heals Link.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("fill_magic", { FillMagicHandler, "Fills magic." });
|
||||||
|
|
||||||
|
CMD_REGISTER("empty_magic", { EmptyMagicHandler, "Empties magic." });
|
||||||
|
|
||||||
|
CMD_REGISTER("no_z", { NoZHandler, "Disables Z-button presses.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("ohko", { OneHitKOHandler, "Activates one hit KO. Any damage kills Link and he cannot gain health in this mode.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("pacifist", { PacifistHandler, "Activates pacifist mode. Prevents Link from using his weapon.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("paper_link", { PaperLinkHandler, "Link but made out of paper.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("rainstorm", { RainstormHandler, "Activates rainstorm." });
|
||||||
|
|
||||||
|
CMD_REGISTER("reverse_controls", { ReverseControlsHandler, "Reverses the controls.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("update_rupees", { UpdateRupeesHandler, "Adds rupees.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("speed_modifier", { SpeedModifierHandler, "Sets the speed modifier.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("boots", { BootsHandler, "Activates boots.", {
|
||||||
|
{ "type", Ship::ArgumentType::TEXT },
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("knockback", { KnockbackHandler, "Knocks Link back.", {
|
||||||
|
{ "value", Ship::ArgumentType::NUMBER }
|
||||||
|
}});
|
||||||
|
|
||||||
|
CMD_REGISTER("electrocute", { ElectrocuteHandler, "Electrocutes Link." });
|
||||||
|
|
||||||
|
CMD_REGISTER("burn", { BurnHandler, "Burns Link." });
|
||||||
|
|
||||||
|
CMD_REGISTER("cucco_storm", { CuccoStormHandler, "Cucco Storm" });
|
||||||
|
|
||||||
CVar_Load();
|
CVar_Load();
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
#define GRAVITY_LEVEL_NORMAL 1.0f
|
||||||
|
#define GRAVITY_LEVEL_LIGHT 0.0f
|
||||||
|
#define GRAVITY_LEVEL_HEAVY 2.0f
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
// bools are exported as uint32_t for compatibility with C code
|
||||||
|
extern uint32_t chaosEffectNoUI;
|
||||||
|
extern uint32_t chaosEffectGiantLink;
|
||||||
|
extern uint32_t chaosEffectMinishLink;
|
||||||
|
extern uint32_t chaosEffectPaperLink;
|
||||||
|
extern uint32_t chaosEffectResetLinkScale;
|
||||||
|
extern uint32_t chaosEffectInvisibleLink;
|
||||||
|
extern uint32_t chaosEffectOneHitKO;
|
||||||
|
extern uint32_t chaosEffectPacifistMode;
|
||||||
|
extern int32_t chaosEffectDefenseModifier;
|
||||||
|
extern uint32_t chaosEffectNoZ;
|
||||||
|
extern uint32_t chaosEffectReverseControls;
|
||||||
|
|
||||||
|
extern uint32_t chaosEffectGravityLevel;
|
||||||
|
extern int32_t chaosEffectSpeedModifier;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void DebugConsole_Init(void);
|
void DebugConsole_Init(void);
|
||||||
|
@ -1492,6 +1492,8 @@ namespace GameMenuBar {
|
|||||||
}
|
}
|
||||||
ImGui::PopStyleVar(3);
|
ImGui::PopStyleVar(3);
|
||||||
ImGui::PopStyleColor(1);
|
ImGui::PopStyleColor(1);
|
||||||
|
UIWidgets::PaddedEnhancementCheckbox("Crowd Control", "gCrowdControl", true, false);
|
||||||
|
UIWidgets::Tooltip("Enables CrowdControl. Will attempt to connect to the local Crowd Control server.");
|
||||||
|
|
||||||
UIWidgets::PaddedSeparator();
|
UIWidgets::PaddedSeparator();
|
||||||
|
|
||||||
|
@ -64,6 +64,11 @@
|
|||||||
#include "Enhancements/item-tables/ItemTableManager.h"
|
#include "Enhancements/item-tables/ItemTableManager.h"
|
||||||
#include "GameMenuBar.hpp"
|
#include "GameMenuBar.hpp"
|
||||||
|
|
||||||
|
#ifdef ENABLE_CROWD_CONTROL
|
||||||
|
#include "Enhancements/crowd-control/CrowdControl.h"
|
||||||
|
CrowdControl* CrowdControl::Instance;
|
||||||
|
#endif
|
||||||
|
|
||||||
OTRGlobals* OTRGlobals::Instance;
|
OTRGlobals* OTRGlobals::Instance;
|
||||||
SaveManager* SaveManager::Instance;
|
SaveManager* SaveManager::Instance;
|
||||||
CustomMessageManager* CustomMessageManager::Instance;
|
CustomMessageManager* CustomMessageManager::Instance;
|
||||||
@ -349,6 +354,11 @@ extern "C" void InitOTR() {
|
|||||||
InitItemTracker();
|
InitItemTracker();
|
||||||
OTRExtScanner();
|
OTRExtScanner();
|
||||||
VanillaItemTable_Init();
|
VanillaItemTable_Init();
|
||||||
|
|
||||||
|
#ifdef ENABLE_CROWD_CONTROL
|
||||||
|
CrowdControl::Instance = new CrowdControl();
|
||||||
|
CrowdControl::Instance->InitCrowdControl();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void DeinitOTR() {
|
extern "C" void DeinitOTR() {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
|
|
||||||
|
#include "soh/Enhancements/debugconsole.h"
|
||||||
|
|
||||||
//#include <string.h>
|
//#include <string.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@ -226,6 +228,25 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) {
|
|||||||
switch (padnow1->err_no) {
|
switch (padnow1->err_no) {
|
||||||
case 0:
|
case 0:
|
||||||
input->cur = *padnow1;
|
input->cur = *padnow1;
|
||||||
|
|
||||||
|
if (chaosEffectNoZ) {
|
||||||
|
input->cur.button &= ~(BTN_Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chaosEffectReverseControls) {
|
||||||
|
if (input->cur.stick_x == -128) {
|
||||||
|
input->cur.stick_x = 127;
|
||||||
|
} else {
|
||||||
|
input->cur.stick_x *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input->cur.stick_y == -128) {
|
||||||
|
input->cur.stick_y = 127;
|
||||||
|
} else {
|
||||||
|
input->cur.stick_y *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!padMgr->ctrlrIsConnected[i]) {
|
if (!padMgr->ctrlrIsConnected[i]) {
|
||||||
padMgr->ctrlrIsConnected[i] = true;
|
padMgr->ctrlrIsConnected[i] = true;
|
||||||
osSyncPrintf(VT_FGCOL(YELLOW));
|
osSyncPrintf(VT_FGCOL(YELLOW));
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "soh/Enhancements/debugconsole.h"
|
||||||
|
|
||||||
|
|
||||||
static uint16_t _doActionTexWidth, _doActionTexHeight = -1;
|
static uint16_t _doActionTexWidth, _doActionTexHeight = -1;
|
||||||
static uint16_t DO_ACTION_TEX_WIDTH() {
|
static uint16_t DO_ACTION_TEX_WIDTH() {
|
||||||
@ -935,7 +937,11 @@ void func_80083108(GlobalContext* globalCtx) {
|
|||||||
Interface_ChangeAlpha(50);
|
Interface_ChangeAlpha(50);
|
||||||
}
|
}
|
||||||
} else if (msgCtx->msgMode == MSGMODE_NONE) {
|
} else if (msgCtx->msgMode == MSGMODE_NONE) {
|
||||||
if ((func_8008F2F8(globalCtx) >= 2) && (func_8008F2F8(globalCtx) < 5)) {
|
if (chaosEffectPacifistMode) {
|
||||||
|
gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] =
|
||||||
|
gSaveContext.buttonStatus[3] = gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] =
|
||||||
|
gSaveContext.buttonStatus[7] = gSaveContext.buttonStatus[8] = BTN_DISABLED;
|
||||||
|
} else if ((func_8008F2F8(globalCtx) >= 2) && (func_8008F2F8(globalCtx) < 5)) {
|
||||||
if (gSaveContext.buttonStatus[0] != BTN_DISABLED) {
|
if (gSaveContext.buttonStatus[0] != BTN_DISABLED) {
|
||||||
sp28 = 1;
|
sp28 = 1;
|
||||||
}
|
}
|
||||||
@ -2913,6 +2919,15 @@ s32 Health_ChangeBy(GlobalContext* globalCtx, s16 healthChange) {
|
|||||||
osSyncPrintf("***** 増減=%d (now=%d, max=%d) ***", healthChange, gSaveContext.health,
|
osSyncPrintf("***** 増減=%d (now=%d, max=%d) ***", healthChange, gSaveContext.health,
|
||||||
gSaveContext.healthCapacity);
|
gSaveContext.healthCapacity);
|
||||||
|
|
||||||
|
// If one-hit ko mode is on, any damage kills you and you cannot gain health.
|
||||||
|
if (chaosEffectOneHitKO) {
|
||||||
|
if (healthChange < 0) {
|
||||||
|
gSaveContext.health = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
if (healthChange > 0) { Audio_PlaySoundGeneral(NA_SE_SY_HP_RECOVER, &D_801333D4, 4,
|
if (healthChange > 0) { Audio_PlaySoundGeneral(NA_SE_SY_HP_RECOVER, &D_801333D4, 4,
|
||||||
&D_801333E0, &D_801333E0, &D_801333E8);
|
&D_801333E0, &D_801333E0, &D_801333E8);
|
||||||
@ -2922,6 +2937,14 @@ s32 Health_ChangeBy(GlobalContext* globalCtx, s16 healthChange) {
|
|||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
if (chaosEffectDefenseModifier != 0 && healthChange < 0) {
|
||||||
|
if (chaosEffectDefenseModifier > 0) {
|
||||||
|
healthChange /= chaosEffectDefenseModifier;
|
||||||
|
} else {
|
||||||
|
healthChange *= abs(chaosEffectDefenseModifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gSaveContext.health += healthChange;
|
gSaveContext.health += healthChange;
|
||||||
|
|
||||||
if (gSaveContext.health > gSaveContext.healthCapacity) {
|
if (gSaveContext.health > gSaveContext.healthCapacity) {
|
||||||
@ -2956,6 +2979,10 @@ void Health_GiveHearts(s16 hearts) {
|
|||||||
gSaveContext.healthCapacity += hearts * 0x10;
|
gSaveContext.healthCapacity += hearts * 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Health_RemoveHearts(s16 hearts) {
|
||||||
|
gSaveContext.healthCapacity -= hearts * 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
void Rupees_ChangeBy(s16 rupeeChange) {
|
void Rupees_ChangeBy(s16 rupeeChange) {
|
||||||
gSaveContext.rupeeAccumulator += rupeeChange;
|
gSaveContext.rupeeAccumulator += rupeeChange;
|
||||||
}
|
}
|
||||||
@ -3022,7 +3049,7 @@ void Inventory_ChangeAmmo(s16 item, s16 ammoChange) {
|
|||||||
void Magic_Fill(GlobalContext* globalCtx) {
|
void Magic_Fill(GlobalContext* globalCtx) {
|
||||||
if (gSaveContext.magicAcquired) {
|
if (gSaveContext.magicAcquired) {
|
||||||
gSaveContext.unk_13F2 = gSaveContext.unk_13F0;
|
gSaveContext.unk_13F2 = gSaveContext.unk_13F0;
|
||||||
gSaveContext.unk_13F6 = (gSaveContext.doubleMagic * 0x30) + 0x30;
|
gSaveContext.unk_13F6 = (gSaveContext.doubleMagic + 1) * 0x30;
|
||||||
gSaveContext.unk_13F0 = 9;
|
gSaveContext.unk_13F0 = 9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4739,6 +4766,10 @@ void Interface_Draw(GlobalContext* globalCtx) {
|
|||||||
s16 svar6;
|
s16 svar6;
|
||||||
bool fullUi = !CVar_GetS32("gMinimalUI", 0) || !R_MINIMAP_DISABLED || globalCtx->pauseCtx.state != 0;
|
bool fullUi = !CVar_GetS32("gMinimalUI", 0) || !R_MINIMAP_DISABLED || globalCtx->pauseCtx.state != 0;
|
||||||
|
|
||||||
|
if (chaosEffectNoUI) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OPEN_DISPS(globalCtx->state.gfxCtx);
|
OPEN_DISPS(globalCtx->state.gfxCtx);
|
||||||
|
|
||||||
// Invalidate Do Action textures as they may have changed
|
// Invalidate Do Action textures as they may have changed
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include "soh/Enhancements/gameconsole.h"
|
#include "soh/Enhancements/gameconsole.h"
|
||||||
#include <libultraship/ImGuiImpl.h>
|
#include <libultraship/ImGuiImpl.h>
|
||||||
#include "soh/frame_interpolation.h"
|
#include "soh/frame_interpolation.h"
|
||||||
|
#include "soh/Enhancements/debugconsole.h"
|
||||||
|
#include <overlays/actors/ovl_En_Niw/z_en_niw.h>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@ -1544,6 +1546,10 @@ void Gameplay_Main(GameState* thisx) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 PlayerGrounded(Player* player) {
|
||||||
|
return player->actor.bgCheckFlags & 1;
|
||||||
|
}
|
||||||
|
|
||||||
// original name: "Game_play_demo_mode_check"
|
// original name: "Game_play_demo_mode_check"
|
||||||
s32 Gameplay_InCsMode(GlobalContext* globalCtx) {
|
s32 Gameplay_InCsMode(GlobalContext* globalCtx) {
|
||||||
return (globalCtx->csCtx.state != CS_STATE_IDLE) || Player_InCsMode(globalCtx);
|
return (globalCtx->csCtx.state != CS_STATE_IDLE) || Player_InCsMode(globalCtx);
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include "objects/object_triforce_spot/object_triforce_spot.h"
|
#include "objects/object_triforce_spot/object_triforce_spot.h"
|
||||||
#include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h"
|
#include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h"
|
||||||
|
|
||||||
|
#include "soh/Enhancements/debugconsole.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* 0x00 */ u8 flag;
|
/* 0x00 */ u8 flag;
|
||||||
/* 0x02 */ u16 textId;
|
/* 0x02 */ u16 textId;
|
||||||
@ -1037,6 +1039,11 @@ s32 func_80090014(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chaosEffectInvisibleLink) {
|
||||||
|
this->actor.shape.shadowDraw = NULL;
|
||||||
|
*dList = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,6 +764,12 @@ void func_80AB70A0(EnNiw* this, GlobalContext* globalCtx) {
|
|||||||
this->actionFunc = func_80AB70F8;
|
this->actionFunc = func_80AB70F8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void func_80AB70A0_nocutscene(EnNiw* this, GlobalContext* globalCtx) {
|
||||||
|
this->timer5 = 10;
|
||||||
|
this->unk_2A2 = 1;
|
||||||
|
this->actionFunc = func_80AB70F8;
|
||||||
|
}
|
||||||
|
|
||||||
void func_80AB70F8(EnNiw* this, GlobalContext* globalCtx) {
|
void func_80AB70F8(EnNiw* this, GlobalContext* globalCtx) {
|
||||||
this->sfxTimer1 = 100;
|
this->sfxTimer1 = 100;
|
||||||
|
|
||||||
|
@ -77,4 +77,17 @@ typedef struct EnNiw {
|
|||||||
/* 0x0358 */ EnNiwFeather feathers[20];
|
/* 0x0358 */ EnNiwFeather feathers[20];
|
||||||
} EnNiw; // size = 0x07B8
|
} EnNiw; // size = 0x07B8
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define this thisx
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
void func_80AB70A0(EnNiw* this, GlobalContext* globalCtx);
|
||||||
|
void func_80AB70A0_nocutscene(EnNiw* this, GlobalContext* globalCtx);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#undef this
|
||||||
|
};
|
||||||
|
#undef this
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
#include "objects/object_link_child/object_link_child.h"
|
#include "objects/object_link_child/object_link_child.h"
|
||||||
#include "textures/icon_item_24_static/icon_item_24_static.h"
|
#include "textures/icon_item_24_static/icon_item_24_static.h"
|
||||||
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
|
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
|
||||||
#include <soh/Enhancements/item-tables/ItemTableTypes.h>
|
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
|
||||||
|
#include "soh/Enhancements/debugconsole.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* 0x00 */ KNOB_ANIM_ADULT_L,
|
/* 0x00 */ KNOB_ANIM_ADULT_L,
|
||||||
@ -6021,9 +6022,19 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) {
|
|||||||
|
|
||||||
if (this->swordState == 0) {
|
if (this->swordState == 0) {
|
||||||
float maxSpeed = R_RUN_SPEED_LIMIT / 100.0f;
|
float maxSpeed = R_RUN_SPEED_LIMIT / 100.0f;
|
||||||
|
|
||||||
|
if (chaosEffectSpeedModifier != 0) {
|
||||||
|
if (chaosEffectSpeedModifier > 0) {
|
||||||
|
maxSpeed *= chaosEffectSpeedModifier;
|
||||||
|
} else {
|
||||||
|
maxSpeed /= abs(chaosEffectSpeedModifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CVar_GetS32("gMMBunnyHood", 0) != 0 && this->currentMask == PLAYER_MASK_BUNNY) {
|
if (CVar_GetS32("gMMBunnyHood", 0) != 0 && this->currentMask == PLAYER_MASK_BUNNY) {
|
||||||
maxSpeed *= 1.5f;
|
maxSpeed *= 1.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->linearVelocity = CLAMP(this->linearVelocity, -maxSpeed, maxSpeed);
|
this->linearVelocity = CLAMP(this->linearVelocity, -maxSpeed, maxSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7630,9 +7641,18 @@ void func_80842180(Player* this, GlobalContext* globalCtx) {
|
|||||||
func_80837268(this, &sp2C, &sp2A, 0.018f, globalCtx);
|
func_80837268(this, &sp2C, &sp2A, 0.018f, globalCtx);
|
||||||
|
|
||||||
if (!func_8083C484(this, &sp2C, &sp2A)) {
|
if (!func_8083C484(this, &sp2C, &sp2A)) {
|
||||||
|
if (chaosEffectSpeedModifier != 0) {
|
||||||
|
if (chaosEffectSpeedModifier > 0) {
|
||||||
|
sp2C *= chaosEffectSpeedModifier;
|
||||||
|
} else {
|
||||||
|
sp2C /= abs(chaosEffectSpeedModifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CVar_GetS32("gMMBunnyHood", 0) != 0 && this->currentMask == PLAYER_MASK_BUNNY) {
|
if (CVar_GetS32("gMMBunnyHood", 0) != 0 && this->currentMask == PLAYER_MASK_BUNNY) {
|
||||||
sp2C *= 1.5f;
|
sp2C *= 1.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
func_8083DF68(this, sp2C, sp2A);
|
func_8083DF68(this, sp2C, sp2A);
|
||||||
func_8083DDC8(this, globalCtx);
|
func_8083DDC8(this, globalCtx);
|
||||||
|
|
||||||
@ -10888,6 +10908,39 @@ void Player_Update(Actor* thisx, GlobalContext* globalCtx) {
|
|||||||
MREG(53) = this->actor.world.pos.y;
|
MREG(53) = this->actor.world.pos.y;
|
||||||
MREG(54) = this->actor.world.pos.z;
|
MREG(54) = this->actor.world.pos.z;
|
||||||
MREG(55) = this->actor.world.rot.y;
|
MREG(55) = this->actor.world.rot.y;
|
||||||
|
|
||||||
|
if (chaosEffectGiantLink) {
|
||||||
|
this->actor.scale.x = 0.02f;
|
||||||
|
this->actor.scale.y = 0.02f;
|
||||||
|
this->actor.scale.z = 0.02f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chaosEffectMinishLink) {
|
||||||
|
this->actor.scale.x = 0.001f;
|
||||||
|
this->actor.scale.y = 0.001f;
|
||||||
|
this->actor.scale.z = 0.001f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chaosEffectPaperLink) {
|
||||||
|
this->actor.scale.x = 0.001f;
|
||||||
|
this->actor.scale.y = 0.01f;
|
||||||
|
this->actor.scale.z = 0.01f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chaosEffectResetLinkScale) {
|
||||||
|
this->actor.scale.x = 0.01f;
|
||||||
|
this->actor.scale.y = 0.01f;
|
||||||
|
this->actor.scale.z = 0.01f;
|
||||||
|
chaosEffectResetLinkScale = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chaosEffectGravityLevel == GRAVITY_LEVEL_HEAVY) {
|
||||||
|
this->actor.gravity = -4.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chaosEffectGravityLevel == GRAVITY_LEVEL_LIGHT) {
|
||||||
|
this->actor.gravity = -0.3f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct_80858AC8 D_80858AC8;
|
static struct_80858AC8 D_80858AC8;
|
||||||
|
Loading…
Reference in New Issue
Block a user