Files
2026-05-05 15:01:01 -07:00

152 lines
4.3 KiB
C++

// Game_Sphere.cpp
//
// pushable exploding sphere
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
CLASS_DECLARATION(hhMoveable, hhSphere)
EVENT( EV_Touch, hhSphere::Event_Touch )
END_CLASS
hhSphere::hhSphere() {
additionalAxis.Identity();
}
void hhSphere::Spawn(void) {
radius = (GetPhysics()->GetBounds()[1][0] - GetPhysics()->GetBounds()[0][0]) * 0.5f;
lastOrigin = GetPhysics()->GetOrigin();
additionalAxis.Identity();
CreateLight();
fl.takedamage = false;
BecomeActive(TH_THINK);
}
void hhSphere::Save( idSaveGame *savefile ) const {
savefile->WriteFloat( radius );
savefile->WriteVec3( lastOrigin );
savefile->WriteMat3( additionalAxis );
light.Save(savefile);
}
void hhSphere::Restore( idRestoreGame *savefile ) {
savefile->ReadFloat( radius );
savefile->ReadVec3( lastOrigin );
savefile->ReadMat3( additionalAxis );
light.Restore(savefile);
}
void hhSphere::CreateLight() {
if ( spawnArgs.GetBool("haslight") ) {
idStr light_shader = spawnArgs.GetString("mtr_light");
idVec3 light_color = spawnArgs.GetVector("light_color");
idVec3 light_frustum = spawnArgs.GetVector("light_frustum");
idVec3 light_offset = spawnArgs.GetVector("offset_light");
idVec3 light_target = spawnArgs.GetVector("offset_lighttarget");
idDict args;
idVec3 lightOrigin = GetPhysics()->GetOrigin() + light_offset * GetPhysics()->GetAxis();
light_target.Normalize();
idMat3 lightAxis = (light_target * GetPhysics()->GetAxis()).hhToMat3();
if ( light_shader.Length() ) {
args.Set( "texture", light_shader );
}
args.SetVector( "origin", lightOrigin );
args.Set ("angles", lightAxis.ToAngles().ToString());
args.SetVector( "_color", light_color );
args.SetVector( "light_target", lightAxis[0] * light_frustum.x );
args.SetVector( "light_right", lightAxis[1] * light_frustum.y );
args.SetVector( "light_up", lightAxis[2] * light_frustum.z );
light = ( idLight * )gameLocal.SpawnEntityType( idLight::Type, &args );
light->Bind(this, true);
light->SetLightParm( 6, 1.0f );
light->SetLightParm( SHADERPARM_TIMEOFFSET, -MS2SEC(gameLocal.time) );
}
}
void hhSphere::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
// skip idMoveable::Damage which handles damage differently
idEntity::Damage(inflictor, attacker, dir, damageDefName, damageScale, location);
}
void hhSphere::RollThink( void ) {
float movedDistance, angle;
idVec3 curOrigin, gravityNormal, dir;
bool wasAtRest = IsAtRest();
RunPhysics();
// only need to give the visual model an additional rotation if the physics were run
if ( !wasAtRest ) {
// current physics state
curOrigin = GetPhysics()->GetOrigin();
dir = curOrigin - lastOrigin;
float movedDistanceSquared = dir.LengthSqr();
// if the sphere moved
if ( movedDistanceSquared > 0.0f && movedDistanceSquared < 20.0f) {
gravityNormal = GetPhysics()->GetGravityNormal();
// movement since last frame
movedDistance = idMath::Sqrt( movedDistanceSquared );
dir *= 1.0f / movedDistance;
// Get local coordinate axes
idVec3 right = -dir.Cross(gravityNormal);
// Rotate about it proportional to the distance moved using axis/angle
angle = 180.0f * movedDistance / (radius*idMath::PI);
additionalAxis *= (idRotation( vec3_origin, right, angle).ToMat3());
}
// save state for next think
lastOrigin = curOrigin;
}
Present();
}
void hhSphere::Think() {
RollThink();
}
void hhSphere::ClientPredictionThink( void ) {
RollThink();
}
bool hhSphere::GetPhysicsToVisualTransform( idVec3 &origin, idMat3 &axis ) {
origin = vec3_origin;
axis = additionalAxis * GetPhysics()->GetAxis().Inverse();
return true;
}
void hhSphere::Event_Touch( idEntity *other, trace_t *trace ) {
if (spawnArgs.GetBool("walkthrough")) {
idVec3 otherVel = other->GetPhysics()->GetLinearVelocity();
float otherSpeed = otherVel.NormalizeFast();
if (otherSpeed > 50.0f) { // && GetPhysics()->IsAtRest()) {
idVec3 toSide = hhUtils::RandomSign() * other->GetAxis()[1];
idVec3 toMoveable = GetOrigin() - other->GetOrigin();
toMoveable.NormalizeFast();
idVec3 newVel = ( 3*otherVel + toSide + hhUtils::RandomVector() ) * (1.0f/5.0f);
newVel.z = 0.0f;
newVel.NormalizeFast();
newVel *= otherSpeed*1.5f;
GetPhysics()->SetLinearVelocity(newVel);
}
}
}