#include "CSamusDoll.hpp" #include "GameGlobalObjects.hpp" #include "CSimplePool.hpp" #include "CDependencyGroup.hpp" #include "zeus/CEulerAngles.hpp" #include "Collision/CollisionUtil.hpp" #include "Graphics/CBooRenderer.hpp" namespace urde { namespace MP1 { const zeus::CVector3f CSamusDoll::skInitialOffset = {0.f, 0.f, 0.8f}; static const std::pair SpiderBallGlassModels[] = { {"SamusSpiderBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 1}, {"SamusPhazonBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 1}, {"SamusPhazonBallGlassCMDL", 0}, }; static const std::pair SpiderBallCharacters[] = { {"SamusSpiderBallANCS", 0}, {"SamusSpiderBallANCS", 0}, {"SamusSpiderBallANCS", 1}, {"SamusPhazonBallANCS", 0}, {"SamusFusionBallANCS", 0}, {"SamusFusionBallANCS", 2}, {"SamusFusionBallANCS", 1}, {"SamusFusionBallANCS", 3}, }; static const std::pair BallCharacters[] = { {"SamusBallANCS", 0}, {"SamusBallANCS", 0}, {"SamusBallANCS", 1}, {"SamusBallANCS", 0}, {"SamusFusionBallANCS", 0}, {"SamusFusionBallANCS", 2}, {"SamusFusionBallANCS", 1}, {"SamusFusionBallANCS", 3}, }; static const u32 SpiderBallGlowColorIdxs[] = { 3, 3, 2, 4, 5, 7, 6, 8 }; static const u32 BallGlowColorIdxs[] = { 0, 0, 1, 0, 5, 7, 6, 8 }; static const char* BeamModels[] = { "CMDL_InvPowerBeam", "CMDL_InvIceBeam", "CMDL_InvWaveBeam", "CMDL_InvPlasmaBeam", "CMDL_InvPowerBeam" }; static const char* VisorModels[] = { "CMDL_InvVisor", "CMDL_InvGravityVisor", "CMDL_InvVisor", "CMDL_InvPhazonVisor", "CMDL_InvFusionVisor", "CMDL_InvFusionVisor", "CMDL_InvFusionVisor", "CMDL_InvFusionVisor" }; static const char* FinModels[] = { "CMDL_InvPowerFins", "CMDL_InvPowerFins", "CMDL_InvPowerFins", "CMDL_InvPowerFins", "CMDL_InvPowerFins", "CMDL_InvVariaFins", "CMDL_InvGravityFins", "CMDL_InvPhazonFins" }; static const u32 Character1Idxs[8] = { 0, 6, 2, 10, 16, 24, 20, 28 }; static const u32 CharacterBootsIdxs[8] = { 1, 7, 3, 11, 17, 25, 21, 29 }; static const u32 Character2and3Idxs[8][2] = { {14, 15}, {8, 9}, {4, 5}, {12, 13}, {18, 19}, {26, 27}, {22, 23}, {30, 31} }; static const u8 BallGlowColors[9][3] = { {0xff, 0xff, 0xff}, {0xff, 0xff, 0xff}, {0xff, 0xff, 0xff}, {0xff, 0xff, 0xff}, {0xff, 0xd5, 0x19}, {0xff, 0xff, 0xff}, {0xff, 0xff, 0xff}, {0xff, 0xff, 0xff}, {0xff, 0xff, 0xff}, }; static const u8 BallTransFlashColors[9][3] = { {0xc2, 0x7e, 0x10}, {0x66, 0xc4, 0xff}, {0x60, 0xff, 0x90}, {0x33, 0x33, 0xff}, {0xff, 0x20, 0x20}, {0x0, 0x9d, 0xb6}, {0xd3, 0xf1, 0x0}, {0xa6, 0x86, 0xd8}, {0xfb, 0x98, 0x21} }; static const u8 BallAuxGlowColors[9][3] = { {0xc2, 0x7e, 0x10}, {0x66, 0xc4, 0xff}, {0x6c, 0xff, 0x61}, {0x33, 0x33, 0xff}, {0xff, 0x20, 0x20}, {0x0, 0x9d, 0xb6}, {0xd3, 0xf1, 0x0}, {0xa6, 0x86, 0xd8}, {0xfb, 0x98, 0x21} }; CSamusDoll::CSamusDoll(const CDependencyGroup& suitDgrp, const CDependencyGroup& ballDgrp, CPlayerState::EPlayerSuit suit, CPlayerState::EBeamId beam, bool hasSpiderBall, bool hasGrappleBeam) : x44_suit(suit), x48_beam(beam) { x1d4_spiderBallGlass = g_SimplePool->GetObj(SpiderBallGlassModels[int(suit)].first); x1e0_ballMatIdx = hasSpiderBall ? SpiderBallCharacters[int(suit)].second : BallCharacters[int(suit)].second; x1e4_glassMatIdx = SpiderBallGlassModels[int(suit)].second; x1e8_ballGlowColorIdx = hasSpiderBall ? SpiderBallGlowColorIdxs[int(suit)] : BallGlowColorIdxs[int(suit)]; x1ec_itemScreenSamus = g_SimplePool->GetObj("ANCS_ItemScreenSamus"); x1f4_invBeam = g_SimplePool->GetObj(BeamModels[int(beam)]); x200_invVisor = g_SimplePool->GetObj(VisorModels[int(suit)]); x20c_invGrappleBeam = g_SimplePool->GetObj("CMDL_InvGrappleBeam"); x218_invFins = g_SimplePool->GetObj(FinModels[int(suit)]); x224_ballInnerGlow = g_SimplePool->GetObj("BallInnerGlow"); x22c_ballInnerGlowGen = std::make_unique(x224_ballInnerGlow, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One); x230_ballTransitionFlash = g_SimplePool->GetObj("MorphBallTransitionFlash"); x23c_lights.push_back(CLight::BuildDirectional(zeus::CVector3f::skForward, zeus::CColor::skWhite)); x24c_actorLights = std::make_unique(8, zeus::CVector3f::skZero, 4, 4, false, false, false, 0.1f); x270_24_hasSpiderBall = hasSpiderBall; x270_25_hasGrappleBeam = hasGrappleBeam; x22c_ballInnerGlowGen->SetGlobalScale(zeus::CVector3f(0.625f)); x0_depToks.reserve(suitDgrp.GetObjectTagVector().size() + ballDgrp.GetObjectTagVector().size()); for (const SObjectTag& tag : suitDgrp.GetObjectTagVector()) { x0_depToks.push_back(g_SimplePool->GetObj(tag)); x0_depToks.back().Lock(); } for (const SObjectTag& tag : ballDgrp.GetObjectTagVector()) { x0_depToks.push_back(g_SimplePool->GetObj(tag)); x0_depToks.back().Lock(); } } bool CSamusDoll::IsLoaded() const { if (x270_31_loaded) return true; if (!x1ec_itemScreenSamus.IsLoaded()) return false; if (!x1f4_invBeam.IsLoaded()) return false; if (!x200_invVisor.IsLoaded()) return false; if (!x20c_invGrappleBeam.IsLoaded()) return false; if (!x1d4_spiderBallGlass.IsLoaded()) return false; if (x218_invFins && !x218_invFins.IsLoaded()) return false; return xc8_suitModel0.operator bool(); } CModelData CSamusDoll::BuildSuitModelData1(CPlayerState::EPlayerSuit suit) { CModelData ret(CAnimRes(g_ResFactory->GetResourceIdByName("ANCS_ItemScreenSamus")->id, Character1Idxs[int(suit)], zeus::CVector3f::skOne, 2, true)); CAnimPlaybackParms parms(2, -1, 1.f, true); ret.AnimationData()->SetAnimation(parms, false); return ret; } CModelData CSamusDoll::BuildSuitModelDataBoots(CPlayerState::EPlayerSuit suit) { CModelData ret(CAnimRes(g_ResFactory->GetResourceIdByName("ANCS_ItemScreenSamus")->id, CharacterBootsIdxs[int(suit)], zeus::CVector3f::skOne, 2, true)); CAnimPlaybackParms parms(2, -1, 1.f, true); ret.AnimationData()->SetAnimation(parms, false); return ret; } bool CSamusDoll::CheckLoadComplete() { if (IsLoaded()) return true; for (const CToken& tok : x0_depToks) if (!tok.IsLoaded()) return false; xc8_suitModel0.emplace(BuildSuitModelData1(x44_suit)); for (int i=0 ; i<2 ; ++i) { CAnimRes res(g_ResFactory->GetResourceIdByName("ANCS_ItemScreenSamus")->id, Character2and3Idxs[int(x44_suit)][i], zeus::CVector3f::skOne, 2, true); CModelData mData(res); x118_suitModel1and2.push_back(mData.GetAnimationData()->GetModelData()); x118_suitModel1and2.back().Lock(); } x134_suitModelBoots.emplace(BuildSuitModelDataBoots(x44_suit)); CAnimRes res(g_ResFactory->GetResourceIdByName(x270_24_hasSpiderBall ? SpiderBallCharacters[int(x44_suit)].first : BallCharacters[int(x44_suit)].first)->id, 0, zeus::CVector3f::skOne, 0, true); x184_ballModelData.emplace(res); x1e0_ballMatIdx = x270_24_hasSpiderBall ? SpiderBallCharacters[int(x44_suit)].second : BallCharacters[int(x44_suit)].second; x270_31_loaded = true; return true; } void CSamusDoll::Update(float dt, CRandom16& rand) { if (x1f4_invBeam.IsLoaded()) x1f4_invBeam->Touch(0); if (x200_invVisor.IsLoaded()) x200_invVisor->Touch(0); if (x20c_invGrappleBeam.IsLoaded()) x20c_invGrappleBeam->Touch(0); if (x1d4_spiderBallGlass.IsLoaded()) x1d4_spiderBallGlass->Touch(0); if (x218_invFins.IsLoaded()) x218_invFins->Touch(0); if (!CheckLoadComplete()) return; x40_alphaIn = std::min(x40_alphaIn + 2.f * dt, 1.f); if (x54_remTransitionTime > 0.f) { float oldRemTransTime = x54_remTransitionTime; x54_remTransitionTime = std::max(0.f, x54_remTransitionTime - dt); if (!x4c_completedMorphball && x4d_selectedMorphball && oldRemTransTime >= x50_totalTransitionTime - 0.5f && x54_remTransitionTime < x50_totalTransitionTime - 0.5f) { x238_ballTransitionFlashGen = std::make_unique(x230_ballTransitionFlash, CElementGen::EModelOrientationType::Normal, CElementGen::EOptionalSystemFlags::One); x238_ballTransitionFlashGen->SetGlobalScale(zeus::CVector3f(0.625f)); } if (x54_remTransitionTime == 0.f) { x4c_completedMorphball = x4d_selectedMorphball; if (!x4d_selectedMorphball) { xc8_suitModel0->AnimationData()->SetAnimation(CAnimPlaybackParms(2, -1, 1.f, true), false); x134_suitModelBoots->AnimationData()->SetAnimation(CAnimPlaybackParms(2, -1, 1.f, true), false); } } } if (x270_26_pulseSuit) x58_suitPulseFactor = std::min(x58_suitPulseFactor + 2.f * dt, 1.f); else x58_suitPulseFactor = std::max(x58_suitPulseFactor - 2.f * dt, 0.f); if (x270_27_pulseBeam) x5c_beamPulseFactor = std::min(x5c_beamPulseFactor + 2.f * dt, 1.f); else x5c_beamPulseFactor = std::max(x5c_beamPulseFactor - 2.f * dt, 0.f); if (x270_28_pulseGrapple) x60_grapplePulseFactor = std::min(x60_grapplePulseFactor + 2.f * dt, 1.f); else x60_grapplePulseFactor = std::max(x60_grapplePulseFactor - 2.f * dt, 0.f); if (x270_29_pulseBoots) x64_bootsPulseFactor = std::min(x64_bootsPulseFactor + 2.f * dt, 1.f); else x64_bootsPulseFactor = std::max(x64_bootsPulseFactor - 2.f * dt, 0.f); if (x270_30_pulseVisor) x68_visorPulseFactor = std::min(x68_visorPulseFactor + 2.f * dt, 1.f); else x68_visorPulseFactor = std::max(x68_visorPulseFactor - 2.f * dt, 0.f); if (x4c_completedMorphball) x6c_ballPulseFactor = std::min(x6c_ballPulseFactor + 2.f * dt, 1.f); else x6c_ballPulseFactor = std::max(x6c_ballPulseFactor - 2.f * dt, 0.f); if (x44_suit == CPlayerState::EPlayerSuit::Phazon) { if (!x250_phazonIndirectTexture) x250_phazonIndirectTexture = g_SimplePool->GetObj("PhazonIndirectTexture"); } else { if (x250_phazonIndirectTexture) x250_phazonIndirectTexture = TLockedToken(); } if (x250_phazonIndirectTexture) { x260_phazonOffsetAngle += 0.03f; g_Renderer->AllocatePhazonSuitMaskTexture(); } xc8_suitModel0->AdvanceAnimationIgnoreParticles(dt, rand, true); x134_suitModelBoots->AdvanceAnimationIgnoreParticles(dt, rand, true); x184_ballModelData->AdvanceAnimationIgnoreParticles(dt, rand, true); SetupLights(); x22c_ballInnerGlowGen->SetGlobalTranslation(x10_xf.origin); x22c_ballInnerGlowGen->Update(dt); if (x238_ballTransitionFlashGen) { if (x238_ballTransitionFlashGen->IsSystemDeletable()) x238_ballTransitionFlashGen.reset(); if (x238_ballTransitionFlashGen) { x22c_ballInnerGlowGen->SetGlobalTranslation(x10_xf.origin); x22c_ballInnerGlowGen->Update(dt); } } if (xc4_viewInterp != 0.f && xc4_viewInterp != 1.f) { if (xc4_viewInterp < 0.f) xc4_viewInterp = std::min(xc4_viewInterp + 3.f * dt, 0.f); else xc4_viewInterp = std::min(xc4_viewInterp + 3.f * dt, 1.f); float interp = std::fabs(xc4_viewInterp); float oneMinusInterp = 1.f - interp; xa4_offset = x84_interpStartOffset * interp + skInitialOffset * oneMinusInterp; xb0_userRot = zeus::CQuaternion::slerpShort(x70_fixedRot, x90_userInterpRot, interp); if (xc4_viewInterp <= 0.f) // Zoom out xc0_userZoom = x80_fixedZoom * oneMinusInterp + xa0_userInterpZoom * interp; else // Zoom in xc0_userZoom = x80_fixedZoom * interp + xa0_userInterpZoom * oneMinusInterp; } } void CSamusDoll::Draw(const CStateManager& mgr, float alpha) { if (!IsLoaded()) return; alpha *= x40_alphaIn; float itemPulse = zeus::clamp(0.f, (std::sin(5.f * CGraphics::GetSecondsMod900()) + 1.f) * 0.5f, 1.f) * (1.f - std::fabs(xc4_viewInterp)); g_Renderer->SetPerspective(55.f, g_Viewport.x8_width, g_Viewport.xc_height, 0.2f, 4096.f); CGraphics::SetViewPointMatrix(zeus::CTransform(xb0_userRot, xa4_offset) * zeus::CTransform::Translate(0.f, xc0_userZoom, 0.f)); zeus::CTransform gunXf = xc8_suitModel0->GetScaledLocatorTransform("GUN_LCTR"); zeus::CTransform visorXf = xc8_suitModel0->GetScaledLocatorTransform("VISOR_LCTR"); zeus::CTransform grappleXf = xc8_suitModel0->GetScaledLocatorTransform("GRAPPLE_LCTR"); if (!x4c_completedMorphball || !x4d_selectedMorphball) { float suitPulse = itemPulse * x58_suitPulseFactor; float bootsPulse = std::max(suitPulse, itemPulse * x64_bootsPulseFactor); bool phazonSuit = x44_suit == CPlayerState::EPlayerSuit::Phazon; // Enable dst alpha 1.0 for (int i=0 ; i<=x118_suitModel1and2.size() ; ++i) { TCachedToken backupModelData = xc8_suitModel0->GetAnimationData()->GetModelData(); if (i < x118_suitModel1and2.size()) xc8_suitModel0->AnimationData()->SubstituteModelData(x118_suitModel1and2[i]); xc8_suitModel0->InvSuitDraw(CModelData::EWhichModel::Normal, zeus::CTransform::Identity(), x24c_actorLights.get(), zeus::CColor(1.f, alpha), zeus::CColor(1.f, alpha * suitPulse)); xc8_suitModel0->AnimationData()->SubstituteModelData(backupModelData); } x134_suitModelBoots->InvSuitDraw(CModelData::EWhichModel::Normal, zeus::CTransform::Identity(), x24c_actorLights.get(), zeus::CColor(1.f, alpha), zeus::CColor(1.f, alpha * bootsPulse)); { CGraphics::SetModelMatrix(gunXf); x1f4_invBeam->GetInstance().ActivateLights(x23c_lights); CModelFlags flags = {}; flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; flags.x4_color = zeus::CColor::skWhite; x1f4_invBeam->Draw(flags); flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor(1.f, alpha); x1f4_invBeam->Draw(flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor(1.f, alpha * itemPulse * x5c_beamPulseFactor); x1f4_invBeam->Draw(flags); } { CGraphics::SetModelMatrix(visorXf); float visorT = std::fmod(CGraphics::GetSecondsMod900(), 1.f) * (1.f - std::fabs(xc4_viewInterp)); float alphaBlend = (visorT < 0.25f) ? 1.f - 2.f * visorT : (visorT < 0.5f) ? 2.f * (visorT - 0.25f) + 0.5f : 1.f; float addBlend = (visorT > 0.75f) ? 1.f - 4.f * (visorT - 0.75f) : (visorT > 0.5f) ? 4.f * (visorT - 0.5f) : 0.f; x200_invVisor->GetInstance().ActivateLights(x23c_lights); CModelFlags flags = {}; flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor::lerp(zeus::CColor(1.f, alpha), zeus::CColor(alphaBlend, alpha), x68_visorPulseFactor); x200_invVisor->Draw(flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor(1.f, alpha * addBlend * x68_visorPulseFactor); x200_invVisor->Draw(flags); } if (x270_25_hasGrappleBeam) { CGraphics::SetModelMatrix(grappleXf); x20c_invGrappleBeam->GetInstance().ActivateLights(x23c_lights); CModelFlags flags = {}; flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor(1.f, alpha); x20c_invGrappleBeam->Draw(flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor(1.f, alpha * itemPulse * x60_grapplePulseFactor); x20c_invGrappleBeam->Draw(flags); } else if (x44_suit >= CPlayerState::EPlayerSuit::FusionPower) { CGraphics::SetModelMatrix(grappleXf); x218_invFins->GetInstance().ActivateLights(x23c_lights); CModelFlags flags = {}; flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor(1.f, alpha); x218_invFins->Draw(flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor(1.f, alpha * suitPulse); x218_invFins->Draw(flags); } if (x54_remTransitionTime > 0.f) { float ballT = 1.f - x54_remTransitionTime / x50_totalTransitionTime; float ballAlpha = 0.f; if (x4d_selectedMorphball) ballAlpha = 1.f - std::min(x54_remTransitionTime / 0.25f, 1.f); else if (x4c_completedMorphball) ballAlpha = std::max(0.f, (x54_remTransitionTime - (x50_totalTransitionTime - 0.25f)) / 0.25f); if (ballAlpha > 0.f) { CModelFlags flags = {}; flags.x1_matSetIdx = x1e0_ballMatIdx; flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; flags.x4_color = zeus::CColor::skWhite; x184_ballModelData->Render(mgr, x10_xf, x24c_actorLights.get(), flags); flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = alpha * ballAlpha; x184_ballModelData->Render(mgr, x10_xf, x24c_actorLights.get(), flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = x6c_ballPulseFactor * alpha * ballAlpha * itemPulse; x184_ballModelData->Render(mgr, x10_xf, x24c_actorLights.get(), flags); } if (x4d_selectedMorphball && ballT > 0.5f) { float ballEndT = (ballT - 0.5f) / 0.5f; float oneMinusBallEndT = 1.f - ballEndT; float spinScale = 0.75f * oneMinusBallEndT + 1.f; float spinAlpha; if (ballEndT < 0.1f) spinAlpha = 0.f; else if (ballEndT < 0.2f) spinAlpha = (ballEndT - 0.1f) / 0.1f; else if (ballEndT < 0.9f) spinAlpha = 1.f; else spinAlpha = 1.f - (ballT - 0.9f) / 0.1f; zeus::CRelAngle spinAngle = zeus::degToRad(360.f * oneMinusBallEndT); spinAlpha *= 0.5f; if (spinAlpha > 0.f) { CModelFlags flags = {}; flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x1_matSetIdx = x1e0_ballMatIdx; flags.x4_color = zeus::CColor(1.f, spinAlpha * alpha); x184_ballModelData->Render(mgr, x10_xf * zeus::CTransform::RotateZ(spinAngle) * zeus::CTransform::Scale(spinScale), x24c_actorLights.get(), flags); } } if (x270_24_hasSpiderBall) { CGraphics::SetModelMatrix(x10_xf); CModelFlags flags = {}; flags.x1_matSetIdx = x1e4_glassMatIdx; x1d4_spiderBallGlass->GetInstance().ActivateLights(x23c_lights); flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; flags.x4_color = zeus::CColor::skWhite; x1d4_spiderBallGlass->Draw(flags); flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = alpha; x1d4_spiderBallGlass->Draw(flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = x6c_ballPulseFactor * alpha * itemPulse; x1d4_spiderBallGlass->Draw(flags); } if (phazonSuit && alpha > 0.1f) { float radius = zeus::clamp(0.2f, (10.f - (xc0_userZoom >= 0.f ? xc0_userZoom : -xc0_userZoom)) / 20.f, 1.f); float offset = std::sin(x260_phazonOffsetAngle); zeus::CColor color = g_tweakGuiColors->GetInvPhazonSuitFilterMod(); color.a = alpha; g_Renderer->DrawPhazonSuitIndirectEffect(zeus::CColor(0.1f, alpha), x250_phazonIndirectTexture, color, radius, 0.1f, offset, offset); } } } else { CModelFlags flags = {}; flags.x1_matSetIdx = x1e0_ballMatIdx; flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; flags.x4_color = zeus::CColor::skWhite; x184_ballModelData->Render(mgr, x10_xf, x24c_actorLights.get(), flags); flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = alpha; x184_ballModelData->Render(mgr, x10_xf, x24c_actorLights.get(), flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = x6c_ballPulseFactor * alpha * itemPulse; x184_ballModelData->Render(mgr, x10_xf, x24c_actorLights.get(), flags); const u8* c = BallGlowColors[x1e8_ballGlowColorIdx]; zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, alpha}; x22c_ballInnerGlowGen->SetModulationColor(color); if (alpha > 0.f) { if (x22c_ballInnerGlowGen->GetNumActiveChildParticles() > 0) { const u8* c = BallTransFlashColors[x1e8_ballGlowColorIdx]; zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, alpha}; x22c_ballInnerGlowGen->GetActiveChildParticle(0).SetModulationColor(color); if (x22c_ballInnerGlowGen->GetNumActiveChildParticles() > 1) { const u8* c = BallAuxGlowColors[x1e8_ballGlowColorIdx]; zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, alpha}; x22c_ballInnerGlowGen->GetActiveChildParticle(1).SetModulationColor(color); } } x22c_ballInnerGlowGen->Render(); } if (x270_24_hasSpiderBall) { CGraphics::SetModelMatrix(x10_xf); CModelFlags flags = {}; flags.x1_matSetIdx = x1e4_glassMatIdx; x1d4_spiderBallGlass->GetInstance().ActivateLights(x23c_lights); flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; flags.x4_color = zeus::CColor::skWhite; x1d4_spiderBallGlass->Draw(flags); flags.m_extendedShader = EExtendedShader::Lighting; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = alpha; x1d4_spiderBallGlass->Draw(flags); flags.m_extendedShader = EExtendedShader::ForcedAdditive; flags.x4_color = zeus::CColor::skWhite; flags.x4_color.a = x6c_ballPulseFactor * alpha * itemPulse; x1d4_spiderBallGlass->Draw(flags); } } if (x238_ballTransitionFlashGen) { const u8* c = BallTransFlashColors[x1e8_ballGlowColorIdx]; zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, 1.f}; x238_ballTransitionFlashGen->SetModulationColor(color); x238_ballTransitionFlashGen->Render(); } CGraphics::DisableAllLights(); } void CSamusDoll::Touch() { if (!CheckLoadComplete()) return; xc8_suitModel0->AnimationData()->PreRender(); x134_suitModelBoots->AnimationData()->PreRender(); x184_ballModelData->AnimationData()->PreRender(); xc8_suitModel0->Touch(CModelData::EWhichModel::Normal, 0); x134_suitModelBoots->Touch(CModelData::EWhichModel::Normal, 0); x184_ballModelData->Touch(CModelData::EWhichModel::Normal, 0); } void CSamusDoll::SetupLights() { x23c_lights[0] = CLight::BuildDirectional(xb0_userRot.toTransform().basis[1], zeus::CColor(0.75f, 1.f)); x24c_actorLights->BuildFakeLightList(x23c_lights, zeus::CColor::skBlack); } void CSamusDoll::SetInMorphball(bool morphball) { if (x54_remTransitionTime > 0.f) return; if (x4d_selectedMorphball == morphball) return; x4d_selectedMorphball = morphball; SetTransitionAnimation(); } void CSamusDoll::SetTransitionAnimation() { if (!x4c_completedMorphball) { /* Into morphball */ xc8_suitModel0->AnimationData()->SetAnimation(CAnimPlaybackParms{0, -1, 1.f, true}, false); x134_suitModelBoots->AnimationData()->SetAnimation(CAnimPlaybackParms{0, -1, 1.f, true}, false); x50_totalTransitionTime = x54_remTransitionTime = xc8_suitModel0->GetAnimationData()->GetAnimationDuration(0); } else if (!x4d_selectedMorphball) { /* Outta morphball */ xc8_suitModel0->AnimationData()->SetAnimation(CAnimPlaybackParms{1, -1, 1.f, true}, false); x134_suitModelBoots->AnimationData()->SetAnimation(CAnimPlaybackParms{1, -1, 1.f, true}, false); x50_totalTransitionTime = x54_remTransitionTime = xc8_suitModel0->GetAnimationData()->GetAnimationDuration(1); } } void CSamusDoll::SetRotationSfxPlaying(bool playing) { if (playing) { if (x268_rotateSfx) return; x268_rotateSfx = CSfxManager::SfxStart(1375, 1.f, 0.f, false, 0x7f, true, kInvalidAreaId); } else { CSfxManager::SfxStop(x268_rotateSfx); x268_rotateSfx.reset(); } } void CSamusDoll::SetOffsetSfxPlaying(bool playing) { if (playing) { if (x264_offsetSfx) return; x264_offsetSfx = CSfxManager::SfxStart(1406, 1.f, 0.f, false, 0x7f, true, kInvalidAreaId); } else { CSfxManager::SfxStop(x264_offsetSfx); x264_offsetSfx.reset(); } } void CSamusDoll::SetZoomSfxPlaying(bool playing) { if (playing) { if (x26c_zoomSfx) return; x26c_zoomSfx = CSfxManager::SfxStart(1376, 1.f, 0.f, false, 0x7f, true, kInvalidAreaId); } else { CSfxManager::SfxStop(x26c_zoomSfx); x26c_zoomSfx.reset(); } } void CSamusDoll::SetRotation(float xDelta, float zDelta, float dt) { if (xc4_viewInterp != 0.f && xc4_viewInterp != 1.f) return; SetRotationSfxPlaying(xDelta != 0.f || zDelta != 0.f); zeus::CEulerAngles angles(xb0_userRot); zeus::CRelAngle angX(angles.x); zeus::CRelAngle angZ(angles.z); angX += xDelta; angZ += zDelta; float angXCenter = angX; if (angXCenter > M_PIF) angXCenter -= 2.f * M_PIF; angX = zeus::clamp(-M_PIF / 2.f, angXCenter, M_PIF / 2.f); float angZCenter = angZ; if (angZCenter > M_PIF) angZCenter -= 2.f * M_PIF; angZ = zeus::clamp(-M_PIF / 2.f, angZCenter, M_PIF / 2.f); zeus::CQuaternion quat; quat.rotateZ(angZ); quat.rotateX(angX); xb0_userRot = quat; } void CSamusDoll::SetOffset(const zeus::CVector3f& offset, float dt) { if (xc4_viewInterp != 0.f && xc4_viewInterp != 1.f) return; zeus::CVector3f oldOffset = xa4_offset; zeus::CMatrix3f rotMtx = xb0_userRot.toTransform().basis; xa4_offset += rotMtx * zeus::CVector3f(offset.x, 0.f, offset.z); SetOffsetSfxPlaying((oldOffset - xa4_offset).magnitude() > dt); float oldZoom = xc0_userZoom; xc0_userZoom = zeus::clamp(-4.f, xc0_userZoom + offset.y, -2.2f); bool zoomSfx = std::fabs(xc0_userZoom - oldZoom) > dt; float zoomDelta = offset.y - (xc0_userZoom - oldZoom); zeus::CVector3f newOffset = rotMtx[1] * zoomDelta + xa4_offset; zeus::CVector3f delta = newOffset - xa4_offset; oldOffset = xa4_offset; if (!delta.isZero()) { zeus::CSphere sphere(skInitialOffset, 1.f); float T; zeus::CVector3f point; if (CollisionUtil::RaySphereIntersection(sphere, xa4_offset, delta.normalized(), 0.f, T, point)) { if ((point - xa4_offset).magnitude() < std::fabs(zoomDelta)) xa4_offset = point; else xa4_offset = newOffset; } else { xa4_offset = newOffset; } } if ((oldOffset - xa4_offset).magnitude() > dt) zoomSfx = true; SetZoomSfxPlaying(zoomSfx); delta = xa4_offset - skInitialOffset; if (delta.magnitude() > 1.f) xa4_offset = delta.normalized() + skInitialOffset; } void CSamusDoll::BeginViewInterpolate(bool zoomIn) { if (xc4_viewInterp == 0.f) { CSfxManager::SfxStart(1440, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } else { SetOffsetSfxPlaying(false); SetZoomSfxPlaying(false); SetRotationSfxPlaying(false); CSfxManager::SfxStart(1441, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } xc4_viewInterp = zoomIn ? FLT_EPSILON : (-1.f + FLT_EPSILON); x84_interpStartOffset = xa4_offset; x90_userInterpRot = xb0_userRot; xa0_userInterpZoom = xc0_userZoom; x80_fixedZoom = zoomIn ? -2.2f : -3.6f; } } }