Skip to content

Commit

Permalink
[Holiday] Custom rainbows (HarbourMasters#4698)
Browse files Browse the repository at this point in the history
* [Holiday] Custom rainbows

* Update soh/soh/Enhancements/Holiday/LL.h

Co-authored-by: briaguya <[email protected]>

---------

Co-authored-by: briaguya <[email protected]>
  • Loading branch information
lilacLunatic and briaguya-ai authored Dec 17, 2024
1 parent a10b4d0 commit d725125
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 3 deletions.
129 changes: 129 additions & 0 deletions soh/soh/Enhancements/Holiday/LL.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "Holiday.hpp"
#include "LL.h"

extern "C" {
#include "macros.h"
#include "functions.h"
#include "variables.h"
extern PlayState* gPlayState;

// TODO: Include anything you need here from C land
}

// TODO: Change this to YourName
#define AUTHOR "LL"
#define CVAR(v) "gHoliday." AUTHOR "." v

static ImVec4 customColorZero = RAINBOW_PRESETS[0][0];
static ImVec4 customColorOne = RAINBOW_PRESETS[0][1];
static ImVec4 customColorMinusZero = RAINBOW_PRESETS[0][2];
static ImVec4 customColorMinusOne = RAINBOW_PRESETS[0][3];

ImVec4 Color_LUSToImGui(Color_RGBA8 color) {
ImVec4 result;

result.x = color.r / 255.0f;
result.y = color.g / 255.0f;
result.z = color.b / 255.0f;
result.w = color.a / 255.0f;

return result;
}

Color_RGBA8 Color_ImGuiToLUS(ImVec4 color) {
Color_RGBA8 result;

result.r = static_cast<uint8_t>(color.x * 255);
result.g = static_cast<uint8_t>(color.y * 255);
result.b = static_cast<uint8_t>(color.z * 255);
result.a = static_cast<uint8_t>(color.w * 255);

return result;
}

static void OnConfigurationChanged() {
Color_RGBA8 c1 = CVarGetColor(CVAR("lCustomRainbow1"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][0]));
Color_RGBA8 c2 = CVarGetColor(CVAR("lCustomRainbow2"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][1]));
Color_RGBA8 c3 = CVarGetColor(CVAR("lCustomRainbow3"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][2]));
Color_RGBA8 c4 = CVarGetColor(CVAR("lCustomRainbow4"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][3]));

customColorZero = Color_LUSToImGui((Color_RGBA8)c1);
customColorOne = Color_LUSToImGui((Color_RGBA8)c2);
customColorMinusZero = Color_LUSToImGui((Color_RGBA8)c3);
customColorMinusOne = Color_LUSToImGui((Color_RGBA8)c4);

// TODO: Register any hooks or things that need to run on startup and when the main CVar is toggled
// Note: Hooks should be registered/unregistered depending on the CVar state (Use COND_HOOK or COND_ID_HOOK)

// COND_HOOK(OnSceneSpawnActors, CVarGetInteger(CVAR("Enabled"), 0), []() {
// // Spawn your own actors?
// });

// COND_ID_HOOK(OnActorInit, ACTOR_OBJ_TSUBO, CVarGetInteger(CVAR("DoSomethingWithPots"), 0), [](void* actorRef) {
// // Do something with pots?
// });
}

static void DrawMenu() {
ImGui::SeparatorText(AUTHOR);
if (ImGui::BeginMenu("Customize Rainbows")) {
UIWidgets::EnhancementCheckbox("Enable", CVAR("lEnableCustomRainbows"));
if (CVarGetInteger(CVAR("lEnableCustomRainbows"), 0)) {
ImGui::ColorEdit3("Color 1", (float*)&customColorZero, ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit3("Color 2", (float*)&customColorOne, ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit3("Color 3", (float*)&customColorMinusZero, ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit3("Color 4", (float*)&customColorMinusOne, ImGuiColorEditFlags_NoInputs);

UIWidgets::PaddedText("Presets", true, false);
size_t rainbowPresetIdx = 0;
if (UIWidgets::EnhancementCombobox(CVAR("lCustomRainbowPreset"), RAINBOW_PRESET_NAMES, 0) &&
(rainbowPresetIdx = CVarGetInteger(CVAR("lCustomRainbowPreset"), 0)) <= RAINBOW_PRESET_LEN) { //paranoia
customColorZero = RAINBOW_PRESETS[rainbowPresetIdx][0];
customColorOne = RAINBOW_PRESETS[rainbowPresetIdx][1];
customColorMinusZero = RAINBOW_PRESETS[rainbowPresetIdx][2];
customColorMinusOne = RAINBOW_PRESETS[rainbowPresetIdx][3];
}

Color_RGBA8 color1, color2, color3, color4;
color1.r = static_cast<uint8_t>(customColorZero.x * 255.0f);
color1.g = static_cast<uint8_t>(customColorZero.y * 255.0f);
color1.b = static_cast<uint8_t>(customColorZero.z * 255.0f);

color2.r = static_cast<uint8_t>(customColorOne.x * 255.0f);
color2.g = static_cast<uint8_t>(customColorOne.y * 255.0f);
color2.b = static_cast<uint8_t>(customColorOne.z * 255.0f);

color3.r = static_cast<uint8_t>(customColorMinusZero.x * 255.0f);
color3.g = static_cast<uint8_t>(customColorMinusZero.y * 255.0f);
color3.b = static_cast<uint8_t>(customColorMinusZero.z * 255.0f);

color4.r = static_cast<uint8_t>(customColorMinusOne.x * 255.0f);
color4.g = static_cast<uint8_t>(customColorMinusOne.y * 255.0f);
color4.b = static_cast<uint8_t>(customColorMinusOne.z * 255.0f);

CVarSetColor(CVAR("lCustomRainbow1"), color1);
CVarSetColor(CVAR("lCustomRainbow2"), color2);
CVarSetColor(CVAR("lCustomRainbow3"), color3);
CVarSetColor(CVAR("lCustomRainbow4"), color4);

OnConfigurationChanged();
}

ImGui::EndMenu();

}
//if (UIWidgets::EnhancementCheckbox("DoSomethingWithPots", CVAR("DoSomethingWithPots"))) {
// OnConfigurationChanged();
//}
}

static void RegisterMod() {
// #region Leave this alone unless you know what you are doing
OnConfigurationChanged();
// #endregion

// TODO: Anything you want to run once on startup
}

// TODO: Uncomment this line to enable the mod
static Holiday holiday(DrawMenu, RegisterMod);
86 changes: 86 additions & 0 deletions soh/soh/Enhancements/Holiday/LL.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#ifndef LL_H
#define LL_H

#include "soh/Enhancements/cosmetics/CosmeticsEditor.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"

const size_t RAINBOW_PRESET_LEN = 9;

static const char* RAINBOW_PRESET_NAMES[RAINBOW_PRESET_LEN] = {
"Christmas",
"Transgender",
"Nonbinary",
"Bisexual",
"Lesbian",
"Gay (MLM)",
"Asexual",
"Brazil",
"Italy"
};

static const ImVec4 RAINBOW_PRESETS[RAINBOW_PRESET_LEN][4] = {
{ //christmas
{0.0/255.0, 140.0/255.0, 69.0/255.0, 0},
{205.0/255.0, 33.0/255.0, 42.0/255.0, 0},
{0.0/255.0, 140.0/255.0, 69.0/255.0, 0},
{205.0/255.0, 33.0/255.0, 42.0/255.0, 0}
},
{ //trans
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{255.0/255.0, 159.0/255.0, 186.0/255.0, 0},
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{71.0/255.0, 186.0/255.0, 230.0/255.0, 0}
},

{ //enby
{252.0/255.0, 244.0/255.0, 52.0/255.0, 0},
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{156.0/255.0, 89.0/255.0, 209.0/255.0, 0},
{0.0/255.0, 0.0/255.0, 0.0/255.0, 0}
},

{ //bi
{155.0/255.0, 79.0/255.0, 150.0/255.0, 0},
{0.0/255.0, 56.0/255.0, 168.0/255.0, 0},
{155.0/255.0, 79.0/255.0, 150.0/255.0, 0},
{214.0/255.0, 2.0/255.0, 112.0/255.0, 0}
},

{ //lesbian
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{213.0/255.0, 45.0/255.0, 0.0/255.0, 0},
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{163.0/255.0, 2.0/255.0, 98.0/255.0, 0}
},

{ //gay
{7.0/255.0, 141.0/255.0, 112.0/255.0, 0},
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{123.0/255.0, 173.0/255.0, 226.0/255.0, 0},
{61.0/255.0, 26.0/255.0, 120.0/255.0, 0}
},

{ //ace
{0.0/255.0, 0.0/255.0, 0.0/255.0, 0},
{163.0/255.0, 163.0/255.0, 163.0/255.0, 0},
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{128.0/255.0, 0.0/255.0, 128.0/255.0, 0}
},

{ //br
{0.0/255.0, 151.0/255.0, 57.0/255.0, 0},
{254.0/255.0, 221.0/255.0, 0.0/255.0, 0},
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{1.0/255.0, 33.0/255.0, 105.0/255.0, 0}
},

{ //it
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{0.0/255.0, 140.0/255.0, 69.0/255.0, 0},
{255.0/255.0, 255.0/255.0, 255.0/255.0, 0},
{205.0/255.0, 33.0/255.0, 42.0/255.0, 0}
}

};

#endif
42 changes: 39 additions & 3 deletions soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@ void ResetPositionAll() {

int hue = 0;

#define CVAR_LL(v) "gHoliday." "LL" "." v

// Runs every frame to update rainbow hue, a potential future optimization is to only run this a once or twice a second and increase the speed of the rainbow hue rotation.
void CosmeticsUpdateTick() {
int index = 0;
Expand All @@ -501,10 +503,44 @@ void CosmeticsUpdateTick() {
if (cosmeticOption.supportsRainbow && CVarGetInteger(cosmeticOption.rainbowCvar, 0)) {
double frequency = 2 * M_PI / (360 * rainbowSpeed);
Color_RGBA8 newColor;
newColor.r = static_cast<uint8_t>(sin(frequency * (hue + index) + 0) * 127) + 128;
newColor.g = static_cast<uint8_t>(sin(frequency * (hue + index) + (2 * M_PI / 3)) * 127) + 128;
newColor.b = static_cast<uint8_t>(sin(frequency * (hue + index) + (4 * M_PI / 3)) * 127) + 128;

newColor.a = 255;

if (!CVarGetInteger(CVAR_LL("lEnableCustomRainbows"), 0)) {
newColor.r = static_cast<uint8_t>(sin(frequency * (hue + index) + 0) * 127) + 128;
newColor.g = static_cast<uint8_t>(sin(frequency * (hue + index) + (2 * M_PI / 3)) * 127) + 128;
newColor.b = static_cast<uint8_t>(sin(frequency * (hue + index) + (4 * M_PI / 3)) * 127) + 128;
}
else {
Color_RGBA8 customColorZero = CVarGetColor(CVAR_LL("lCustomRainbow1"), {});
Color_RGBA8 customColorOne = CVarGetColor(CVAR_LL("lCustomRainbow2"), {});
Color_RGBA8 customColorMinusZero = CVarGetColor(CVAR_LL("lCustomRainbow3"), {});
Color_RGBA8 customColorMinusOne = CVarGetColor(CVAR_LL("lCustomRainbow4"), {});
float sinangle = sin(frequency * (hue + index));
bool quadrant1 = hue <= (360 * rainbowSpeed) / 4;
bool quadrant2 = hue >= (360 * rainbowSpeed) / 4 && hue <= (360 * rainbowSpeed) / 2;
bool quadrant3 = hue >= (360 * rainbowSpeed) / 2 && hue <= (360 * rainbowSpeed) * 3 / 4;
bool quadrant4 = hue >= (360 * rainbowSpeed) * 3 / 4;

if (quadrant1) { //zero to one
newColor.r = sinangle * (customColorOne.r - customColorZero.r) + customColorZero.r;
newColor.g = sinangle * (customColorOne.g - customColorZero.g) + customColorZero.g;
newColor.b = sinangle * (customColorOne.b - customColorZero.b) + customColorZero.b;
} else if (quadrant2) { //one to zero
newColor.r = sinangle * (customColorOne.r - customColorMinusZero.r) + customColorMinusZero.r;
newColor.g = sinangle * (customColorOne.g - customColorMinusZero.g) + customColorMinusZero.g;
newColor.b = sinangle * (customColorOne.b - customColorMinusZero.b) + customColorMinusZero.b;
} else if (quadrant3) { //zero to minus one
newColor.r = -sinangle * (customColorMinusOne.r - customColorMinusZero.r) + customColorMinusZero.r;
newColor.g = -sinangle * (customColorMinusOne.g - customColorMinusZero.g) + customColorMinusZero.g;
newColor.b = -sinangle * (customColorMinusOne.b - customColorMinusZero.b) + customColorMinusZero.b;
} else if (quadrant4) { //minus one to zero
newColor.r = -sinangle * (customColorMinusOne.r - customColorZero.r) + customColorZero.r;
newColor.g = -sinangle * (customColorMinusOne.g - customColorZero.g) + customColorZero.g;
newColor.b = -sinangle * (customColorMinusOne.b - customColorZero.b) + customColorZero.b;
}
}

// For alpha supported options, retain the last set alpha instead of overwriting
if (cosmeticOption.supportsAlpha) {
newColor.a = static_cast<uint8_t>(cosmeticOption.currentColor.w * 255.0f);
Expand Down

0 comments on commit d725125

Please sign in to comment.