Start effects

This commit is contained in:
David Chavez 2022-08-11 16:24:28 +02:00
parent 791f7774a5
commit 1bebf6ad91
18 changed files with 1803 additions and 34 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/*
SDL_net: An example cross-platform network library for use with SDL
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* $Id$ */
/* Include normal system headers */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifndef _WIN32_WCE
#include <errno.h>
#endif
/* Include system network headers */
#if defined(__WIN32__) || defined(WIN32)
#define __USE_W32_SOCKETS
#ifdef _WIN64
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <winsock.h>
/* NOTE: windows socklen_t is signed
* and is defined only for winsock2. */
typedef int socklen_t;
#endif /* W64 */
#include <iphlpapi.h>
#else /* UNIX */
#include <sys/types.h>
#ifdef __FreeBSD__
#include <sys/socket.h>
#endif
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#ifndef __BEOS__
#include <arpa/inet.h>
#endif
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netdb.h>
#endif /* WIN32 */
/* FIXME: What platforms need this? */
#if 0
typedef Uint32 socklen_t;
#endif
/* System-dependent definitions */
#ifndef __USE_W32_SOCKETS
#ifdef __OS2__
#define closesocket soclose
#else /* !__OS2__ */
#define closesocket close
#endif /* __OS2__ */
#define SOCKET int
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#endif /* __USE_W32_SOCKETS */
#ifdef __USE_W32_SOCKETS
#define SDLNet_GetLastError WSAGetLastError
#define SDLNet_SetLastError WSASetLastError
#ifndef EINTR
#define EINTR WSAEINTR
#endif
#else
int SDLNet_GetLastError(void);
void SDLNet_SetLastError(int err);
#endif

View File

@ -0,0 +1,53 @@
/*
CHAT: A chat client/server using the SDL example network library
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* $Id$ */
/* Convert four letters into a number */
#define MAKE_NUM(A, B, C, D) (((A+B)<<8)|(C+D))
/* Defines for the chat client */
#define CHAT_SCROLLBACK 512 /* Save 512 lines in scrollback */
#define CHAT_PROMPT "> "
#define CHAT_PACKETSIZE 256 /* Maximum length of a message */
/* Defines shared between the server and client */
#define CHAT_PORT MAKE_NUM('C','H','A','T')
/* The protocol between the chat client and server */
#define CHAT_HELLO 0 /* 0+Port+len+name */
#define CHAT_HELLO_PORT 1
#define CHAT_HELLO_NLEN CHAT_HELLO_PORT+2
#define CHAT_HELLO_NAME CHAT_HELLO_NLEN+1
#define CHAT_ADD 1 /* 1+N+IP+Port+len+name */
#define CHAT_ADD_SLOT 1
#define CHAT_ADD_HOST CHAT_ADD_SLOT+1
#define CHAT_ADD_PORT CHAT_ADD_HOST+4
#define CHAT_ADD_NLEN CHAT_ADD_PORT+2
#define CHAT_ADD_NAME CHAT_ADD_NLEN+1
#define CHAT_DEL 2 /* 2+N */
#define CHAT_DEL_SLOT 1
#define CHAT_DEL_LEN CHAT_DEL_SLOT+1
#define CHAT_BYE 255 /* 255 */
#define CHAT_BYE_LEN 1
/* The maximum number of people who can talk at once */
#define CHAT_MAXPEOPLE 10

View File

@ -222,6 +222,13 @@ set(Header_Files__soh__Enhancements__custom_message
source_group("Header Files\\soh\\Enhancements\\custom-message" FILES ${Header_Files__soh__Enhancements__custom_message})
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
"soh/GbiWrap.cpp"
"soh/OTRAudio.h"
@ -339,6 +346,13 @@ set(Source_Files__soh__Enhancements__custom_message
source_group("Source Files\\soh\\Enhancements\\custom-message" FILES ${Source_Files__soh__Enhancements__custom_message})
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
"src/boot/assert.c"
"src/boot/boot_main.c"
@ -1548,6 +1562,7 @@ set(ALL_FILES
${Header_Files__soh__Enhancements__randomizer}
${Header_Files__soh__Enhancements__randomizer__3drando}
${Header_Files__soh__Enhancements__custom_message}
${Header_Files__soh__Enhancements__crowd_control}
${Source_Files__soh}
${Source_Files__soh__Enhancements}
${Source_Files__soh__Enhancements__cosmetics}
@ -1557,6 +1572,7 @@ set(ALL_FILES
${Source_Files__soh__Enhancements__randomizer__3drando__hint_list}
${Source_Files__soh__Enhancements__randomizer__3drando__location_access}
${Source_Files__soh__Enhancements__custom_message}
${Source_Files__soh__Enhancements__crowd_control}
${Source_Files__src__boot}
${Source_Files__src__buffers}
${Source_Files__src__code}
@ -1663,7 +1679,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"$<$<CONFIG:Debug>:"
"_DEBUG;"
"_CRT_SECURE_NO_WARNINGS;"
"ENABLE_DX11"
"ENABLE_DX11;"
"ENABLE_CROWD_CONTROL"
">"
"$<$<CONFIG:Release>:"
"NDEBUG"

View File

@ -481,3 +481,6 @@
/* 0x01D4 */ DEFINE_ACTOR(En_Mm2, ACTOR_EN_MM2, ALLOCTYPE_NORMAL)
/* 0x01D5 */ DEFINE_ACTOR(Bg_Jya_Block, ACTOR_BG_JYA_BLOCK, ALLOCTYPE_NORMAL)
/* 0x01D6 */ DEFINE_ACTOR(Obj_Warp2block, ACTOR_OBJ_WARP2BLOCK, ALLOCTYPE_NORMAL)
#ifdef __ENABLE_CROWD_CONTROL__
/* 0x01D7 */ DEFINE_ACTOR(Obj_CrowdControl, ACTOR_CROWD_CONTROL, ALLOCTYPE_NORMAL)
#endif

View File

@ -0,0 +1,217 @@
#ifdef ENABLE_CROWD_CONTROL
#include "CrowdControl.h"
#include "Cvar.h"
#include "Lib/json.hpp"
#include <spdlog/spdlog.h>
#include <regex>
#include "soh/Enhancements/debugconsole.h"
extern "C" u8 ExecuteEffect(const char* effectId, uint32_t value);
extern "C" void RemoveEffect(const char* effectId);
namespace Ship {
namespace CrowdControl {
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) {
u8 paused = 0;
while (connected) {
u8 anotherEffect = 0;
nlohmann::json dataSend;
dataSend["id"] = packet->packetId;
dataSend["type"] = 0;
dataSend["timeRemaining"] = packet->timeRemaining;
for (CCPacket* pack : receivedCommands) {
if (pack != packet && pack->effectCategory == packet->effectCategory && pack->packetId < packet->packetId) {
anotherEffect = 1;
dataSend["status"] = EffectResult::Retry;
break;
}
}
u8 returnSuccess = 0;
if (anotherEffect == 0) {
returnSuccess = ExecuteEffect(packet->effectType.c_str(), packet->effectValue);
dataSend["status"] = returnSuccess == 1 ? EffectResult::Success : returnSuccess == 2 ? EffectResult::Failure : EffectResult::Retry;
}
std::string jsonResponse = dataSend.dump();
SDLNet_TCP_Send(tcpsock, const_cast<char*> (jsonResponse.data()), jsonResponse.size() + 1);
if (anotherEffect == 0) {
if (returnSuccess == 2) {
return;
}
if (returnSuccess == 1) {
if (paused && packet->timeRemaining > 0) {
paused = 0;
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, const_cast<char*> (jsonResponse.data()), jsonResponse.size() + 1);
}
if (packet->timeRemaining <= 0) {
receivedCommands.erase(std::remove(receivedCommands.begin(), receivedCommands.end(), packet), receivedCommands.end());
RemoveEffect(packet->effectType.c_str());
return;
}
packet->timeRemaining -= 1000;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
else if (returnSuccess == 0 && paused == 0 && packet->timeRemaining > 0) {
paused = 1;
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, const_cast<char*> (jsonResponse.data()), jsonResponse.size() + 1);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
else {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
else {
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) == 1) {
tcpsock = SDLNet_TCP_Open(&ip);
if (tcpsock) {
connected = true;
printf("Connected to Crowd Control!");
break;
}
}
while (connected && CVar_GetS32("gCrowdControl", 0) == 1 && tcpsock) {
int len = SDLNet_TCP_Recv(tcpsock, &received, 512);
if (!len || !tcpsock || len == -1) {
printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
break;
}
nlohmann::json dataReceived = nlohmann::json::parse(received);
CCPacket* packet = new CCPacket();
packet->packetId = dataReceived["id"];
packet->effectValue = dataReceived["type"];
packet->effectType = dataReceived["code"].get<std::string>();
if (strcmp(packet->effectType.c_str(), "high_gravity") == 0 ||
strcmp(packet->effectType.c_str(), "low_gravity") == 0) {
packet->effectCategory = "gravity";
packet->timeRemaining = 30000;
}
else if (strcmp(packet->effectType.c_str(), "defense_modifier") == 0) {
packet->effectCategory = "defense";
packet->timeRemaining = 30000;
}
else if (strcmp(packet->effectType.c_str(), "giant_link") == 0 ||
strcmp(packet->effectType.c_str(), "minish_link") == 0 ||
strcmp(packet->effectType.c_str(), "invisible") == 0 ||
strcmp(packet->effectType.c_str(), "paper_link") == 0) {
packet->effectCategory = "link_size";
packet->timeRemaining = 30000;
}
else if (strcmp(packet->effectType.c_str(), "freeze") == 0 ||
strcmp(packet->effectType.c_str(), "damage") == 0 ||
strcmp(packet->effectType.c_str(), "heal") == 0 ||
strcmp(packet->effectType.c_str(), "knockback") == 0 ||
strcmp(packet->effectType.c_str(), "electrocute") == 0 ||
strcmp(packet->effectType.c_str(), "burn") == 0) {
packet->effectCategory = "link_damage";
}
else if (strcmp(packet->effectType.c_str(), "hover_boots") == 0 ||
strcmp(packet->effectType.c_str(), "iron_boots") == 0) {
packet->effectCategory = "boots";
packet->timeRemaining = 30000;
}
else if (strcmp(packet->effectType.c_str(), "add_heart_container") == 0 ||
strcmp(packet->effectType.c_str(), "remove_heart_container") == 0) {
packet->effectCategory = "heart_container";
}
else if (strcmp(packet->effectType.c_str(), "no_ui") == 0) {
packet->effectCategory = "ui";
}
else if (strcmp(packet->effectType.c_str(), "fill_magic") == 0 ||
strcmp(packet->effectType.c_str(), "empty_magic") == 0) {
packet->effectCategory = "magic";
}
else if (strcmp(packet->effectType.c_str(), "ohko") == 0) {
packet->effectCategory = "ohko";
}
else if (strcmp(packet->effectType.c_str(), "pacifist") == 0) {
packet->effectCategory = "pacifist";
}
else if (strcmp(packet->effectType.c_str(), "rainstorm") == 0) {
packet->effectCategory = "weather";
}
else if (strcmp(packet->effectType.c_str(), "reverse") == 0) {
packet->effectCategory = "controls";
}
else if (strcmp(packet->effectType.c_str(), "rupees") == 0) {
packet->effectCategory = "rupees";
}
else if (strcmp(packet->effectType.c_str(), "speed") == 0) {
packet->effectCategory = "speed";
}
else if (strcmp(packet->effectType.c_str(), "wallmaster") == 0 ||
strcmp(packet->effectType.c_str(), "cucco") == 0) {
packet->effectCategory = "spawn";
}
else {
packet->effectCategory = "none";
packet->timeRemaining = 0;
}
receivedCommands.push_back(packet);
std::thread t = std::thread(&CrowdControl::RunCrowdControl, this, packet);
t.detach();
}
if (connected) {
SDLNet_TCP_Close(tcpsock);
SDLNet_Quit();
connected = false;
}
}
}
}
#endif

View File

@ -0,0 +1,89 @@
#ifdef ENABLE_CROWD_CONTROL
#ifndef _CROWDCONTROL_C
#define _CROWDCONTROL_C
#endif
#include "stdint.h"
#include <SDL2/SDL_net.h>
#include <cstdint>
#include <thread>
#include <memory>
#include <map>
#include <vector>
#include <iostream>
#include <chrono>
#include <future>
namespace Ship {
namespace CrowdControl {
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;
};
class CrowdControl {
private:
std::thread ccThreadReceive;
TCPsocket tcpsock;
IPaddress ip;
bool connected;
char received[512];
std::vector<CCPacket*> currentCommands;
std::vector<CCPacket*> receivedCommands;
void RunCrowdControl(CCPacket* packet);
void ReceiveFromCrowdControl();
public:
void InitCrowdControl();
};
}
} // namespace Ship
#endif

View File

@ -33,6 +33,14 @@ extern GlobalContext* gGlobalCtx;
#define CMD_REGISTER SohImGui::BindCmd
uint32_t defenseModifier;
uint32_t giantLink;
uint32_t minishLink;
uint32_t highGravity;
uint32_t resetLinkScale;
uint32_t noUi;
uint32_t invisibleLink;
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)) {
SohImGui::console->SendErrorMessage("Not enough arguments passed to actorspawn");
@ -373,6 +381,25 @@ static bool StateSlotSelectHandler(std::shared_ptr<Ship::Console> Console, const
return CMD_SUCCESS;
}
static bool InvisibleHandler(std::shared_ptr<Ship::Console> Console, const std::vector<std::string>& args) {
if (args.size() != 2) {
SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
bool invisible;
try {
invisible = std::stoi(args[1], nullptr, 10);
} catch (std::invalid_argument const& ex) {
SohImGui::console->SendErrorMessage("[SOH] Invisible value must be a number.");
return CMD_FAILED;
}
invisibleLink = invisible;
return CMD_SUCCESS;
}
#define VARTYPE_INTEGER 0
#define VARTYPE_FLOAT 1
#define VARTYPE_STRING 2
@ -466,47 +493,62 @@ void DebugConsole_Init(void) {
CMD_REGISTER("rupee", { RuppeHandler, "Set your rupee counter.", {
{"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("spawn", { ActorSpawnHandler, "Spawn an actor.", { { "actor_id", Ship::ArgumentType::NUMBER },
{ "data", Ship::ArgumentType::NUMBER },
{ "x", Ship::ArgumentType::PLAYER_POS, true },
{ "y", Ship::ArgumentType::PLAYER_POS, true },
{ "z", Ship::ArgumentType::PLAYER_POS, true },
{ "rx", Ship::ArgumentType::PLAYER_ROT, true },
{ "ry", Ship::ArgumentType::PLAYER_ROT, true },
{ "rz", Ship::ArgumentType::PLAYER_ROT, true }
CMD_REGISTER("health", { SetPlayerHealthHandler, "Set the health of the player.", {
{ "health", Ship::ArgumentType::NUMBER }
}});
CMD_REGISTER("pos", { SetPosHandler, "Sets the position of the player.", { { "x", Ship::ArgumentType::PLAYER_POS, true },
{ "y", Ship::ArgumentType::PLAYER_POS, true },
{ "z", Ship::ArgumentType::PLAYER_POS, true }
CMD_REGISTER("spawn", { ActorSpawnHandler, "Spawn an actor.", {
{ "actor_id", Ship::ArgumentType::NUMBER },
{ "data", Ship::ArgumentType::NUMBER },
{ "x", Ship::ArgumentType::PLAYER_POS, true },
{ "y", Ship::ArgumentType::PLAYER_POS, true },
{ "z", Ship::ArgumentType::PLAYER_POS, true },
{ "rx", Ship::ArgumentType::PLAYER_ROT, true },
{ "ry", 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 },
{ "y", 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("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("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("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("entrance", { EntranceHandler,
"Sends player to the entered entrance (hex)",
{ { "entrance", 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("entrance", { EntranceHandler, "Sends player to the entered entrance (hex)", {
{ "entrance", Ship::ArgumentType::NUMBER }
}});
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("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", {
{ "Slot number", Ship::ArgumentType::NUMBER, }
}});
CMD_REGISTER("invisible", { InvisibleHandler, "Toggles invisibility.", {
{ "invisible", Ship::ArgumentType::NUMBER }
}});
CVar_Load();
}

View File

@ -1,3 +1,19 @@
#pragma once
#include "stdint.h"
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t defenseModifier;
extern uint32_t giantLink;
extern uint32_t minishLink;
extern uint32_t highGravity;
extern uint32_t resetLinkScale;
extern uint32_t noUi;
extern uint32_t invisibleLink;
#ifdef __cplusplus
}
#endif
void DebugConsole_Init(void);

View File

@ -4,8 +4,10 @@
#include <string.h>
#include "soh/Enhancements/gameconsole.h"
#include "soh/Enhancements/debugconsole.h"
#include "../libultraship/ImGuiImpl.h"
#include "soh/frame_interpolation.h"
#include <overlays/actors/ovl_En_Niw/z_en_niw.h>
#include <time.h>
@ -1527,6 +1529,158 @@ void Gameplay_Main(GameState* thisx) {
}
u8 PlayerGrounded(Player* player) {
return (player->actor.world.pos.y - player->actor.floorHeight) == 0;
}
extern func_80AB70A0(EnNiw* this, GlobalContext* globalCtx);
void RemoveEffect(const char* effectId) {
if (gGlobalCtx == NULL) {
return;
}
Player* player = GET_PLAYER(gGlobalCtx);
if (player != NULL) {
if (strcmp(effectId, "giant_link") == 0) {
giantLink = 0;
resetLinkScale = 1;
return;
} else if (strcmp(effectId, "minish_link") == 0) {
minishLink = 0;
resetLinkScale = 1;
} else if (strcmp(effectId, "defense_modifier") == 0) {
defenseModifier = 0;
return;
} else if (strcmp(effectId, "iron_boots") == 0 || strcmp(effectId, "hover_boots") == 0) {
player->currentBoots = PLAYER_BOOTS_KOKIRI;
Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_KOKIRI + 1);
Player_SetBootData(gGlobalCtx, player);
return;
} else if (strcmp(effectId, "high_gravity") == 0 || strcmp(effectId, "low_gravity") == 0) {
highGravity = 0;
return;
} else if (strcmp(effectId, "no_ui") == 0) {
noUi = 0;
return;
} else if (strcmp(effectId, "invisible") == 0) {
invisibleLink = 0;
player->actor.shape.shadowDraw = ActorShadow_DrawFeet;
return;
}
}
}
u8 ExecuteEffect(const char* effectId, uint32_t value) {
if (gGlobalCtx == NULL) {
return 0;
}
Player* player = GET_PLAYER(gGlobalCtx);
if (player != NULL) {
if (strcmp(effectId, "add_heart_container") == 0) {
if (gSaveContext.healthCapacity >= 0x140) {
return 2;
}
gSaveContext.healthCapacity += 0x10;
return 1;
} else if (strcmp(effectId, "remove_heart_container") == 0) {
if ((gSaveContext.healthCapacity - 0x10) <= 0) {
return 2;
}
gSaveContext.healthCapacity -= 0x10;
return 1;
}
}
if (player != NULL && !Player_InBlockingCsMode(gGlobalCtx, player) && gGlobalCtx->pauseCtx.state == 0) {
if (strcmp(effectId, "high_gravity") == 0) {
highGravity = 1;
return 1;
} else if (strcmp(effectId, "low_gravity") == 0) {
highGravity = 2;
return 1;
} else if (strcmp(effectId, "giant_link") == 0) {
giantLink = 1;
return 1;
} else if (strcmp(effectId, "minish_link") == 0) {
minishLink = 1;
return 1;
} else if (strcmp(effectId, "defense_modifier") == 0) {
defenseModifier = value;
return 1;
} else if (strcmp(effectId, "kill") == 0) {
if (PlayerGrounded(player)) {
gSaveContext.health = 0;
return 1;
}
return 0;
} else if (strcmp(effectId, "cucco") == 0) {
EnNiw* cucco =
(EnNiw*)Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_NIW, player->actor.world.pos.x,
player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, 0);
cucco->actionFunc = func_80AB70A0;
return 1;
} else if (strcmp(effectId, "damage") == 0) {
Health_ChangeBy(gGlobalCtx, -value * 16);
func_80837C0C(gGlobalCtx, player, 0, 0, 0, 0, 0);
player->invincibilityTimer = 28;
return 1;
} else if (strcmp(effectId, "heal") == 0) {
Health_ChangeBy(gGlobalCtx, value * 16);
return 1;
} else if (strcmp(effectId, "freeze") == 0) {
if (PlayerGrounded(player)) {
func_80837C0C(gGlobalCtx, player, 3, 0, 0, 0, 0);
return 1;
}
return 0;
} else if (strcmp(effectId, "knockback") == 0) {
func_8002F71C(gGlobalCtx, &player->actor, value * 5, player->actor.world.rot.y + 0x8000, value * 5);
return 1;
} else if (strcmp(effectId, "burn") == 0) {
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 1;
}
return 0;
} else if (strcmp(effectId, "electrocute") == 0) {
if (PlayerGrounded(player)) {
func_80837C0C(gGlobalCtx, player, 4, 0, 0, 0, 0);
return 1;
}
return 0;
} else if (strcmp(effectId, "iron_boots") == 0) {
player->currentBoots = PLAYER_BOOTS_IRON;
Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_IRON + 1);
Player_SetBootData(gGlobalCtx, player);
return 1;
} else if (strcmp(effectId, "hover_boots") == 0) {
player->currentBoots = PLAYER_BOOTS_HOVER;
Inventory_ChangeEquipment(EQUIP_BOOTS, PLAYER_BOOTS_HOVER + 1);
Player_SetBootData(gGlobalCtx, player);
return 1;
} else if (strcmp(effectId, "wallmaster") == 0) {
Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, ACTOR_EN_WALLMAS, player->actor.world.pos.x, player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, 0);
return 1;
} else if (strcmp(effectId, "no_ui") == 0) {
noUi = 1;
return 1;
} else if (strcmp(effectId, "invisible") == 0) {
invisibleLink = 1;
return 1;
}
}
return 0;
}
// original name: "Game_play_demo_mode_check"
s32 Gameplay_InCsMode(GlobalContext* globalCtx) {
return (globalCtx->csCtx.state != CS_STATE_IDLE) || Player_InCsMode(globalCtx);

View File

@ -5,6 +5,8 @@
#include "objects/object_triforce_spot/object_triforce_spot.h"
#include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h"
#include "soh/Enhancements/debugconsole.h"
typedef struct {
/* 0x00 */ u8 flag;
/* 0x02 */ u16 textId;
@ -1037,6 +1039,11 @@ s32 func_80090014(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* p
}
}
if (invisibleLink) {
this->actor.shape.shadowDraw = NULL;
*dList = NULL;
}
return false;
}

View File

@ -21,6 +21,7 @@
#include "objects/object_link_child/object_link_child.h"
#include "textures/icon_item_24_static/icon_item_24_static.h"
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
#include "soh/Enhancements/debugconsole.h"
typedef struct {
/* 0x00 */ u8 itemId;
@ -11105,6 +11106,35 @@ void Player_Update(Actor* thisx, GlobalContext* globalCtx) {
MREG(53) = this->actor.world.pos.y;
MREG(54) = this->actor.world.pos.z;
MREG(55) = this->actor.world.rot.y;
// Crowd Control
if (giantLink == 1) {
this->actor.scale.x = 0.025f;
this->actor.scale.y = 0.025f;
this->actor.scale.z = 0.025f;
}
if (minishLink == 1) {
this->actor.scale.x = 0.001f;
this->actor.scale.y = 0.001f;
this->actor.scale.z = 0.001f;
}
if (resetLinkScale == 1) {
this->actor.scale.x = 0.01f;
this->actor.scale.y = 0.01f;
this->actor.scale.z = 0.01f;
resetLinkScale = 0;
}
if (highGravity == 1) {
this->actor.gravity = -4.0f;
}
if (highGravity == 2) {
this->actor.gravity = -0.3f;
}
}
static struct_80858AC8 D_80858AC8;