diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 3a475516bad..2b38f29f567 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -59,6 +59,8 @@ u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); } static WidgetInfo goronNeck; +static void RegisterBlueBloodHook(); +static void RegisterGreenBloodHook(); namespace SohGui { extern std::shared_ptr mSohMenu; @@ -97,6 +99,7 @@ std::map groupLabels = { { COSMETICS_GROUP_NAVI, "Navi" }, { COSMETICS_GROUP_IVAN, "Ivan" }, { COSMETICS_GROUP_MESSAGE, "Message" }, + { COSMETICS_GROUP_BLOOD, "Blood" }, }; static const std::unordered_map cosmeticsRandomizerModes = { @@ -420,6 +423,23 @@ static std::map cosmeticOptions = { COSMETIC_OPTION("SpinAttack.Level2Primary", "Level 2 Primary", COSMETICS_GROUP_SPIN_ATTACK, ColorRGBA8(255, 255, 170, 255), false, true, true), COSMETIC_OPTION("SpinAttack.Level2Secondary", "Level 2 Secondary", COSMETICS_GROUP_SPIN_ATTACK, ColorRGBA8(255, 100, 0, 255), false, true, false), + COSMETIC_OPTION("Blood.Blue0Begin", "Blue 0 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 10, 10, 200, 255), true, true, false), + COSMETIC_OPTION("Blood.Blue0End", "Blue 0 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 0, 32, 0), true, true, false), + COSMETIC_OPTION("Blood.Blue1Begin", "Blue 1 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 0, 128, 255), true, true, false), + COSMETIC_OPTION("Blood.Blue1End", "Blue 1 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 0, 32, 0), true, true, false), + COSMETIC_OPTION("Blood.Blue2Begin", "Blue 2 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 0, 128, 255), true, true, false), + COSMETIC_OPTION("Blood.Blue2End", "Blue 2 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 0, 64, 0), true, true, false), + COSMETIC_OPTION("Blood.Blue3Begin", "Blue 3 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 0, 128, 255), true, true, false), + COSMETIC_OPTION("Blood.Blue3End", "Blue 3 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 0, 64, 0), true, true, false), + COSMETIC_OPTION("Blood.Green0Begin", "Green 0 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 10, 200, 10, 255), true, true, false), + COSMETIC_OPTION("Blood.Green0End", "Green 0 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 32, 0, 0), true, true, false), + COSMETIC_OPTION("Blood.Green1Begin", "Green 1 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 128, 0, 255), true, true, false), + COSMETIC_OPTION("Blood.Green1End", "Green 1 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 32, 0, 0), true, true, false), + COSMETIC_OPTION("Blood.Green2Begin", "Green 2 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 128, 0, 255), true, true, false), + COSMETIC_OPTION("Blood.Green2End", "Green 2 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 64, 0, 0), true, true, false), + COSMETIC_OPTION("Blood.Green3Begin", "Green 3 Begin", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 128, 0, 255), true, true, false), + COSMETIC_OPTION("Blood.Green3End", "Green 3 End", COSMETICS_GROUP_BLOOD, ColorRGBA8( 0, 64, 0, 0), true, true, false), + COSMETIC_OPTION("Trails.Bombchu", "Bombchu", COSMETICS_GROUP_TRAILS, ColorRGBA8(250, 0, 0, 255), false, true, true), COSMETIC_OPTION("Trails.Boomerang", "Boomerang", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 100, 255), false, true, true), COSMETIC_OPTION("Trails.KokiriSword", "Kokiri Sword", COSMETICS_GROUP_TRAILS, ColorRGBA8(255, 255, 255, 255), false, true, false), @@ -1509,6 +1529,12 @@ void ApplyOrResetCustomGfxPatches(bool manualChange) { player->actor.scale.z = scale; } } + + // (Un)register Hooks + if (manualChange) { + RegisterBlueBloodHook(); + RegisterGreenBloodHook(); + } } extern "C" Color_RGBA8 CosmeticsEditor_GetDefaultValue(const char* id) { @@ -2528,6 +2554,7 @@ void CosmeticsEditorWindow::DrawElement() { DrawCosmeticGroup(COSMETICS_GROUP_MAGIC); DrawCosmeticGroup(COSMETICS_GROUP_ARROWS); DrawCosmeticGroup(COSMETICS_GROUP_SPIN_ATTACK); + DrawCosmeticGroup(COSMETICS_GROUP_BLOOD); DrawCosmeticGroup(COSMETICS_GROUP_TRAILS); if (UIWidgets::CVarSliderInt("Trails Duration: %d", CVAR_COSMETIC("Trails.Duration.Value"), UIWidgets::IntSliderOptions() @@ -2678,6 +2705,95 @@ void CosmeticsEditor_ResetGroup(CosmeticGroup group) { ApplyOrResetCustomGfxPatches(); } +static void SetBlueBloodColor(EffectSparkInit* effectSparkInit) { + Color_RGBA8 blue0begin = { 10, 10, 200, 255 }; + effectSparkInit->colorStart[0] = CVarGetColor(CVAR_COSMETIC("Blood.Blue0Begin.Value"), blue0begin); + Color_RGBA8 blue0end = { 0, 0, 32, 0 }; + effectSparkInit->colorEnd[0] = CVarGetColor(CVAR_COSMETIC("Blood.Blue0End.Value"), blue0end); + + Color_RGBA8 blue1begin = { 0, 0, 128, 255 }; + effectSparkInit->colorStart[1] = CVarGetColor(CVAR_COSMETIC("Blood.Blue1Begin.Value"), blue1begin); + Color_RGBA8 blue1end = { 0, 0, 32, 0 }; + effectSparkInit->colorEnd[1] = CVarGetColor(CVAR_COSMETIC("Blood.Blue1End.Value"), blue1end); + + Color_RGBA8 blue2begin = { 0, 0, 128, 255 }; + effectSparkInit->colorStart[2] = CVarGetColor(CVAR_COSMETIC("Blood.Blue2Begin.Value"), blue2begin); + Color_RGBA8 blue2end = { 0, 0, 64, 0 }; + effectSparkInit->colorEnd[2] = CVarGetColor(CVAR_COSMETIC("Blood.Blue2End.Value"), blue2end); + + Color_RGBA8 blue3begin = { 0, 0, 128, 255 }; + effectSparkInit->colorStart[3] = CVarGetColor(CVAR_COSMETIC("Blood.Blue3Begin.Value"), blue3begin); + Color_RGBA8 blue3end = { 0, 0, 64, 0 }; + effectSparkInit->colorEnd[3] = CVarGetColor(CVAR_COSMETIC("Blood.Blue3End.Value"), blue3end); +} + +static void SetGreenBloodColor(EffectSparkInit* effectSparkInit) { + Color_RGBA8 green0begin = { 10, 200, 10, 255 }; + effectSparkInit->colorStart[0] = CVarGetColor(CVAR_COSMETIC("Blood.Green0Begin.Value"), green0begin); + Color_RGBA8 green0end = { 0, 32, 0, 0 }; + effectSparkInit->colorEnd[0] = CVarGetColor(CVAR_COSMETIC("Blood.Green0End.Value"), green0end); + + Color_RGBA8 green1begin = { 0, 128, 0, 255 }; + effectSparkInit->colorStart[1] = CVarGetColor(CVAR_COSMETIC("Blood.Green1Begin.Value"), green1begin); + Color_RGBA8 green1end = { 0, 32, 0, 0 }; + effectSparkInit->colorEnd[1] = CVarGetColor(CVAR_COSMETIC("Blood.Green1End.Value"), green1end); + + Color_RGBA8 green2begin = { 0, 128, 0, 255 }; + effectSparkInit->colorStart[2] = CVarGetColor(CVAR_COSMETIC("Blood.Green2Begin.Value"), green2begin); + Color_RGBA8 green2end = { 0, 64, 0, 0 }; + effectSparkInit->colorEnd[2] = CVarGetColor(CVAR_COSMETIC("Blood.Green2End.Value"), green2end); + + Color_RGBA8 green3begin = { 0, 128, 0, 255 }; + effectSparkInit->colorStart[3] = CVarGetColor(CVAR_COSMETIC("Blood.Green3Begin.Value"), green3begin); + Color_RGBA8 green3end = { 0, 64, 0, 0 }; + effectSparkInit->colorEnd[3] = CVarGetColor(CVAR_COSMETIC("Blood.Green3End.Value"), green3end); +} + +static void RegisterBlueBloodHook() { + static bool previousHookState = false; // Previous hook enabled state (we don't re-register if unchanged) + bool hookEnabled = CVarGetInteger(CVAR_COSMETIC("Blood.Blue0Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Blue0End.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Blue1Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Blue1End.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Blue2Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Blue2End.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Blue3Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Blue3End.Changed"), 0); + + if (previousHookState != hookEnabled) { + previousHookState = hookEnabled; + + COND_VB_SHOULD(VB_BLOOD_SET_COLOR_BLUE, hookEnabled, { + EffectSparkInit* effectSparkInit = va_arg(args, EffectSparkInit*); + *should = false; // Don't run vanilla color set code + // Call a separate color set function (Inlining code here breaks COND_VB_SHOULD macro for some reason) + SetBlueBloodColor(effectSparkInit); + }); + } +} + +static void RegisterGreenBloodHook() { + static bool previousHookState = false; + bool hookEnabled = CVarGetInteger(CVAR_COSMETIC("Blood.Green0Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Green0End.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Green1Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Green1End.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Green2Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Green2End.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Green3Begin.Changed"), 0) || + CVarGetInteger(CVAR_COSMETIC("Blood.Green3End.Changed"), 0); + + if (previousHookState != hookEnabled) { + previousHookState = hookEnabled; + + COND_VB_SHOULD(VB_BLOOD_SET_COLOR_GREEN, hookEnabled, { + EffectSparkInit* effectSparkInit = va_arg(args, EffectSparkInit*); + *should = false; + SetGreenBloodColor(effectSparkInit); + }); + } +} + void RegisterCosmeticHooks() { COND_HOOK(OnGenerationCompletion, CVarGetInteger(CVAR_COSMETIC("RandomizeCosmeticsGenModes"), RANDOMIZE_OFF) == RANDOMIZE_ON_RANDO_GEN_ONLY, @@ -2716,7 +2832,31 @@ void RegisterCosmeticWidgets() { SohGui::mSohMenu->AddSearchWidget({ goronNeck, "Enhancements", "Cosmetics Editor", "Silly" }); } -static RegisterShipInitFunc initFunc(RegisterCosmeticHooks, { - CVAR_COSMETIC("RandomizeCosmeticsGenModes"), - }); +static RegisterShipInitFunc initFunc_BlueBlood(RegisterBlueBloodHook, { + CVAR_COSMETIC("Blood.Blue0Begin.Changed"), + CVAR_COSMETIC("Blood.Blue0End.Changed"), + CVAR_COSMETIC("Blood.Blue1Begin.Changed"), + CVAR_COSMETIC("Blood.Blue1End.Changed"), + CVAR_COSMETIC("Blood.Blue2Begin.Changed"), + CVAR_COSMETIC("Blood.Blue2End.Changed"), + CVAR_COSMETIC("Blood.Blue3Begin.Changed"), + CVAR_COSMETIC("Blood.Blue3End.Changed"), + }); + +static RegisterShipInitFunc initFunc_GreenBlood(RegisterGreenBloodHook, { + CVAR_COSMETIC("Blood.Green0Begin.Changed"), + CVAR_COSMETIC("Blood.Green0End.Changed"), + CVAR_COSMETIC("Blood.Green1Begin.Changed"), + CVAR_COSMETIC("Blood.Green1End.Changed"), + CVAR_COSMETIC("Blood.Green2Begin.Changed"), + CVAR_COSMETIC("Blood.Green2End.Changed"), + CVAR_COSMETIC("Blood.Green3Begin.Changed"), + CVAR_COSMETIC("Blood.Green3End.Changed"), + }); + +static RegisterShipInitFunc initFunc_CosmeticHooks(RegisterCosmeticHooks, + { + CVAR_COSMETIC("RandomizeCosmeticsGenModes"), + }); + static RegisterMenuInitFunc menuInitFunc(RegisterCosmeticWidgets); diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h index 7da88bdbc6b..7e1c59ca6a8 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h @@ -26,6 +26,7 @@ typedef enum { COSMETICS_GROUP_NAVI, COSMETICS_GROUP_IVAN, COSMETICS_GROUP_MESSAGE, + COSMETICS_GROUP_BLOOD, COSMETICS_GROUP_MAX, } CosmeticGroup; @@ -70,4 +71,4 @@ class CosmeticsEditorWindow final : public Ship::GuiWindow { void ApplyDungeonKeyColors(); void UpdateElement() override{}; }; -#endif //__cplusplus \ No newline at end of file +#endif //__cplusplus diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 6c472930930..2644ebd5080 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -227,6 +227,22 @@ typedef enum { // - None VB_BIGGORON_CONSIDER_TRADE_COMPLETE, + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - `*EffectSparkInit` + VB_BLOOD_SET_COLOR_BLUE, + + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - `*EffectSparkInit` + VB_BLOOD_SET_COLOR_GREEN, + // #### `result` // Actor is ACTOR_EN_ELF, ACTOR_EN_FISH, ACTOR_EN_ICE_HONO, or ACTOR_EN_INSECT // ```c diff --git a/soh/src/code/z_collision_check.c b/soh/src/code/z_collision_check.c index aa466e412eb..8dfb4e366d7 100644 --- a/soh/src/code/z_collision_check.c +++ b/soh/src/code/z_collision_check.c @@ -2,6 +2,7 @@ #include "vt.h" #include "overlays/effects/ovl_Effect_Ss_HitMark/z_eff_ss_hitmark.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include typedef s32 (*ColChkResetFunc)(PlayState*, Collider*); @@ -1473,38 +1474,40 @@ void CollisionCheck_BlueBlood(PlayState* play, Collider* collider, Vec3f* v) { D_8015D8A0.position.z = v->z; D_8015D8A0.uDiv = 5; D_8015D8A0.vDiv = 5; - D_8015D8A0.colorStart[0].r = 10; - D_8015D8A0.colorStart[0].g = 10; - D_8015D8A0.colorStart[0].b = 200; - D_8015D8A0.colorStart[0].a = 255; - D_8015D8A0.colorStart[1].r = 0; - D_8015D8A0.colorStart[1].g = 0; - D_8015D8A0.colorStart[1].b = 128; - D_8015D8A0.colorStart[1].a = 255; - D_8015D8A0.colorStart[2].r = 0; - D_8015D8A0.colorStart[2].g = 0; - D_8015D8A0.colorStart[2].b = 128; - D_8015D8A0.colorStart[2].a = 255; - D_8015D8A0.colorStart[3].r = 0; - D_8015D8A0.colorStart[3].g = 0; - D_8015D8A0.colorStart[3].b = 128; - D_8015D8A0.colorStart[3].a = 255; - D_8015D8A0.colorEnd[0].r = 0; - D_8015D8A0.colorEnd[0].g = 0; - D_8015D8A0.colorEnd[0].b = 32; - D_8015D8A0.colorEnd[0].a = 0; - D_8015D8A0.colorEnd[1].r = 0; - D_8015D8A0.colorEnd[1].g = 0; - D_8015D8A0.colorEnd[1].b = 32; - D_8015D8A0.colorEnd[1].a = 0; - D_8015D8A0.colorEnd[2].r = 0; - D_8015D8A0.colorEnd[2].g = 0; - D_8015D8A0.colorEnd[2].b = 64; - D_8015D8A0.colorEnd[2].a = 0; - D_8015D8A0.colorEnd[3].r = 0; - D_8015D8A0.colorEnd[3].g = 0; - D_8015D8A0.colorEnd[3].b = 64; - D_8015D8A0.colorEnd[3].a = 0; + if (GameInteractor_Should(VB_BLOOD_SET_COLOR_BLUE, true, &D_8015D8A0)) { + D_8015D8A0.colorStart[0].r = 10; + D_8015D8A0.colorStart[0].g = 10; + D_8015D8A0.colorStart[0].b = 200; + D_8015D8A0.colorStart[0].a = 255; + D_8015D8A0.colorStart[1].r = 0; + D_8015D8A0.colorStart[1].g = 0; + D_8015D8A0.colorStart[1].b = 128; + D_8015D8A0.colorStart[1].a = 255; + D_8015D8A0.colorStart[2].r = 0; + D_8015D8A0.colorStart[2].g = 0; + D_8015D8A0.colorStart[2].b = 128; + D_8015D8A0.colorStart[2].a = 255; + D_8015D8A0.colorStart[3].r = 0; + D_8015D8A0.colorStart[3].g = 0; + D_8015D8A0.colorStart[3].b = 128; + D_8015D8A0.colorStart[3].a = 255; + D_8015D8A0.colorEnd[0].r = 0; + D_8015D8A0.colorEnd[0].g = 0; + D_8015D8A0.colorEnd[0].b = 32; + D_8015D8A0.colorEnd[0].a = 0; + D_8015D8A0.colorEnd[1].r = 0; + D_8015D8A0.colorEnd[1].g = 0; + D_8015D8A0.colorEnd[1].b = 32; + D_8015D8A0.colorEnd[1].a = 0; + D_8015D8A0.colorEnd[2].r = 0; + D_8015D8A0.colorEnd[2].g = 0; + D_8015D8A0.colorEnd[2].b = 64; + D_8015D8A0.colorEnd[2].a = 0; + D_8015D8A0.colorEnd[3].r = 0; + D_8015D8A0.colorEnd[3].g = 0; + D_8015D8A0.colorEnd[3].b = 64; + D_8015D8A0.colorEnd[3].a = 0; + } D_8015D8A0.timer = 0; D_8015D8A0.duration = 16; D_8015D8A0.speed = 8.0f; @@ -1526,38 +1529,40 @@ void CollisionCheck_GreenBlood(PlayState* play, Collider* collider, Vec3f* v) { D_8015DD68.position.z = v->z; D_8015DD68.uDiv = 5; D_8015DD68.vDiv = 5; - D_8015DD68.colorStart[0].r = 10; - D_8015DD68.colorStart[0].g = 200; - D_8015DD68.colorStart[0].b = 10; - D_8015DD68.colorStart[0].a = 255; - D_8015DD68.colorStart[1].r = 0; - D_8015DD68.colorStart[1].g = 128; - D_8015DD68.colorStart[1].b = 0; - D_8015DD68.colorStart[1].a = 255; - D_8015DD68.colorStart[2].r = 0; - D_8015DD68.colorStart[2].g = 128; - D_8015DD68.colorStart[2].b = 0; - D_8015DD68.colorStart[2].a = 255; - D_8015DD68.colorStart[3].r = 0; - D_8015DD68.colorStart[3].g = 128; - D_8015DD68.colorStart[3].b = 0; - D_8015DD68.colorStart[3].a = 255; - D_8015DD68.colorEnd[0].r = 0; - D_8015DD68.colorEnd[0].g = 32; - D_8015DD68.colorEnd[0].b = 0; - D_8015DD68.colorEnd[0].a = 0; - D_8015DD68.colorEnd[1].r = 0; - D_8015DD68.colorEnd[1].g = 32; - D_8015DD68.colorEnd[1].b = 0; - D_8015DD68.colorEnd[1].a = 0; - D_8015DD68.colorEnd[2].r = 0; - D_8015DD68.colorEnd[2].g = 64; - D_8015DD68.colorEnd[2].b = 0; - D_8015DD68.colorEnd[2].a = 0; - D_8015DD68.colorEnd[3].r = 0; - D_8015DD68.colorEnd[3].g = 64; - D_8015DD68.colorEnd[3].b = 0; - D_8015DD68.colorEnd[3].a = 0; + if (GameInteractor_Should(VB_BLOOD_SET_COLOR_GREEN, true, &D_8015DD68)) { + D_8015DD68.colorStart[0].r = 10; + D_8015DD68.colorStart[0].g = 200; + D_8015DD68.colorStart[0].b = 10; + D_8015DD68.colorStart[0].a = 255; + D_8015DD68.colorStart[1].r = 0; + D_8015DD68.colorStart[1].g = 128; + D_8015DD68.colorStart[1].b = 0; + D_8015DD68.colorStart[1].a = 255; + D_8015DD68.colorStart[2].r = 0; + D_8015DD68.colorStart[2].g = 128; + D_8015DD68.colorStart[2].b = 0; + D_8015DD68.colorStart[2].a = 255; + D_8015DD68.colorStart[3].r = 0; + D_8015DD68.colorStart[3].g = 128; + D_8015DD68.colorStart[3].b = 0; + D_8015DD68.colorStart[3].a = 255; + D_8015DD68.colorEnd[0].r = 0; + D_8015DD68.colorEnd[0].g = 32; + D_8015DD68.colorEnd[0].b = 0; + D_8015DD68.colorEnd[0].a = 0; + D_8015DD68.colorEnd[1].r = 0; + D_8015DD68.colorEnd[1].g = 32; + D_8015DD68.colorEnd[1].b = 0; + D_8015DD68.colorEnd[1].a = 0; + D_8015DD68.colorEnd[2].r = 0; + D_8015DD68.colorEnd[2].g = 64; + D_8015DD68.colorEnd[2].b = 0; + D_8015DD68.colorEnd[2].a = 0; + D_8015DD68.colorEnd[3].r = 0; + D_8015DD68.colorEnd[3].g = 64; + D_8015DD68.colorEnd[3].b = 0; + D_8015DD68.colorEnd[3].a = 0; + } D_8015DD68.timer = 0; D_8015DD68.duration = 16; D_8015DD68.speed = 8.0f;