Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cosmetics: Add rainbow tunic option #713

Merged
merged 2 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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