Skip to content

Commit

Permalink
Cosmetics: Add rainbow tunic option (#713)
Browse files Browse the repository at this point in the history
* Rainbow Tunic settings

* formatting
  • Loading branch information
HylianFreddy authored Jan 30, 2024
1 parent e4d4603 commit 3d5291f
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 89 deletions.
42 changes: 42 additions & 0 deletions code/src/actors/player.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "arrow.h"
#include "grotto.h"
#include "item_override.h"
#include "colors.h"
#include "common.h"

#define PlayerActor_Init_addr 0x191844
#define PlayerActor_Init ((ActorFunc)PlayerActor_Init_addr)
Expand Down Expand Up @@ -167,6 +169,9 @@ void PlayerActor_rDraw(Actor* thisx, GlobalContext* globalCtx) {
PLAYER->sheathDLists = PlayerDListGroup_EmptySheathChildWithHylianShield;
}
}

Player_UpdateRainbowTunic();

PlayerActor_Draw(thisx, globalCtx);
}

Expand Down Expand Up @@ -211,3 +216,40 @@ s32 Player_CanPickUpThisActor(Actor* interactedActor) {
return 1;
}
}

#define TUNIC_CYCLE_FRAMES 30
void Player_UpdateRainbowTunic(void) {
u8 currentTunic = (gSaveContext.equips.equipment >> 8) & 3;
s16 exObjectBankIdx = Object_GetIndex(&rExtendedObjectCtx, OBJECT_CUSTOM_GENERAL_ASSETS);
void* cmabManager;
char* cmabChunk;
u8 redOffset, greenOffset, blueOffset;

if (gSaveContext.linkAge == AGE_CHILD) {
if (gSettingsContext.rainbowChildTunic == OFF) {
return;
}
cmabManager = ZAR_GetCMABByIndex(&rExtendedObjectCtx.status[exObjectBankIdx].zarInfo, TEXANIM_CHILD_LINK_BODY);
redOffset = 0x70;
greenOffset = 0x88;
blueOffset = 0xA0;
} else { // AGE_ADULT
if ((currentTunic == 1 && gSettingsContext.rainbowKokiriTunic == OFF) ||
(currentTunic == 2 && gSettingsContext.rainbowGoronTunic == OFF) ||
(currentTunic == 3 && gSettingsContext.rainbowZoraTunic == OFF)) {
return;
}
cmabManager = ZAR_GetCMABByIndex(&rExtendedObjectCtx.status[exObjectBankIdx].zarInfo, TEXANIM_LINK_BODY);
redOffset = 0x70 + 8 * (currentTunic - 1);
greenOffset = 0x98 + 8 * (currentTunic - 1);
blueOffset = 0xC0 + 8 * (currentTunic - 1);
}

cmabChunk = *((char**)cmabManager);

Color_RGBA8 color = Colors_GetRainbowColor(rGameplayFrames, TUNIC_CYCLE_FRAMES);

*(f32*)(cmabChunk + redOffset) = color.r / 255.0f;
*(f32*)(cmabChunk + greenOffset) = color.g / 255.0f;
*(f32*)(cmabChunk + blueOffset) = color.b / 255.0f;
}
1 change: 1 addition & 0 deletions code/src/actors/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ void PlayerActor_rInit(Actor* thisx, GlobalContext* globalCtx);
void PlayerActor_rUpdate(Actor* thisx, GlobalContext* globalCtx);
void PlayerActor_rDestroy(Actor* thisx, GlobalContext* globalCtx);
void PlayerActor_rDraw(Actor* thisx, GlobalContext* globalCtx);
void Player_UpdateRainbowTunic(void);

#endif //_PLAYER_H_
51 changes: 38 additions & 13 deletions code/src/colors.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
#include "z3D/z3D.h"
#include "colors.h"
#include "common.h"

void Colors_ChangeRainbowColorRGBAf(Color_RGBAf* color, float speed, float max) {
if (color->r >= max && color->g < max && color->b <= 0)
color->g += speed;
else if (color->r > 0 && color->g >= max && color->b <= 0)
color->r -= speed;
else if (color->r <= 0 && color->g >= max && color->b < max)
color->b += speed;
else if (color->r <= 0 && color->g > 0 && color->b >= max)
color->g -= speed;
else if (color->r < max && color->g <= 0 && color->b >= max)
color->r += speed;
else if (color->r >= max && color->g <= 0 && color->b > 0)
color->b -= speed;
// This function is taken from OoTR:
// https://github.com/OoTRandomizer/OoT-Randomizer/blob/1827fbb8089d3fe3e816a297a5f3ce2c99a6e0c5/ASM/c/rainbow.c
Color_RGBA8 Colors_GetRainbowColor(u32 curFrame, u32 stepFrames) {
static Color_RGBA8 cycleColors[] = {
{ 0xE0, 0x10, 0x10, 0x00 }, // red
{ 0xE0, 0xE0, 0x10, 0x00 }, // yellow
{ 0x10, 0xE0, 0x10, 0x00 }, // green
{ 0x10, 0xE0, 0xE0, 0x00 }, // cyan
{ 0x10, 0x10, 0xE0, 0x00 }, // blue
{ 0xE0, 0x10, 0xE0, 0x00 }, // purple
{ 0xE0, 0x10, 0x10, 0x00 }, // red
};

int index;
float tweenA, tweenB;

index = (curFrame / stepFrames) % 6;

tweenB = ((f32)(curFrame % stepFrames) / stepFrames);
tweenA = 1 - tweenB;

Color_RGBA8 cA = cycleColors[index];
Color_RGBA8 cB = cycleColors[index + 1];

Color_RGBA8 ret;
ret.r = (u8)((cA.r * tweenA) + (cB.r * tweenB));
ret.g = (u8)((cA.g * tweenA) + (cB.g * tweenB));
ret.b = (u8)((cA.b * tweenA) + (cB.b * tweenB));
ret.a = 0xFF;
return ret;
}

void Colors_ChangeRainbowColorRGBA8(Color_RGBA8* color, u32 stepFrames, u8 stepOffset) {
Color_RGBA8 newColor = Colors_GetRainbowColor(rGameplayFrames + stepOffset * stepFrames, stepFrames);
color->r = newColor.r;
color->g = newColor.g;
color->b = newColor.b;
}
5 changes: 4 additions & 1 deletion code/src/colors.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ typedef struct {
f32 r, g, b, a;
} Color_RGBAf;

void Colors_ChangeRainbowColorRGBAf(Color_RGBAf* color, float speed, float max);
Color_RGBA8 Colors_GetRainbowColor(u32 curFrame, u32 stepFrames);

// Function to change rainbow color without affecting alpha component.
void Colors_ChangeRainbowColorRGBA8(Color_RGBA8* color, u32 stepFrames, u8 stepOffset);

#endif //_COLORS_H_
2 changes: 2 additions & 0 deletions code/src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#define TICKS_PER_SEC 268123480
#define SEQ_AUDIO_BLANK 0x1000142

extern u32 rGameplayFrames; // globalCtx->gameplayFrames is not accurate, it doesn't increment on file 3

/// Returns 1 if the bit is set in value1 but not in value2, -1 if vice versa, and 0 if they're the same
s8 BitCompare(u32 value1, u32 value2, u8 bit);

Expand Down
51 changes: 18 additions & 33 deletions code/src/effects.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,35 +45,16 @@ s32 forceTrailEffectUpdate(EffectBlure* effect) {
return effect->numElements;
}

void changeRainbowColorRGBA8(Color_RGBA8* color) {
#define COLOR_SPEED 17 // 255 = 3*17*5
if (color->r == 0xFF && color->g != 0xFF && color->b == 0)
color->g += COLOR_SPEED;
else if (color->r != 0 && color->g == 0xFF && color->b == 0)
color->r -= COLOR_SPEED;
else if (color->r == 0 && color->g == 0xFF && color->b != 0xFF)
color->b += COLOR_SPEED;
else if (color->r == 0 && color->g != 0 && color->b == 0xFF)
color->g -= COLOR_SPEED;
else if (color->r != 0xFF && color->g == 0 && color->b == 0xFF)
color->r += COLOR_SPEED;
else if (color->r == 0xFF && color->g == 0 && color->b != 0)
color->b -= COLOR_SPEED;
else {
color->r = 0xFF;
color->g = 0;
color->b = 0;
}
}

#define SWORD_CYCLE_FRAMES_INNER 18
#define SWORD_CYCLE_FRAMES_OUTER 15
void updateSwordTrailColors(EffectBlure* effect) {
if (gSettingsContext.rainbowSwordTrailInnerColor) {
changeRainbowColorRGBA8(&effect->p2StartColor);
changeRainbowColorRGBA8(&effect->p2EndColor);
Colors_ChangeRainbowColorRGBA8(&effect->p2StartColor, SWORD_CYCLE_FRAMES_INNER, 0);
Colors_ChangeRainbowColorRGBA8(&effect->p2EndColor, SWORD_CYCLE_FRAMES_INNER, 0);
}
if (gSettingsContext.rainbowSwordTrailOuterColor) {
changeRainbowColorRGBA8(&effect->p1StartColor);
changeRainbowColorRGBA8(&effect->p1EndColor);
Colors_ChangeRainbowColorRGBA8(&effect->p1StartColor, SWORD_CYCLE_FRAMES_OUTER, 0);
Colors_ChangeRainbowColorRGBA8(&effect->p1EndColor, SWORD_CYCLE_FRAMES_OUTER, 0);
}
}

Expand Down Expand Up @@ -101,6 +82,8 @@ s32 handleLongTrails(u8 durationSetting, EffectBlure* effect, Vec3f* p1, Vec3f*
return 0;
}

#define BOOM_CYCLE_FRAMES_INNER 9
#define BOOM_CYCLE_FRAMES_OUTER 7
u32 updateBoomerangTrailEffect(EffectBlure* effect, Vec3f* p1, Vec3f* p2) {
u8 isRainbow = gSettingsContext.boomerangTrailColorMode == TRAILCOLOR_RAINBOW ||
gSettingsContext.boomerangTrailColorMode == TRAILCOLOR_RAINBOW_SIMPLEMODE;
Expand Down Expand Up @@ -154,24 +137,26 @@ u32 updateBoomerangTrailEffect(EffectBlure* effect, Vec3f* p1, Vec3f* p2) {
}

if (isRainbow) {
changeRainbowColorRGBA8(&effect->p2StartColor);
changeRainbowColorRGBA8(&effect->p2EndColor);
changeRainbowColorRGBA8(&effect->p1StartColor);
changeRainbowColorRGBA8(&effect->p1EndColor);
Colors_ChangeRainbowColorRGBA8(&effect->p2StartColor, BOOM_CYCLE_FRAMES_INNER, 0);
Colors_ChangeRainbowColorRGBA8(&effect->p2EndColor, BOOM_CYCLE_FRAMES_INNER, 2);
Colors_ChangeRainbowColorRGBA8(&effect->p1StartColor, BOOM_CYCLE_FRAMES_OUTER, 0);
Colors_ChangeRainbowColorRGBA8(&effect->p1EndColor, BOOM_CYCLE_FRAMES_OUTER, 2);
}

return handleLongTrails(gSettingsContext.boomerangTrailDuration, effect, p1, p2);
}

#define BOMBCHU_CYCLE_FRAMES_INNER 12
#define BOMBCHU_CYCLE_FRAMES_OUTER 9
u32 updateChuTrailColors(EffectBlure* effect, Vec3f* p1, Vec3f* p2) {

if (gSettingsContext.rainbowChuTrailInnerColor) {
changeRainbowColorRGBA8(&effect->p2StartColor);
changeRainbowColorRGBA8(&effect->p2EndColor);
Colors_ChangeRainbowColorRGBA8(&effect->p2StartColor, BOMBCHU_CYCLE_FRAMES_INNER, 0);
Colors_ChangeRainbowColorRGBA8(&effect->p2EndColor, BOMBCHU_CYCLE_FRAMES_INNER, 2);
}
if (gSettingsContext.rainbowChuTrailOuterColor) {
changeRainbowColorRGBA8(&effect->p1StartColor);
changeRainbowColorRGBA8(&effect->p1EndColor);
Colors_ChangeRainbowColorRGBA8(&effect->p1StartColor, BOMBCHU_CYCLE_FRAMES_OUTER, 0);
Colors_ChangeRainbowColorRGBA8(&effect->p1EndColor, BOMBCHU_CYCLE_FRAMES_OUTER, 2);
}

switch (gSettingsContext.bombchuTrailDuration) {
Expand Down
49 changes: 31 additions & 18 deletions code/src/fairy.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
#include "fairy.h"
#include "settings.h"
#include "objects.h"
#include "common.h"

#define NAVI_COLORS_ARRAY ((Color_RGBA8*)0x50C998)
#define FAIRY_COLOR_SPEED 17 // 255 = 3*17*5
#define FAIRY_COLOR_MAX 255.0f // max value for RGB components

#define NAVI_CYCLE_FRAMES_OUTER 18
#define NAVI_CYCLE_FRAMES_INNER 21

static u8 lastTargetActorType = 0;
// Data to manage the rainbow colors
Expand Down Expand Up @@ -45,31 +47,42 @@ u8 Fairy_IsNaviOuterRainbowForActorType(u8 type) {
}
}

void Fairy_ApplyColorToTargetCMAB(void* cmab, Color_RGBA8 color) {
void Fairy_ApplyColorToTargetCMAB(void* cmab, Color_RGBA8 color8) {
Color_RGBAf colorF = {
.r = color8.r / 255.0f,
.g = color8.g / 255.0f,
.b = color8.b / 255.0f,
.a = color8.a / 255.0f,
};

// keyframe 1
*(f32*)(cmab + 0x6C) = color.r / 255.0f;
*(f32*)(cmab + 0xAC) = color.g / 255.0f;
*(f32*)(cmab + 0xEC) = color.b / 255.0f;
*(f32*)(cmab + 0x6C) = colorF.r;
*(f32*)(cmab + 0xAC) = colorF.g;
*(f32*)(cmab + 0xEC) = colorF.b;
// keyframe 2
*(f32*)(cmab + 0x7C) = color.r / 255.0f;
*(f32*)(cmab + 0xBC) = color.g / 255.0f;
*(f32*)(cmab + 0xFC) = color.b / 255.0f;
*(f32*)(cmab + 0x7C) = colorF.r;
*(f32*)(cmab + 0xBC) = colorF.g;
*(f32*)(cmab + 0xFC) = colorF.b;
// keyframe 3
*(f32*)(cmab + 0x8C) = color.r / 255.0f;
*(f32*)(cmab + 0xCC) = color.g / 255.0f;
*(f32*)(cmab + 0x10C) = color.b / 255.0f;
*(f32*)(cmab + 0x8C) = colorF.r;
*(f32*)(cmab + 0xCC) = colorF.g;
*(f32*)(cmab + 0x10C) = colorF.b;
}

void Fairy_UpdateRainbowNaviColors(EnElf* navi) {
if (Fairy_IsNaviInnerRainbowForActorType(lastTargetActorType)) {
Colors_ChangeRainbowColorRGBAf(&(navi->innerColor), FAIRY_COLOR_SPEED, FAIRY_COLOR_MAX);
staticRainbowColor.r = navi->innerColor.r;
staticRainbowColor.g = navi->innerColor.g;
staticRainbowColor.b = navi->innerColor.b;
staticRainbowColor.a = 0xFF;
Color_RGBA8 newColor = Colors_GetRainbowColor(rGameplayFrames, NAVI_CYCLE_FRAMES_INNER);
staticRainbowColor = newColor;
// Navi color components go up to 255.0f instead of 1.0f
navi->innerColor.r = newColor.r / 1.0f;
navi->innerColor.g = newColor.g / 1.0f;
navi->innerColor.b = newColor.b / 1.0f;
}
if (Fairy_IsNaviOuterRainbowForActorType(lastTargetActorType)) {
Colors_ChangeRainbowColorRGBAf(&(navi->outerColor), FAIRY_COLOR_SPEED, FAIRY_COLOR_MAX);
Color_RGBA8 newColor = Colors_GetRainbowColor(rGameplayFrames, NAVI_CYCLE_FRAMES_OUTER);
navi->outerColor.r = newColor.r / 1.0f;
navi->outerColor.g = newColor.g / 1.0f;
navi->outerColor.b = newColor.b / 1.0f;
}

// Handle target pointer color
Expand Down
2 changes: 0 additions & 2 deletions code/src/fairy.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ typedef struct EnElf {
/* 0x938 */ Color_RGBAf outerColor;
} EnElf;

#define gNaviColorList ((NaviColor*)0x50C998)

void Fairy_UpdateRainbowNaviColors(EnElf* navi);
void Fairy_ResetRainbowCMABs(void);

Expand Down
2 changes: 2 additions & 0 deletions code/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

GlobalContext* gGlobalContext = NULL;
static u8 rRandomizerInit = 0;
u32 rGameplayFrames = 0;

void set_GlobalContext(GlobalContext* globalCtx) {
gGlobalContext = globalCtx;
Expand All @@ -39,6 +40,7 @@ void before_GlobalContext_Update(GlobalContext* globalCtx) {
set_GlobalContext(globalCtx);
rRandomizerInit = 1;
}
rGameplayFrames++;
ItemOverride_Update();
ActorSetup_Extra();
Model_UpdateAll(globalCtx);
Expand Down
4 changes: 4 additions & 0 deletions code/src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,10 @@ typedef struct {
u8 freeCamControl;

u8 customTunicColors;
u8 rainbowChildTunic;
u8 rainbowKokiriTunic;
u8 rainbowGoronTunic;
u8 rainbowZoraTunic;
u8 customNaviColors;
u8 rainbowIdleNaviInnerColor;
u8 rainbowNPCNaviInnerColor;
Expand Down
3 changes: 2 additions & 1 deletion source/cosmetics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const std::array<std::string_view, 13> gauntletColors = {
"5B8A06", // Lime
"800080", // Purple
};
const std::array<std::string_view, 28> tunicColors = {
const std::array<std::string_view, 29> tunicColors = {
"168A0E", // Kokiri Green
"96000E", // Goron Red
"002A8E", // Zora Blue
Expand Down Expand Up @@ -83,6 +83,7 @@ const std::array<std::string_view, 28> tunicColors = {
"52314F", // Mauve
"505A59", // Silver
"F16F16", // Gold
"FF0000", // Rainbow (placeholder)
};
const std::array<std::string_view, 20> naviInnerColors = {
"FFFFFF", // White
Expand Down
2 changes: 1 addition & 1 deletion source/cosmetics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct Color_RGBA8 {
};

extern const std::array<std::string_view, 13> gauntletColors;
extern const std::array<std::string_view, 28> tunicColors;
extern const std::array<std::string_view, 29> tunicColors;
extern const std::array<std::string_view, 20> naviInnerColors;
extern const std::array<std::string_view, 20> naviOuterColors;
extern const std::array<std::string_view, 13> weaponTrailColors;
Expand Down
Loading

0 comments on commit 3d5291f

Please sign in to comment.