dhewm3-sdk/d3xp/Grab.cpp
Daniel Gibson a8e0cda873 CMake integration of Sikkmod, changes to code to make it compile
no idea if it works, but it builds :-p
2024-06-21 03:37:30 +02:00

213 lines
5.7 KiB
C++

// sikk---> Object Manipulation
#include "Game_local.h"
#include "Grab.h"
#include "Misc.h"
#include "Player.h"
#include "gamesys/SysCvar.h"
#define MAX_DRAG_TRACE_DISTANCE 80.0f
#define TRACE_BOUNDS_SIZE 3.0f
#define MAX_HOLD_DISTANCE 96.0f
#define MIN_HOLD_DISTANCE 48.0f
#define DRAG_FAIL_LEN 64.0f
#define FAIL_TIME 1000
#define THROW_TIME 500
#define THROW_SCALE 20000
#define MAX_PICKUP_VELOCITY 1000 * 1000
#define MAX_PICKUP_SIZE 96.0f
/*
===============================================================================
Allows entities to be dragged through the world with physics.
===============================================================================
*/
CLASS_DECLARATION( idEntity, idGrabEntity )
END_CLASS
/*
==============
idGrabEntity::idGrabEntity
==============
*/
idGrabEntity::idGrabEntity( void ) {
Clear();
}
/*
==============
idGrabEntity::~idGrabEntity
==============
*/
idGrabEntity::~idGrabEntity( void ) {
StopDrag( owner, true );
}
/*
==============
idGrabEntity::Clear
==============
*/
void idGrabEntity::Clear() {
dragEnt = NULL;
owner = NULL;
id = 0;
oldUcmdFlags = 0;
dragFailTime = 0;
lastThrownTime = 0;
localPlayerPoint.Zero();
saveGravity.Zero();
}
/*
==============
idGrabEntity::StartDrag
==============
*/
void idGrabEntity::StartDrag( idPlayer *player, idEntity *grabEnt, int id ) {
if ( grabEnt && grabEnt->GetPhysics()->GetBounds().GetRadius() < MAX_PICKUP_SIZE &&
grabEnt->GetPhysics()->GetLinearVelocity().LengthSqr() < MAX_PICKUP_VELOCITY ) {
dragFailTime = gameLocal.time + FAIL_TIME;
oldUcmdFlags = player->usercmd.flags;
// This is the new object to drag around
dragEnt = grabEnt;
// Get the current physics object to manipulate
idPhysics *phys = grabEnt->GetPhysics();
// Turn off gravity on object
saveGravity = phys->GetGravity();
phys->SetGravity( vec3_origin );
// hold it directly in front of player, distance depends on object size
float lerp = 1.0f - ( grabEnt->GetPhysics()->GetBounds().GetRadius() / MAX_HOLD_DISTANCE );
lerp *= lerp;
float holdDist = lerp * MIN_HOLD_DISTANCE + ( 1.0f - lerp ) * MAX_HOLD_DISTANCE;
localPlayerPoint = ( player->firstPersonViewAxis[0] * holdDist ) * player->firstPersonViewAxis.Transpose();
// Start up the Force_Drag to bring it in
drag.Init( g_dragDamping.GetFloat() );
drag.SetPhysics( phys, id, player->firstPersonViewOrigin + localPlayerPoint * player->firstPersonViewAxis );
player->StartSoundShader( declManager->FindSound( "use_grab" ), SND_CHANNEL_VOICE, 0, false, NULL );
}
}
/*
==============
idGrabEntity::StopDrag
==============
*/
void idGrabEntity::StopDrag( idPlayer *player, bool drop ) {
if ( dragEnt.IsValid() ) {
idEntity *ent = dragEnt.GetEntity();
// If a cinematic has started, allow dropped object to think in cinematics
if ( gameLocal.inCinematic )
ent->cinematic = true;
// Restore Gravity
ent->GetPhysics()->SetGravity( saveGravity );
// If the object isn't near its goal, just drop it in place.
if ( drop || drag.GetDistanceToGoal() > DRAG_FAIL_LEN ) {
ent->GetPhysics()->SetLinearVelocity( vec3_origin );
} else { // throw the object forward
ent->ApplyImpulse( player, 0, ent->GetPhysics()->GetOrigin(), player->firstPersonViewAxis[0] * THROW_SCALE );
player->StartSoundShader( declManager->FindSound( "use_throw" ), SND_CHANNEL_VOICE, 0, false, NULL );
}
// Remove the Force_Drag's control of the entity
drag.RemovePhysics( ent->GetPhysics() );
lastThrownTime = gameLocal.time + THROW_TIME;
}
dragEnt = NULL;
}
/*
==============
idGrabEntity::Update
==============
*/
void idGrabEntity::Update( idPlayer *player ) {
owner = player;
if ( lastThrownTime > gameLocal.time ) {
prevViewAngles = player->viewAngles;
return;
}
bool valid = dragEnt.IsValid();
// Check if object being held has been removed or player is dead
if ( valid && dragEnt.GetEntity()->IsHidden() || player->health <= 0 ) {
StopDrag( player, true );
prevViewAngles = player->viewAngles;
return;
}
// attack throws object
if ( valid && player->usercmd.buttons & BUTTON_ATTACK ) {
StopDrag( player, false );
prevViewAngles = player->viewAngles;
return;
}
// if there is an entity selected for dragging
if ( dragEnt.GetEntity() ) {
idPhysics *entPhys = dragEnt.GetEntity()->GetPhysics();
idVec3 goalPos;
// Check if the player is standing on the object
idBounds playerBounds;
idBounds objectBounds = entPhys->GetAbsBounds();
idVec3 newPoint = player->GetPhysics()->GetOrigin();
// create a bounds at the players feet
playerBounds.Clear();
playerBounds.AddPoint( newPoint );
newPoint.z -= 1.0f;
playerBounds.AddPoint( newPoint );
playerBounds.ExpandSelf( 8.0f );
// If it intersects the object bounds, then drop it
if ( playerBounds.IntersectsBounds( objectBounds ) ) {
StopDrag( player, true );
prevViewAngles = player->viewAngles;
return;
}
idAngles ang = entPhys->GetAxis().ToAngles();
ang.yaw += player->viewAngles.yaw - prevViewAngles.yaw;
if ( ang.yaw > 180.0f )
ang.yaw -= 360.0f;
else if ( ang.yaw < -180.0f )
ang.yaw += 360.0f;
entPhys->SetAxis( ang.ToMat3() );
// Set and evaluate drag force
goalPos = player->firstPersonViewOrigin + localPlayerPoint * player->firstPersonViewAxis;
drag.SetGoalPosition( goalPos );
drag.Evaluate( gameLocal.time, false );
// If the object is stuck away from its intended position for more than 500ms, let it go.
if ( drag.GetDistanceToGoal() > DRAG_FAIL_LEN ) {
if ( dragFailTime < gameLocal.time ) {
StopDrag( player, true );
prevViewAngles = player->viewAngles;
return;
}
} else {
dragFailTime = gameLocal.time + 1000;
}
}
prevViewAngles = player->viewAngles;
}
// <---sikk