mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-10-31 15:45:06 -04:00
Merge branch 'develop' into pausedpadnav
This commit is contained in:
commit
bc1861a569
@ -18,6 +18,7 @@ Shader shader = { 0 };
|
||||
Light light = { 0 };
|
||||
Vector3 lightPos = { -5.0f, 10.0f, 10.0f };
|
||||
Vector2 dragOffset;
|
||||
bool isDragging = false;
|
||||
std::string sohFolder = NULLSTR;
|
||||
bool extracting = false;
|
||||
bool rom_ready = false;
|
||||
@ -95,69 +96,101 @@ void OTRGame::update(){
|
||||
}
|
||||
|
||||
void OTRGame::draw() {
|
||||
Vector2 windowSize(GetScreenWidth(), GetScreenHeight());
|
||||
Rectangle titlebar = Rectangle(0, 0, windowSize.x - 50, 35);
|
||||
Vector2 mousePos = GetMousePosition();
|
||||
Vector2 mouseDelta = GetMouseDelta();
|
||||
|
||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && !isDragging &&
|
||||
mousePos.x >= titlebar.x && mousePos.y >= titlebar.y && mousePos.x <= titlebar.x + titlebar.width && mousePos.y <= titlebar.y + titlebar.height) {
|
||||
isDragging = true;
|
||||
dragOffset = mousePos;
|
||||
}
|
||||
else if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT) && isDragging) {
|
||||
isDragging = false;
|
||||
dragOffset = Vector2(0, 0);
|
||||
}
|
||||
|
||||
if (isDragging && (mouseDelta.x != 0.0f || mouseDelta.y != 0.0f)) {
|
||||
Vector2 wndPos = GetWindowPosition();
|
||||
wndPos = Vector2(wndPos.x + (mousePos.x - dragOffset.x), wndPos.y + (mousePos.y - dragOffset.y));
|
||||
|
||||
// Calculate virtual screen total size in case there are multiple monitors
|
||||
|
||||
int vsX1 = 0, vsY1 = 0, vsX2 = 0, vsY2 = 0;
|
||||
int monitorCount = GetMonitorCount();
|
||||
|
||||
for (int m = 0; m < monitorCount; m++) {
|
||||
Vector2 monitorPos = GetMonitorPosition(m);
|
||||
Vector2 monitorSize = Vector2(GetMonitorWidth(m), GetMonitorHeight(m));
|
||||
|
||||
if (monitorPos.x < vsX1) vsX1 = monitorPos.x;
|
||||
if (monitorPos.y < vsY1) vsY1 = monitorPos.y;
|
||||
if (monitorPos.x + monitorSize.x > vsX2) vsX2 = monitorPos.x + monitorSize.x;
|
||||
if (monitorPos.y + monitorSize.y > vsY2) vsY2 = monitorPos.y + monitorSize.y;
|
||||
}
|
||||
|
||||
// Clamp the window to the borders of the monitors
|
||||
|
||||
if (wndPos.x < vsX1) wndPos.x = vsX1;
|
||||
if (wndPos.y < vsY1) wndPos.y = vsY1;
|
||||
if (wndPos.x + windowSize.x > vsX2) wndPos.x = vsX2 - windowSize.x;
|
||||
if (wndPos.y + windowSize.y > vsY2) wndPos.y = vsY2 - windowSize.y;
|
||||
|
||||
SetWindowPosition(wndPos.x, wndPos.y);
|
||||
}
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color(40, 40, 40, 255));
|
||||
Vector3 windowSize(GetScreenWidth(), GetScreenHeight());
|
||||
Rectangle titlebar = Rectangle(0, 0, windowSize.x - 50, 35);
|
||||
Vector2 mousePos = Vector2(GetMouseX(), GetMouseY());
|
||||
bool hoveredTitlebar = mousePos.x >= titlebar.x && mousePos.y >= titlebar.y && mousePos.x <= titlebar.x + titlebar.width && mousePos.y <= titlebar.y + titlebar.height;
|
||||
ClearBackground(Color(40, 40, 40, 255));
|
||||
|
||||
if (hoveredTitlebar && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
||||
if (dragOffset.x == 0 && dragOffset.y == 0) dragOffset = mousePos;
|
||||
Vector2 wndPos = GetWindowPosition();
|
||||
DrawTexture(Textures["Frame"], 0, 0, WHITE);
|
||||
|
||||
SetWindowPosition(wndPos.x + (mousePos.x - dragOffset.x), wndPos.y + (mousePos.y - dragOffset.y));
|
||||
}
|
||||
else dragOffset = Vector2(0, 0);
|
||||
Texture2D titleTex = Textures["Title"];
|
||||
DrawTexture(titleTex, windowSize.x / 2 - titleTex.width / 2, titlebar.height / 2 - titleTex.height / 2, WHITE);
|
||||
|
||||
DrawTexture(Textures["Frame"], 0, 0, WHITE);
|
||||
if (UIUtils::GuiIcon("Exit", windowSize.x - 36, titlebar.height / 2 - 10) && (extracting && currentStep.find("Done") != std::string::npos || !extracting)) {
|
||||
closeRequested = true;
|
||||
}
|
||||
|
||||
Texture2D titleTex = Textures["Title"];
|
||||
DrawTexture(titleTex, windowSize.x / 2 - titleTex.width / 2, titlebar.height / 2 - titleTex.height / 2, WHITE);
|
||||
BeginMode3D(camera);
|
||||
DrawModelEx(Models["Ship"], Vector3Zero(), Vector3(.0f, 1.0f, .0f), this->ModelRotation, SCALE(1.0f), WHITE);
|
||||
EndMode3D();
|
||||
|
||||
if (UIUtils::GuiIcon("Exit", windowSize.x - 36, titlebar.height / 2 - 10) && (extracting && currentStep.find("Done") != std::string::npos || !extracting)) {
|
||||
CloseWindow();
|
||||
}
|
||||
constexpr float text_y = 125.f;
|
||||
UIUtils::GuiShadowText(("Rom Type: " + version.version).c_str(), 32, text_y, 10, WHITE, BLACK);
|
||||
UIUtils::GuiShadowText("Tool Version: 1.0", 32, text_y + 15, 10, WHITE, BLACK);
|
||||
UIUtils::GuiShadowText("OTR Version: 1.0", 32, text_y + 30, 10, WHITE, BLACK);
|
||||
UIUtils::GuiToggle(&single_thread, "Single Thread", 32, text_y + 40, currentStep != NULLSTR);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawModelEx(Models["Ship"] ,Vector3Zero(), Vector3(.0f, 1.0f, .0f), this->ModelRotation, SCALE(1.0f), WHITE);
|
||||
EndMode3D();
|
||||
if (!hide_second_btn && UIUtils::GuiIconButton("Folder", "Open\nShip Folder", 109, 50, currentStep != NULLSTR, "Select your Ship of Harkinian Folder\n\nYou could use another folder\nfor development purposes")) {
|
||||
const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FOLDER);
|
||||
sohFolder = path;
|
||||
}
|
||||
|
||||
constexpr float text_y = 125.f;
|
||||
UIUtils::GuiShadowText(("Rom Type: " + version.version).c_str(), 32, text_y, 10, WHITE, BLACK);
|
||||
UIUtils::GuiShadowText("Tool Version: 1.0", 32, text_y + 15, 10, WHITE, BLACK);
|
||||
UIUtils::GuiShadowText("OTR Version: 1.0", 32, text_y + 30, 10, WHITE, BLACK);
|
||||
UIUtils::GuiToggle(&single_thread, "Single Thread", 32, text_y + 40, currentStep != NULLSTR);
|
||||
|
||||
if(!hide_second_btn && UIUtils::GuiIconButton("Folder", "Open\nShip Folder", 109, 50, currentStep != NULLSTR, "Select your Ship of Harkinian Folder\n\nYou could use another folder\nfor development purposes")) {
|
||||
const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FOLDER);
|
||||
sohFolder = path;
|
||||
}
|
||||
|
||||
if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nMaster Quest or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) {
|
||||
const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FILE);
|
||||
if (path != NULLSTR) {
|
||||
const std::string patched_n64 = std::string(patched_rom);
|
||||
MoonUtils::rm(patched_n64);
|
||||
version = GetVersion(fopen(path.c_str(), "r"));
|
||||
if (version.version != NULLSTR) {
|
||||
MoonUtils::copy(path, patched_n64);
|
||||
rom_ready = true;
|
||||
return;
|
||||
}
|
||||
fix_baserom(path.c_str(), patched_rom);
|
||||
version = GetVersion(fopen(patched_rom, "r"));
|
||||
if (version.version != NULLSTR) rom_ready = true;
|
||||
if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nMaster Quest or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) {
|
||||
const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FILE);
|
||||
if (path != NULLSTR) {
|
||||
const std::string patched_n64 = std::string(patched_rom);
|
||||
MoonUtils::rm(patched_n64);
|
||||
version = GetVersion(fopen(path.c_str(), "r"));
|
||||
if (version.version != NULLSTR) {
|
||||
MoonUtils::copy(path, patched_n64);
|
||||
rom_ready = true;
|
||||
return;
|
||||
}
|
||||
fix_baserom(path.c_str(), patched_rom);
|
||||
version = GetVersion(fopen(patched_rom, "r"));
|
||||
if (version.version != NULLSTR) rom_ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(currentStep != NULLSTR) {
|
||||
DrawRectangle(0, 0, windowSize.x, windowSize.y, Color(0, 0, 0, 160));
|
||||
DrawTexture(Textures["Modal"], windowSize.x / 2 - Textures["Modal"].width / 2, windowSize.y / 2 - Textures["Modal"].height / 2, WHITE);
|
||||
UIUtils::GuiShadowText(currentStep.c_str(), 0, windowSize.y / 2, 10, WHITE, BLACK, windowSize.x, true);
|
||||
}
|
||||
if (currentStep != NULLSTR) {
|
||||
DrawRectangle(0, 0, windowSize.x, windowSize.y, Color(0, 0, 0, 160));
|
||||
DrawTexture(Textures["Modal"], windowSize.x / 2 - Textures["Modal"].width / 2, windowSize.y / 2 - Textures["Modal"].height / 2, WHITE);
|
||||
UIUtils::GuiShadowText(currentStep.c_str(), 0, windowSize.y / 2, 10, WHITE, BLACK, windowSize.x, true);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
void setCurrentStep(const std::string& step) {
|
||||
|
@ -19,6 +19,8 @@ public:
|
||||
void update();
|
||||
void draw();
|
||||
void exit();
|
||||
|
||||
inline bool CloseRequested() { return closeRequested; }
|
||||
protected:
|
||||
void LoadTexture(const std::string& name, const std::string& path) {
|
||||
const Image tmp = LoadImage(path.c_str());
|
||||
@ -32,6 +34,9 @@ protected:
|
||||
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT);
|
||||
Fonts[name] = font;
|
||||
}
|
||||
|
||||
private:
|
||||
bool closeRequested = false;
|
||||
};
|
||||
|
||||
extern OTRGame* Game;
|
||||
|
@ -17,8 +17,8 @@ void UpdateDrawFrame(void) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
constexpr Vector2 windowSize = Vector2(400, 200);
|
||||
SetTargetFPS(144);
|
||||
constexpr Vector2 windowSize = Vector2(400, 200);
|
||||
SetConfigFlags(FLAG_VSYNC_HINT);
|
||||
SetConfigFlags(FLAG_WINDOW_HIGHDPI);
|
||||
SetConfigFlags(FLAG_WINDOW_UNDECORATED);
|
||||
SetConfigFlags(FLAG_MSAA_4X_HINT);
|
||||
@ -32,7 +32,7 @@ int main() {
|
||||
Game = new OTRGame();
|
||||
Game->preload();
|
||||
Game->init();
|
||||
while(!WindowShouldClose()) {
|
||||
while(!WindowShouldClose() && !Game->CloseRequested()) {
|
||||
UpdateDrawFrame();
|
||||
}
|
||||
CloseWindow();
|
||||
|
@ -188,14 +188,16 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
else if (arg == "-eh") // Enable Error Handler
|
||||
{
|
||||
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
|
||||
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
|
||||
signal(SIGSEGV, ErrorHandler);
|
||||
signal(SIGABRT, ErrorHandler);
|
||||
#else
|
||||
HANDLE_WARNING(WarningType::Always,
|
||||
"tried to set error handler, but this ZAPD build lacks support for one",
|
||||
"");
|
||||
// HANDLE_WARNING(WarningType::Always,
|
||||
// "tried to set error handler, but this ZAPD build lacks support for one",
|
||||
// "");
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
else if (arg == "-v") // Verbose
|
||||
{
|
||||
|
@ -27,6 +27,7 @@ namespace Game {
|
||||
const std::string AudioSection = AUDIO_SECTION;
|
||||
const std::string ControllerSection = CONTROLLER_SECTION;
|
||||
const std::string EnhancementSection = ENHANCEMENTS_SECTION;
|
||||
const std::string CheatSection = CHEATS_SECTION;
|
||||
|
||||
void UpdateAudio() {
|
||||
Audio_SetGameVolume(SEQ_BGM_MAIN, Settings.audio.music_main);
|
||||
@ -57,9 +58,7 @@ namespace Game {
|
||||
Settings.enhancements.animated_pause_menu = stob(Conf[EnhancementSection]["animated_pause_menu"]);
|
||||
CVar_SetS32(const_cast<char*>("gPauseLiveLink"), Settings.enhancements.animated_pause_menu);
|
||||
|
||||
Settings.enhancements.debug_mode = stob(Conf[EnhancementSection]["debug_mode"]);
|
||||
CVar_SetS32(const_cast<char*>("gDebugEnabled"), Settings.enhancements.debug_mode);
|
||||
|
||||
// Audio
|
||||
Settings.audio.master = Ship::stof(Conf[AudioSection]["master"]);
|
||||
CVar_SetFloat(const_cast<char*>("gGameMasterVolume"), Settings.audio.master);
|
||||
|
||||
@ -75,6 +74,7 @@ namespace Game {
|
||||
Settings.audio.fanfare = Ship::stof(Conf[AudioSection]["fanfare"]);
|
||||
CVar_SetFloat(const_cast<char*>("gFanfareVolume"), Settings.audio.fanfare);
|
||||
|
||||
// Controllers
|
||||
Settings.controller.gyro_sensitivity = Ship::stof(Conf[ControllerSection]["gyro_sensitivity"]);
|
||||
CVar_SetFloat(const_cast<char*>("gGyroSensitivity"), Settings.controller.gyro_sensitivity);
|
||||
|
||||
@ -87,6 +87,34 @@ namespace Game {
|
||||
Settings.controller.input_enabled = stob(Conf[ControllerSection]["input_enabled"]);
|
||||
CVar_SetS32(const_cast<char*>("gInputEnabled"), Settings.controller.input_enabled);
|
||||
|
||||
// Cheats
|
||||
Settings.cheats.debug_mode = stob(Conf[CheatSection]["debug_mode"]);
|
||||
CVar_SetS32(const_cast<char*>("gDebugEnabled"), Settings.cheats.debug_mode);
|
||||
|
||||
Settings.cheats.infinite_money = stob(Conf[CheatSection]["infinite_money"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteMoney"), Settings.cheats.infinite_money);
|
||||
|
||||
Settings.cheats.infinite_health = stob(Conf[CheatSection]["infinite_health"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteHealth"), Settings.cheats.infinite_health);
|
||||
|
||||
Settings.cheats.infinite_ammo = stob(Conf[CheatSection]["infinite_ammo"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteAmmo"), Settings.cheats.infinite_ammo);
|
||||
|
||||
Settings.cheats.infinite_magic = stob(Conf[CheatSection]["infinite_magic"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteMagic"), Settings.cheats.infinite_magic);
|
||||
|
||||
Settings.cheats.no_clip = stob(Conf[CheatSection]["no_clip"]);
|
||||
CVar_SetS32(const_cast<char*>("gNoClip"), Settings.cheats.no_clip);
|
||||
|
||||
Settings.cheats.climb_everything = stob(Conf[CheatSection]["climb_everything"]);
|
||||
CVar_SetS32(const_cast<char*>("gClimbEverything"), Settings.cheats.climb_everything);
|
||||
|
||||
Settings.cheats.moon_jump_on_l = stob(Conf[CheatSection]["moon_jump_on_l"]);
|
||||
CVar_SetS32(const_cast<char*>("gMoonJumpOnL"), Settings.cheats.moon_jump_on_l);
|
||||
|
||||
Settings.cheats.super_tunic = stob(Conf[CheatSection]["super_tunic"]);
|
||||
CVar_SetS32(const_cast<char*>("gSuperTunic"), Settings.cheats.super_tunic);
|
||||
|
||||
UpdateAudio();
|
||||
}
|
||||
|
||||
@ -111,13 +139,25 @@ namespace Game {
|
||||
Conf[EnhancementSection]["fast_text"] = std::to_string(Settings.enhancements.fast_text);
|
||||
Conf[EnhancementSection]["disable_lod"] = std::to_string(Settings.enhancements.disable_lod);
|
||||
Conf[EnhancementSection]["animated_pause_menu"] = std::to_string(Settings.enhancements.animated_pause_menu);
|
||||
Conf[EnhancementSection]["debug_mode"] = std::to_string(Settings.enhancements.debug_mode);
|
||||
|
||||
|
||||
// Controllers
|
||||
Conf[ControllerSection]["gyro_sensitivity"] = std::to_string(Settings.controller.gyro_sensitivity);
|
||||
Conf[ControllerSection]["rumble_strength"] = std::to_string(Settings.controller.rumble_strength);
|
||||
Conf[ControllerSection]["input_scale"] = std::to_string(Settings.controller.input_scale);
|
||||
Conf[ControllerSection]["input_enabled"] = std::to_string(Settings.controller.input_enabled);
|
||||
|
||||
// Cheats
|
||||
Conf[CheatSection]["debug_mode"] = std::to_string(Settings.cheats.debug_mode);
|
||||
Conf[CheatSection]["infinite_money"] = std::to_string(Settings.cheats.infinite_money);
|
||||
Conf[CheatSection]["infinite_health"] = std::to_string(Settings.cheats.infinite_health);
|
||||
Conf[CheatSection]["infinite_ammo"] = std::to_string(Settings.cheats.infinite_ammo);
|
||||
Conf[CheatSection]["infinite_magic"] = std::to_string(Settings.cheats.infinite_magic);
|
||||
Conf[CheatSection]["no_clip"] = std::to_string(Settings.cheats.no_clip);
|
||||
Conf[CheatSection]["climb_everything"] = std::to_string(Settings.cheats.climb_everything);
|
||||
Conf[CheatSection]["moon_jump_on_l"] = std::to_string(Settings.cheats.moon_jump_on_l);
|
||||
Conf[CheatSection]["super_tunic"] = std::to_string(Settings.cheats.super_tunic);
|
||||
|
||||
Conf.Save();
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,30 @@ struct SoHConfigType {
|
||||
bool fast_text = false;
|
||||
bool disable_lod = false;
|
||||
bool animated_pause_menu = false;
|
||||
bool debug_mode = false;
|
||||
} enhancements;
|
||||
|
||||
// Controller
|
||||
struct {
|
||||
float gyro_sensitivity = 1.0f;
|
||||
float rumble_strength = 1.0f;
|
||||
float input_scale = 1.0f;
|
||||
bool input_enabled = false;
|
||||
float gyroDriftX = 0.0f;
|
||||
float gyroDriftY = 0.0f;
|
||||
bool input_enabled = false;
|
||||
} controller;
|
||||
|
||||
// Cheats
|
||||
struct {
|
||||
bool debug_mode = false;
|
||||
bool infinite_money = false;
|
||||
bool infinite_health = false;
|
||||
bool infinite_ammo = false;
|
||||
bool infinite_magic = false;
|
||||
bool no_clip = false;
|
||||
bool climb_everything = false;
|
||||
bool moon_jump_on_l = false;
|
||||
bool super_tunic = false;
|
||||
} cheats;
|
||||
};
|
||||
|
||||
enum SeqPlayers {
|
||||
@ -46,6 +61,7 @@ enum SeqPlayers {
|
||||
#define AUDIO_SECTION "AUDIO SETTINGS"
|
||||
#define CONTROLLER_SECTION "CONTROLLER SECTION"
|
||||
#define ENHANCEMENTS_SECTION "ENHANCEMENT SETTINGS"
|
||||
#define CHEATS_SECTION "CHEATS SETTINGS"
|
||||
|
||||
namespace Game {
|
||||
extern SoHConfigType Settings;
|
||||
|
@ -673,7 +673,11 @@ static void gfx_opengl_resize_framebuffer(int fb, uint32_t width, uint32_t heigh
|
||||
|
||||
void gfx_opengl_set_framebuffer(int fb)
|
||||
{
|
||||
glClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE); // Set origin to upper left corner, to match N64 and DX11
|
||||
if (GLEW_ARB_clip_control || GLEW_VERSION_4_5) {
|
||||
// Set origin to upper left corner, to match N64 and DX11
|
||||
// If this function is not supported, the texture will be upside down :(
|
||||
glClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb);
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
@ -687,7 +691,9 @@ void gfx_opengl_reset_framebuffer(void)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer);
|
||||
glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
|
||||
if (GLEW_ARB_clip_control || GLEW_VERSION_4_5) {
|
||||
glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_opengl_select_texture_fb(int fbID)
|
||||
|
@ -7,12 +7,8 @@
|
||||
#include "Window.h"
|
||||
|
||||
extern "C" uint8_t __osMaxControllers;
|
||||
float gyroDriftX;
|
||||
float gyroDriftY;
|
||||
|
||||
namespace Ship {
|
||||
|
||||
|
||||
SDLController::SDLController(int32_t dwControllerNumber) : Controller(dwControllerNumber), Cont(nullptr), guid(INVALID_SDL_CONTROLLER_GUID) {
|
||||
|
||||
}
|
||||
@ -147,8 +143,8 @@ namespace Ship {
|
||||
//bound diagonals to an octagonal range {-68 ... +68}
|
||||
if (ax != 0.0 && ay != 0.0) {
|
||||
auto slope = ay / ax;
|
||||
auto edgex = copysign(85.0 / (abs(slope) + wAxisThreshold / 69.0), ax);
|
||||
auto edgey = copysign(std::min(abs(edgex * slope), 85.0 / (1.0 / abs(slope) + wAxisThreshold / 69.0)), ay);
|
||||
auto edgex = copysign(85.0 / (abs(slope) + 16.0 / 69.0), ax);
|
||||
auto edgey = copysign(std::min(abs(edgex * slope), 85.0 / (1.0 / abs(slope) + 16.0 / 69.0)), ay);
|
||||
edgex = edgey / slope;
|
||||
|
||||
auto scale = sqrt(edgex * edgex + edgey * edgey) / 85.0;
|
||||
@ -186,31 +182,31 @@ namespace Ship {
|
||||
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
|
||||
|
||||
const char* contName = SDL_GameControllerName(Cont);
|
||||
const int isSpecialController = strcmp("PS5 Controller", contName);
|
||||
const int isSpecialController = !strcmp("PS5 Controller", contName);
|
||||
const float gyroSensitivity = Game::Settings.controller.gyro_sensitivity;
|
||||
|
||||
if (gyroDriftX == 0) {
|
||||
if (isSpecialController == 0) {
|
||||
gyroDriftX = gyroData[2];
|
||||
if (Game::Settings.controller.gyroDriftX == 0) {
|
||||
Game::Settings.controller.gyroDriftX = gyroData[0];
|
||||
}
|
||||
|
||||
if (Game::Settings.controller.gyroDriftY == 0) {
|
||||
if (isSpecialController == 1) {
|
||||
Game::Settings.controller.gyroDriftY = gyroData[2];
|
||||
}
|
||||
else {
|
||||
gyroDriftX = gyroData[0];
|
||||
Game::Settings.controller.gyroDriftY = gyroData[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (gyroDriftY == 0) {
|
||||
gyroDriftY = gyroData[1];
|
||||
}
|
||||
|
||||
if (isSpecialController == 0) {
|
||||
wGyroX = gyroData[2] - gyroDriftX;
|
||||
if (isSpecialController == 1) {
|
||||
wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX;
|
||||
wGyroY = -gyroData[2] - Game::Settings.controller.gyroDriftY;
|
||||
}
|
||||
else {
|
||||
wGyroX = gyroData[0] - gyroDriftX;
|
||||
wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX;
|
||||
wGyroY = gyroData[1] - Game::Settings.controller.gyroDriftY;
|
||||
}
|
||||
|
||||
wGyroY = gyroData[1] - gyroDriftY;
|
||||
|
||||
wGyroX *= gyroSensitivity;
|
||||
wGyroY *= gyroSensitivity;
|
||||
}
|
||||
@ -340,11 +336,19 @@ namespace Ship {
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasLED(Cont)) {
|
||||
if (controller->ledColor == 1) {
|
||||
switch (controller->ledColor) {
|
||||
case 0:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 255, 0, 0);
|
||||
}
|
||||
else {
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0, 255, 0);
|
||||
break;
|
||||
case 1:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0x1E, 0x69, 0x1B);
|
||||
break;
|
||||
case 2:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0x64, 0x14, 0x00);
|
||||
break;
|
||||
case 3:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0x00, 0x3C, 0x64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -306,6 +306,14 @@ namespace SohImGui {
|
||||
if (ImGui::SliderFloat("##GYROSCOPE", &Game::Settings.controller.gyro_sensitivity, 0.0f, 1.0f, "")) {
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Recalibrate Gyro")) {
|
||||
Game::Settings.controller.gyroDriftX = 0;
|
||||
Game::Settings.controller.gyroDriftY = 0;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Rumble Strength: %d %%", static_cast<int>(100 * Game::Settings.controller.rumble_strength));
|
||||
if (ImGui::SliderFloat("##RUMBLE", &Game::Settings.controller.rumble_strength, 0.0f, 1.0f, "")) {
|
||||
needs_save = true;
|
||||
@ -350,20 +358,65 @@ namespace SohImGui {
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
ImGui::Text("Debugging");
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Checkbox("Debug Mode", &Game::Settings.enhancements.debug_mode)) {
|
||||
CVar_SetS32(const_cast<char*>("gDebugEnabled"), Game::Settings.enhancements.debug_mode);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Developer Tools")) {
|
||||
HOOK(ImGui::MenuItem("Stats", nullptr, &Game::Settings.debug.soh));
|
||||
HOOK(ImGui::MenuItem("Console", nullptr, &console->opened));
|
||||
|
||||
ImGui::Text("Debug");
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Checkbox("Debug Mode", &Game::Settings.cheats.debug_mode)) {
|
||||
CVar_SetS32(const_cast<char*>("gDebugEnabled"), Game::Settings.cheats.debug_mode);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Cheats")) {
|
||||
if (ImGui::Checkbox("Infinite Money", &Game::Settings.cheats.infinite_money)) {
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteMoney"), Game::Settings.cheats.infinite_money);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Infinite Health", &Game::Settings.cheats.infinite_health)) {
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteHealth"), Game::Settings.cheats.infinite_health);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Infinite Ammo", &Game::Settings.cheats.infinite_ammo)) {
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteAmmo"), Game::Settings.cheats.infinite_ammo);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Infinite Magic", &Game::Settings.cheats.infinite_magic)) {
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteMagic"), Game::Settings.cheats.infinite_magic);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("No Clip", &Game::Settings.cheats.no_clip)) {
|
||||
CVar_SetS32(const_cast<char*>("gNoClip"), Game::Settings.cheats.no_clip);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Climb Everything", &Game::Settings.cheats.climb_everything)) {
|
||||
CVar_SetS32(const_cast<char*>("gClimbEverything"), Game::Settings.cheats.climb_everything);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Moon Jump on L", &Game::Settings.cheats.moon_jump_on_l)) {
|
||||
CVar_SetS32(const_cast<char*>("gMoonJumpOnL"), Game::Settings.cheats.moon_jump_on_l);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Super Tunic", &Game::Settings.cheats.super_tunic)) {
|
||||
CVar_SetS32(const_cast<char*>("gSuperTunic"), Game::Settings.cheats.super_tunic);
|
||||
needs_save = true;
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,14 @@ extern "C" {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char* controllerDb = "gamecontrollerdb.txt";
|
||||
int mappingsAdded = SDL_GameControllerAddMappingsFromFile(controllerDb);
|
||||
if (mappingsAdded >= 0) {
|
||||
SPDLOG_INFO("Added SDL game controllers from \"{}\" ({})", controllerDb, mappingsAdded);
|
||||
} else {
|
||||
SPDLOG_ERROR("Failed add SDL game controller mappings from \"{}\" ({})", controllerDb, SDL_GetError());
|
||||
}
|
||||
|
||||
// TODO: This for loop is debug. Burn it with fire.
|
||||
for (size_t i = 0; i < SDL_NumJoysticks(); i++) {
|
||||
if (SDL_IsGameController(i)) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<Root>
|
||||
<File Name="object_triforce_spot" Segment="6">
|
||||
<Array Name="gTriforceVtx" Count="32" Offset="0x0000">
|
||||
<Array Name="gTriforceVtx" Count="96" Offset="0x0000">
|
||||
<Vtx/>
|
||||
</Array>
|
||||
|
||||
|
@ -324,6 +324,75 @@ void GameState_Update(GameState* gameState) {
|
||||
func_800C49F4(gfxCtx);
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Cheats hooks
|
||||
// -----------------------
|
||||
|
||||
// Inf Money
|
||||
if (CVar_GetS32("gInfiniteMoney", 0) != 0) {
|
||||
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
|
||||
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
||||
}
|
||||
}
|
||||
|
||||
// Inf Health
|
||||
if (CVar_GetS32("gInfiniteHealth", 0) != 0) {
|
||||
if (gSaveContext.health < gSaveContext.healthCapacity) {
|
||||
gSaveContext.health = gSaveContext.healthCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
// Inf Ammo
|
||||
if (CVar_GetS32("gInfiniteAmmo", 0) != 0) {
|
||||
// Deku Sticks
|
||||
if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) {
|
||||
AMMO(ITEM_STICK) = CUR_CAPACITY(UPG_STICKS);
|
||||
}
|
||||
|
||||
// Deku Nuts
|
||||
if (AMMO(ITEM_NUT) < CUR_CAPACITY(UPG_NUTS)) {
|
||||
AMMO(ITEM_NUT) = CUR_CAPACITY(UPG_NUTS);
|
||||
}
|
||||
|
||||
// Bombs
|
||||
if (AMMO(ITEM_BOMB) < CUR_CAPACITY(UPG_BOMB_BAG)) {
|
||||
AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG);
|
||||
}
|
||||
|
||||
// Fairy Bow (Ammo)
|
||||
if (AMMO(ITEM_BOW) < CUR_CAPACITY(UPG_QUIVER)) {
|
||||
AMMO(ITEM_BOW) = CUR_CAPACITY(UPG_QUIVER);
|
||||
}
|
||||
|
||||
// Fairy Slingshot (Ammo)
|
||||
if (AMMO(ITEM_SLINGSHOT) < CUR_CAPACITY(UPG_BULLET_BAG)) {
|
||||
AMMO(ITEM_SLINGSHOT) = CUR_CAPACITY(UPG_BULLET_BAG);
|
||||
}
|
||||
|
||||
// Bombchus (max: 50, no upgrades)
|
||||
if (AMMO(ITEM_BOMBCHU) < 50) {
|
||||
AMMO(ITEM_BOMBCHU) = 50;
|
||||
}
|
||||
}
|
||||
|
||||
// Inf Magic
|
||||
if (CVar_GetS32("gInfiniteMagic", 0) != 0) {
|
||||
if (gSaveContext.magicAcquired && gSaveContext.magic != (gSaveContext.doubleMagic + 1) * 0x30) {
|
||||
gSaveContext.magic = (gSaveContext.doubleMagic + 1) * 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
// Moon Jump On L
|
||||
if (CVar_GetS32("gMoonJumpOnL", 0) != 0) {
|
||||
if (gGlobalCtx) {
|
||||
Player* player = GET_PLAYER(gGlobalCtx);
|
||||
|
||||
if (CHECK_BTN_ANY(gGlobalCtx->state.input[0].cur.button, BTN_L)) {
|
||||
player->actor.velocity.y = 6.34375f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gameState->frames++;
|
||||
}
|
||||
|
||||
|
@ -272,9 +272,19 @@ void PadMgr_ProcessInputs(PadMgr* padMgr) {
|
||||
controllerCallback.rumble = padMgr->rumbleEnable[0] > 0 ? 1 : 0;
|
||||
|
||||
if (HealthMeter_IsCritical()) {
|
||||
controllerCallback.ledColor = 1;
|
||||
} else {
|
||||
controllerCallback.ledColor = 0;
|
||||
} else if (gGlobalCtx) {
|
||||
switch (CUR_EQUIP_VALUE(EQUIP_TUNIC) - 1) {
|
||||
case PLAYER_TUNIC_KOKIRI:
|
||||
controllerCallback.ledColor = 1;
|
||||
break;
|
||||
case PLAYER_TUNIC_GORON:
|
||||
controllerCallback.ledColor = 2;
|
||||
break;
|
||||
case PLAYER_TUNIC_ZORA:
|
||||
controllerCallback.ledColor = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OTRControllerCallback(&controllerCallback);
|
||||
|
@ -1874,6 +1874,10 @@ s32 BgCheck_CheckWallImpl(CollisionContext* colCtx, u16 xpFlags, Vec3f* posResul
|
||||
s32 bgId2;
|
||||
f32 nx, ny, nz; // unit normal of polygon
|
||||
|
||||
if (CVar_GetS32("gNoClip", 0) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
result = false;
|
||||
*outBgId = BGCHECK_SCENE;
|
||||
*outPoly = NULL;
|
||||
@ -3996,7 +4000,11 @@ u32 func_80041D94(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
|
||||
* SurfaceType Get Wall Flags
|
||||
*/
|
||||
s32 func_80041DB8(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
|
||||
return D_80119D90[func_80041D94(colCtx, poly, bgId)];
|
||||
if (CVar_GetS32("gClimbEverything", 0) != 0) {
|
||||
return (1 << 3) | D_80119D90[func_80041D94(colCtx, poly, bgId)];
|
||||
} else {
|
||||
return D_80119D90[func_80041D94(colCtx, poly, bgId)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4078,11 +4078,11 @@ void Interface_Update(GlobalContext* globalCtx) {
|
||||
D_80125A58 = func_8008F2F8(globalCtx);
|
||||
|
||||
if (D_80125A58 == 1) {
|
||||
if (CUR_EQUIP_VALUE(EQUIP_TUNIC) == 2) {
|
||||
if (CUR_EQUIP_VALUE(EQUIP_TUNIC) == 2 || CVar_GetS32("gSuperTunic", 0) != 0) {
|
||||
D_80125A58 = 0;
|
||||
}
|
||||
} else if ((func_8008F2F8(globalCtx) >= 2) && (func_8008F2F8(globalCtx) < 5)) {
|
||||
if (CUR_EQUIP_VALUE(EQUIP_TUNIC) == 3) {
|
||||
if (CUR_EQUIP_VALUE(EQUIP_TUNIC) == 3 || CVar_GetS32("gSuperTunic", 0) != 0) {
|
||||
D_80125A58 = 0;
|
||||
}
|
||||
}
|
||||
|
@ -631,9 +631,9 @@ s32 func_8008F2F8(GlobalContext* globalCtx) {
|
||||
if (0) {}
|
||||
|
||||
if ((triggerEntry->flag != 0) && !(gSaveContext.textTriggerFlags & triggerEntry->flag) &&
|
||||
(((var == 0) && (this->currentTunic != PLAYER_TUNIC_GORON)) ||
|
||||
(((var == 0) && (this->currentTunic != PLAYER_TUNIC_GORON && CVar_GetS32("gSuperTunic", 0) == 0)) ||
|
||||
(((var == 1) || (var == 3)) && (this->currentBoots == PLAYER_BOOTS_IRON) &&
|
||||
(this->currentTunic != PLAYER_TUNIC_ZORA)))) {
|
||||
(this->currentTunic != PLAYER_TUNIC_ZORA && CVar_GetS32("gSuperTunic", 0) == 0)))) {
|
||||
Message_StartTextbox(globalCtx, triggerEntry->textId, NULL);
|
||||
gSaveContext.textTriggerFlags |= triggerEntry->flag;
|
||||
}
|
||||
@ -1590,7 +1590,7 @@ void func_80091A24(GlobalContext* globalCtx, void* seg04, void* seg06, SkelAnime
|
||||
sp12C[0] = sword;
|
||||
sp12C[1] = shield;
|
||||
|
||||
Matrix_SetTranslateRotateYXZ(pos->x - (LINK_AGE_IN_YEARS == YEARS_ADULT ? 25 : 0),
|
||||
Matrix_SetTranslateRotateYXZ(pos->x - ((CVar_GetS32("gPauseLiveLink", 0) && LINK_AGE_IN_YEARS == YEARS_ADULT) ? 25 : 0),
|
||||
pos->y - (CVar_GetS32("gPauseTriforce", 0) ? 16 : 0), pos->z, rot);
|
||||
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
|
||||
|
||||
|
@ -300,7 +300,7 @@ void EnKusa_Main(EnKusa* this, GlobalContext* globalCtx) {
|
||||
if (Actor_HasParent(&this->actor, globalCtx)) {
|
||||
EnKusa_SetupLiftedUp(this);
|
||||
SoundSource_PlaySfxAtFixedWorldPos(globalCtx, &this->actor.world.pos, 20, NA_SE_PL_PULL_UP_PLANT);
|
||||
} else if (this->collider.base.acFlags & AC_HIT) {
|
||||
} else if (this->collider.base.acFlags & AC_HIT && gGlobalCtx->csCtx.state == 0) {
|
||||
this->collider.base.acFlags &= ~AC_HIT;
|
||||
EnKusa_SpawnFragments(this, globalCtx);
|
||||
EnKusa_DropCollectible(this, globalCtx);
|
||||
|
@ -2321,9 +2321,7 @@ s32 func_8083501C(Player* this, GlobalContext* globalCtx) {
|
||||
if ((!Player_HoldsHookshot(this) || func_80834FBC(this)) && !func_80834758(globalCtx, this) &&
|
||||
!func_80834F2C(this, globalCtx)) {
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (this->rideActor != NULL) {
|
||||
this->unk_6AD = 2; // OTRTODO: THIS IS A BAD IDEA BUT IT FIXES THE HORSE FIRST PERSON?
|
||||
}
|
||||
|
||||
@ -3842,12 +3840,12 @@ s32 func_808382DC(Player* this, GlobalContext* globalCtx) {
|
||||
s32 sp48 = func_80838144(D_808535E4);
|
||||
|
||||
if (((this->actor.wallPoly != NULL) &&
|
||||
SurfaceType_IsWallDamage(&globalCtx->colCtx, this->actor.wallPoly, this->actor.wallBgId)) ||
|
||||
SurfaceType_IsWallDamage(&globalCtx->colCtx, this->actor.wallPoly, this->actor.wallBgId)) ||
|
||||
((sp48 >= 0) &&
|
||||
SurfaceType_IsWallDamage(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId) &&
|
||||
(this->unk_A79 >= D_808544F4[sp48])) ||
|
||||
((sp48 >= 0) &&
|
||||
((this->currentTunic != PLAYER_TUNIC_GORON) || (this->unk_A79 >= D_808544F4[sp48])))) {
|
||||
((this->currentTunic != PLAYER_TUNIC_GORON && CVar_GetS32("gSuperTunic", 0) == 0) || (this->unk_A79 >= D_808544F4[sp48])))) {
|
||||
this->unk_A79 = 0;
|
||||
this->actor.colChkInfo.damage = 4;
|
||||
func_80837C0C(globalCtx, this, 0, 4.0f, 5.0f, this->actor.shape.rot.y, 20);
|
||||
@ -4632,7 +4630,7 @@ s32 func_8083A6AC(Player* this, GlobalContext* globalCtx) {
|
||||
|
||||
if (BgCheck_EntityLineTest1(&globalCtx->colCtx, &this->actor.world.pos, &sp74, &sp68, &sp84, true, false, false,
|
||||
true, &sp80) &&
|
||||
(ABS(sp84->normal.y) < 600)) {
|
||||
((ABS(sp84->normal.y) < 600) || (CVar_GetS32("gClimbEverything", 0) != 0))) {
|
||||
f32 nx = COLPOLY_GET_NORMAL(sp84->normal.x);
|
||||
f32 ny = COLPOLY_GET_NORMAL(sp84->normal.y);
|
||||
f32 nz = COLPOLY_GET_NORMAL(sp84->normal.z);
|
||||
@ -8152,7 +8150,7 @@ static struct_80832924 D_808545F0[] = {
|
||||
};
|
||||
|
||||
void func_80843CEC(Player* this, GlobalContext* globalCtx) {
|
||||
if (this->currentTunic != PLAYER_TUNIC_GORON) {
|
||||
if (this->currentTunic != PLAYER_TUNIC_GORON && CVar_GetS32("gSuperTunic", 0) == 0) {
|
||||
if ((globalCtx->roomCtx.curRoom.unk_02 == 3) || (D_808535E4 == 9) ||
|
||||
((func_80838144(D_808535E4) >= 0) &&
|
||||
!SurfaceType_IsWallDamage(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId))) {
|
||||
@ -9888,7 +9886,7 @@ void func_80847BA0(GlobalContext* globalCtx, Player* this) {
|
||||
if ((this->actor.bgCheckFlags & 0x200) && (D_80853608 < 0x3000)) {
|
||||
CollisionPoly* wallPoly = this->actor.wallPoly;
|
||||
|
||||
if (ABS(wallPoly->normal.y) < 600) {
|
||||
if ((ABS(wallPoly->normal.y) < 600) || (CVar_GetS32("gClimbEverything", 0) != 0)) {
|
||||
f32 sp8C = COLPOLY_GET_NORMAL(wallPoly->normal.x);
|
||||
f32 sp88 = COLPOLY_GET_NORMAL(wallPoly->normal.y);
|
||||
f32 sp84 = COLPOLY_GET_NORMAL(wallPoly->normal.z);
|
||||
@ -10188,7 +10186,7 @@ void func_80848C74(GlobalContext* globalCtx, Player* this) {
|
||||
s32 sp58;
|
||||
s32 sp54;
|
||||
|
||||
if (this->currentTunic == PLAYER_TUNIC_GORON) {
|
||||
if (this->currentTunic == PLAYER_TUNIC_GORON || CVar_GetS32("gSuperTunic", 0) != 0) {
|
||||
sp54 = 20;
|
||||
}
|
||||
else {
|
||||
|
Loading…
Reference in New Issue
Block a user