void CSPCharacter::Think() { BaseClass::Think(); CPlanet* pPlanet = GetNearestPlanet(); if (pPlanet && !HasMoveParent()) { m_flLastEnteredAtmosphere = GameServer()->GetGameTime(); m_flRollFromSpace = GetGlobalAngles().r; } SetMoveParent(pPlanet); if (pPlanet) { // Estimate this planet's mass given things we know about earth. Assume equal densities. double flEarthVolume = 1097509500000000000000.0; // cubic meters double flEarthMass = 5974200000000000000000000.0; // kilograms // 4/3 * pi * r^3 = volume of a sphere CScalableFloat flPlanetVolume = pPlanet->GetRadius()*pPlanet->GetRadius()*pPlanet->GetRadius()*(M_PI*4/3); double flPlanetMass = RemapVal(flPlanetVolume, CScalableFloat(), CScalableFloat(flEarthVolume, SCALE_METER), 0, flEarthMass); double flG = 0.0000000000667384; // Gravitational constant CScalableVector vecDistance = (pPlanet->GetGlobalOrigin() - GetGlobalOrigin()); CScalableFloat flDistance = vecDistance.Length(); CScalableFloat flGravity = CScalableFloat(flPlanetMass*flG, SCALE_METER)/(flDistance*flDistance); CScalableVector vecGravity = vecDistance * flGravity / flDistance; SetGlobalGravity(vecGravity); } }
void CLaser::PostRender() const { BaseClass::PostRender(); if (!GameServer()->GetRenderer()->IsRenderingTransparent()) return; if (!m_bShouldRender) return; if (!m_hOwner) return; CRenderingContext r(DigitanksGame()->GetDigitanksRenderer(), true); r.SetBlend(BLEND_ADDITIVE); Vector vecForward, vecRight, vecUp; float flLength = LaserLength(); CDigitank* pOwner = dynamic_cast<CDigitank*>(GetOwner()); Vector vecMuzzle = m_hOwner->GetGlobalOrigin(); Vector vecTarget = vecMuzzle + AngleVector(GetGlobalAngles()) * flLength; if (pOwner) { Vector vecDirection = (pOwner->GetLastAim() - pOwner->GetGlobalOrigin()).Normalized(); vecTarget = vecMuzzle + vecDirection * flLength; AngleVectors(VectorAngles(vecDirection), &vecForward, &vecRight, &vecUp); vecMuzzle = pOwner->GetGlobalOrigin() + vecDirection * 3 + Vector(0, 0, 3); } float flBeamWidth = 1.5; Vector avecRayColors[] = { Vector(1, 0, 0), Vector(0, 1, 0), Vector(0, 0, 1), }; float flRayRamp = RemapValClamped((float)(GameServer()->GetGameTime() - GetSpawnTime()), 0.5f, 1.5f, 0.0f, 1); float flAlphaRamp = RemapValClamped((float)(GameServer()->GetGameTime() - GetSpawnTime()), 1, 2, 1.0f, 0); size_t iBeams = 21; for (size_t i = 0; i < iBeams; i++) { float flUp = RemapVal((float)i, 0, (float)iBeams, -flLength, flLength); Vector vecRay = LerpValue<Vector>(Vector(1, 1, 1), avecRayColors[i%3], flRayRamp); Color clrRay = vecRay; clrRay.SetAlpha((int)(200*flAlphaRamp)); r.SetColor(clrRay); CRopeRenderer rope(DigitanksGame()->GetDigitanksRenderer(), s_hBeam, vecMuzzle, flBeamWidth); rope.SetTextureOffset(((float)i/20) - GameServer()->GetGameTime() - GetSpawnTime()); rope.Finish(vecTarget + vecUp*flUp); } }
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); }
void CLaser::OnSetOwner(CBaseEntity* pOwner) { BaseClass::OnSetOwner(pOwner); CDigitank* pTank = dynamic_cast<CDigitank*>(pOwner); if (!pTank) return; SetGlobalAngles(VectorAngles((pTank->GetLastAim() - GetGlobalOrigin()).Normalized())); SetGlobalOrigin(pOwner->GetGlobalOrigin()); SetGlobalVelocity(Vector(0,0,0)); SetGlobalGravity(Vector(0,0,0)); m_flTimeExploded = GameServer()->GetGameTime(); Vector vecForward, vecRight; AngleVectors(GetGlobalAngles(), &vecForward, &vecRight, NULL); for (size_t i = 0; i < GameServer()->GetMaxEntities(); i++) { CBaseEntity* pEntity = CBaseEntity::GetEntity(i); if (!pEntity) continue; if (!pEntity->TakesDamage()) continue; if (pEntity->GetOwner() == pOwner->GetOwner()) continue; float flDistance = DistanceToPlane(pEntity->GetGlobalOrigin(), GetGlobalOrigin(), vecRight); if (flDistance > 4 + pEntity->GetBoundingRadius()) continue; // Cull objects behind if (vecForward.Dot(pEntity->GetGlobalOrigin() - GetGlobalOrigin()) < 0) continue; if (pEntity->Distance(GetGlobalOrigin()) > LaserLength()) continue; pEntity->TakeDamage(pOwner, this, DAMAGE_LASER, m_flDamage, flDistance < pEntity->GetBoundingRadius()-2); CDigitank* pTank = dynamic_cast<CDigitank*>(pEntity); if (pTank) { float flRockIntensity = 0.5f; Vector vecDirection = (pTank->GetGlobalOrigin() - pOwner->GetGlobalOrigin()).Normalized(); pTank->RockTheBoat(flRockIntensity, vecDirection); } } CDigitanksPlayer* pCurrentTeam = DigitanksGame()->GetCurrentLocalDigitanksPlayer(); if (pCurrentTeam && pCurrentTeam->GetVisibilityAtPoint(GetGlobalOrigin()) < 0.1f) { if (pCurrentTeam->GetVisibilityAtPoint(GetGlobalOrigin() + AngleVector(GetGlobalAngles())*LaserLength()) < 0.1f) { // If the start and end points are both in the fog of war, delete it now that we've aready done the damage so it doesn't get rendered later. if (GameNetwork()->IsHost()) Delete(); } } }
void CLaser::ClientSpawn() { BaseClass::ClientSpawn(); if (DigitanksGame()->GetCurrentLocalDigitanksPlayer()->GetVisibilityAtPoint(GetGlobalOrigin()) < 0.1f) { if (DigitanksGame()->GetCurrentLocalDigitanksPlayer()->GetVisibilityAtPoint(GetGlobalOrigin() + AngleVector(GetGlobalAngles())*LaserLength()) < 0.1f) m_bShouldRender = false; } }