void CSPCharacter::LockViewToPlanet() { // Now lock the roll value to the planet. CPlanet* pNearestPlanet = GetNearestPlanet(); if (!pNearestPlanet) return; Matrix4x4 mGlobalRotation = GetGlobalTransform(); mGlobalRotation.SetTranslation(CScalableVector()); // Construct a "local space" for the planet Vector vecPlanetUp = GetUpVector(); Vector vecPlanetForward = mGlobalRotation.GetForwardVector(); Vector vecPlanetRight = vecPlanetForward.Cross(vecPlanetUp).Normalized(); vecPlanetForward = vecPlanetUp.Cross(vecPlanetRight).Normalized(); Matrix4x4 mPlanet(vecPlanetForward, vecPlanetUp, vecPlanetRight); Matrix4x4 mPlanetInverse = mPlanet; mPlanetInverse.InvertTR(); // Bring our current view angles into that local space Matrix4x4 mLocalRotation = mPlanetInverse * mGlobalRotation; EAngle angLocalRotation = mLocalRotation.GetAngles(); // Lock them so that the roll is 0 // I'm sure there's a way to do this without converting to euler but at this point I don't care. angLocalRotation.r = 0; Matrix4x4 mLockedLocalRotation; mLockedLocalRotation.SetAngles(angLocalRotation); // Bring it back out to global space Matrix4x4 mLockedRotation = mPlanet * mLockedLocalRotation; // Only use the changed r value to avoid floating point crap EAngle angNewLockedRotation = GetGlobalAngles(); EAngle angOverloadRotation = mLockedRotation.GetAngles(); // Lerp our way there float flTimeToLocked = 1; if (GameServer()->GetGameTime() - m_flLastEnteredAtmosphere > flTimeToLocked) angNewLockedRotation.r = angOverloadRotation.r; else angNewLockedRotation.r = RemapValClamped(SLerp(GameServer()->GetGameTime() - m_flLastEnteredAtmosphere, 0.3f), 0, flTimeToLocked, m_flRollFromSpace, angOverloadRotation.r); SetGlobalAngles(angNewLockedRotation); }
CStructure* CStructure::CreateStructure(structure_type eType, CSPPlayer* pOwner, CSpire* pSpire, const CScalableVector& vecOrigin) { CStructure* pStructure = nullptr; switch (eType) { default: case STRUCTURE_NONE: TAssert(false); return nullptr; case STRUCTURE_SPIRE: pStructure = GameServer()->Create<CSpire>("CSpire"); break; case STRUCTURE_MINE: pStructure = GameServer()->Create<CMine>("CMine"); break; case STRUCTURE_PALLET: pStructure = GameServer()->Create<CPallet>("CPallet"); break; case STRUCTURE_STOVE: pStructure = GameServer()->Create<CStove>("CStove"); break; } pStructure->GameData().SetPlayerOwner(pOwner->GetPlayerCharacter()->GameData().GetPlayerOwner()); pStructure->GameData().SetPlanet(pOwner->GetPlayerCharacter()->GameData().GetPlanet()); pStructure->SetOwner(pOwner); pStructure->SetSpire(pSpire); pStructure->SetGlobalOrigin(pOwner->GetPlayerCharacter()->GameData().GetPlanet()->GetGlobalOrigin()); // Avoid floating point precision problems pStructure->SetMoveParent(pOwner->GetPlayerCharacter()->GameData().GetPlanet()); pStructure->SetLocalOrigin(vecOrigin); if (pStructure->GameData().GetPlanet()) { Vector vecUp = pStructure->GetLocalOrigin().Normalized(); Matrix4x4 mDirection; mDirection.SetUpVector(vecUp); mDirection.SetForwardVector(vecUp.Cross(pOwner->GetPlayerCharacter()->GetLocalTransform().GetRightVector()).Normalized()); mDirection.SetRightVector(mDirection.GetForwardVector().Cross(vecUp).Normalized()); pStructure->SetLocalAngles(mDirection.GetAngles()); } pStructure->AddToPhysics(CT_STATIC_MESH); pStructure->PostConstruction(); return pStructure; }