123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #ifdef _D3XP
- #include "Game_local.h"
- #include "Misc.h"
- #define MAX_DRAG_TRACE_DISTANCE 384.0f
- #define TRACE_BOUNDS_SIZE 3.f
- #define HOLD_DISTANCE 72.f
- #define FIRING_DELAY 1000.0f
- #define DRAG_FAIL_LEN 64.f
- #define THROW_SCALE 1000
- #define MAX_PICKUP_VELOCITY 1500 * 1500
- #define MAX_PICKUP_SIZE 96
- /*
- ===============================================================================
- Allows entities to be dragged through the world with physics.
- ===============================================================================
- */
- CLASS_DECLARATION( idEntity, idGrabber )
- END_CLASS
- /*
- ==============
- idGrabber::idGrabber
- ==============
- */
- idGrabber::idGrabber( void ) {
- dragEnt = NULL;
- owner = NULL;
- beam = NULL;
- beamTarget = NULL;
- oldUcmdFlags = 0;
- shakeForceFlip = false;
- holdingAF = false;
- endTime = 0;
- lastFiredTime = -FIRING_DELAY;
- dragFailTime = 0;
- startDragTime = 0;
- warpId = -1;
- dragTraceDist = MAX_DRAG_TRACE_DISTANCE;
- }
- /*
- ==============
- idGrabber::~idGrabber
- ==============
- */
- idGrabber::~idGrabber( void ) {
- StopDrag( true );
- if ( beam ) {
- delete beam;
- }
- if ( beamTarget ) {
- delete beamTarget;
- }
- }
- /*
- ==============
- idGrabber::Save
- ==============
- */
- void idGrabber::Save( idSaveGame *savefile ) const {
- dragEnt.Save( savefile );
- savefile->WriteStaticObject( drag );
- savefile->WriteVec3( saveGravity );
- savefile->WriteInt( id );
- savefile->WriteVec3( localPlayerPoint );
- owner.Save( savefile );
- savefile->WriteBool( holdingAF );
- savefile->WriteBool( shakeForceFlip );
- savefile->WriteInt( endTime );
- savefile->WriteInt( lastFiredTime );
- savefile->WriteInt( dragFailTime );
- savefile->WriteInt( startDragTime );
- savefile->WriteFloat( dragTraceDist );
- savefile->WriteInt( savedContents );
- savefile->WriteInt( savedClipmask );
- savefile->WriteObject( beam );
- savefile->WriteObject( beamTarget );
- savefile->WriteInt( warpId );
- }
- /*
- ==============
- idGrabber::Restore
- ==============
- */
- void idGrabber::Restore( idRestoreGame *savefile ) {
- //Spawn the beams
- Initialize();
- dragEnt.Restore( savefile );
- savefile->ReadStaticObject( drag );
- savefile->ReadVec3( saveGravity );
- savefile->ReadInt( id );
- // Restore the drag force's physics object
- if ( dragEnt.IsValid() ) {
- drag.SetPhysics( dragEnt.GetEntity()->GetPhysics(), id, dragEnt.GetEntity()->GetPhysics()->GetOrigin() );
- }
- savefile->ReadVec3( localPlayerPoint );
- owner.Restore( savefile );
- savefile->ReadBool( holdingAF );
- savefile->ReadBool( shakeForceFlip );
- savefile->ReadInt( endTime );
- savefile->ReadInt( lastFiredTime );
- savefile->ReadInt( dragFailTime );
- savefile->ReadInt( startDragTime );
- savefile->ReadFloat( dragTraceDist );
- savefile->ReadInt( savedContents );
- savefile->ReadInt( savedClipmask );
- savefile->ReadObject( reinterpret_cast<idClass *&>(beam) );
- savefile->ReadObject( reinterpret_cast<idClass *&>(beamTarget) );
- savefile->ReadInt( warpId );
- }
- /*
- ==============
- idGrabber::Initialize
- ==============
- */
- void idGrabber::Initialize( void ) {
- if ( !gameLocal.isMultiplayer ) {
- idDict args;
- if ( !beamTarget ) {
- args.SetVector( "origin", vec3_origin );
- args.SetBool( "start_off", true );
- beamTarget = ( idBeam * )gameLocal.SpawnEntityType( idBeam::Type, &args );
- }
- if ( !beam ) {
- args.Clear();
- args.Set( "target", beamTarget->name.c_str() );
- args.SetVector( "origin", vec3_origin );
- args.SetBool( "start_off", true );
- args.Set( "width", "6" );
- args.Set( "skin", "textures/smf/flareSizeable" );
- args.Set( "_color", "0.0235 0.843 0.969 0.2" );
- beam = ( idBeam * )gameLocal.SpawnEntityType( idBeam::Type, &args );
- beam->SetShaderParm( 6, 1.0f );
- }
- endTime = 0;
- dragTraceDist = MAX_DRAG_TRACE_DISTANCE;
- }
- else {
- beam = NULL;
- beamTarget = NULL;
- endTime = 0;
- dragTraceDist = MAX_DRAG_TRACE_DISTANCE;
- };
- }
- /*
- ==============
- idGrabber::SetDragDistance
- ==============
- */
- void idGrabber::SetDragDistance( float dist ) {
- dragTraceDist = dist;
- }
- /*
- ==============
- idGrabber::StartDrag
- ==============
- */
- void idGrabber::StartDrag( idEntity *grabEnt, int id ) {
- int clipModelId = id;
- idPlayer *thePlayer = owner.GetEntity();
- holdingAF = false;
- dragFailTime = gameLocal.slow.time;
- startDragTime = gameLocal.slow.time;
- oldUcmdFlags = thePlayer->usercmd.flags;
- // set grabbed state for networking
- grabEnt->SetGrabbedState( true );
- // This is the new object to drag around
- dragEnt = grabEnt;
- // Show the beams!
- UpdateBeams();
- if ( beam ) {
- beam->Show();
- }
- if ( beamTarget ) {
- beamTarget->Show();
- }
- // Move the object to the fast group (helltime)
- grabEnt->timeGroup = TIME_GROUP2;
- // Handle specific class types
- if ( grabEnt->IsType( idProjectile::Type ) ) {
- idProjectile* p = (idProjectile*)grabEnt;
- p->CatchProjectile( thePlayer, "_catch" );
- // Make the projectile non-solid to other projectiles/enemies (special hack for helltime hunter)
- if ( !idStr::Cmp( grabEnt->GetEntityDefName(), "projectile_helltime_killer" ) ) {
- savedContents = CONTENTS_PROJECTILE;
- savedClipmask = MASK_SHOT_RENDERMODEL|CONTENTS_PROJECTILE;
- } else {
- savedContents = grabEnt->GetPhysics()->GetContents();
- savedClipmask = grabEnt->GetPhysics()->GetClipMask();
- }
- grabEnt->GetPhysics()->SetContents( 0 );
- grabEnt->GetPhysics()->SetClipMask( CONTENTS_SOLID|CONTENTS_BODY );
- } else if ( grabEnt->IsType( idExplodingBarrel::Type ) ) {
- idExplodingBarrel *ebarrel = static_cast<idExplodingBarrel*>(grabEnt);
- ebarrel->StartBurning();
- } else if ( grabEnt->IsType( idAFEntity_Gibbable::Type ) ) {
- holdingAF = true;
- clipModelId = 0;
- if ( grabbableAI( grabEnt->spawnArgs.GetString( "classname" ) ) ) {
- idAI *aiEnt = static_cast<idAI*>(grabEnt);
- aiEnt->StartRagdoll();
- }
- } else if ( grabEnt->IsType( idMoveableItem::Type ) ) {
- grabEnt->PostEventMS( &EV_Touch, 250, thePlayer, NULL );
- }
- // 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
- localPlayerPoint = ( thePlayer->firstPersonViewAxis[0] * HOLD_DISTANCE ) * thePlayer->firstPersonViewAxis.Transpose();
- // Set the ending time for the hold
- endTime = gameLocal.time + g_grabberHoldSeconds.GetFloat() * 1000;
- // Start up the Force_Drag to bring it in
- drag.Init( g_grabberDamping.GetFloat() );
- drag.SetPhysics( phys, clipModelId, thePlayer->firstPersonViewOrigin + localPlayerPoint * thePlayer->firstPersonViewAxis);
- // start the screen warp
- warpId = thePlayer->playerView.AddWarp( phys->GetOrigin(), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 160, 2000 );
- }
- /*
- ==============
- idGrabber::StopDrag
- ==============
- */
- void idGrabber::StopDrag( bool dropOnly ) {
- idPlayer *thePlayer = owner.GetEntity();
- if ( beam ) {
- beam->Hide();
- }
- if ( beamTarget ) {
- beamTarget->Hide();
- }
- if ( dragEnt.IsValid() ) {
- idEntity *ent = dragEnt.GetEntity();
- // set grabbed state for networking
- ent->SetGrabbedState( false );
- // If a cinematic has started, allow dropped object to think in cinematics
- if ( gameLocal.inCinematic ) {
- ent->cinematic = true;
- }
- // Restore Gravity
- ent->GetPhysics()->SetGravity( saveGravity );
- // Move the object back to the slow group (helltime)
- ent->timeGroup = TIME_GROUP1;
- if ( holdingAF ) {
- idAFEntity_Gibbable *af = static_cast<idAFEntity_Gibbable *>(ent);
- idPhysics_AF *af_Phys = static_cast<idPhysics_AF*>(af->GetPhysics());
- if ( grabbableAI( ent->spawnArgs.GetString( "classname" ) ) ) {
- idAI *aiEnt = static_cast<idAI*>(ent);
- aiEnt->Damage( thePlayer, thePlayer, vec3_origin, "damage_suicide", 1.0f, INVALID_JOINT );
- }
-
- af->SetThrown( !dropOnly );
- // Reset timers so that it isn't forcibly put to rest in mid-air
- af_Phys->PutToRest();
- af_Phys->Activate();
- af_Phys->SetTimeScaleRamp( MS2SEC(gameLocal.slow.time) - 1.5f, MS2SEC(gameLocal.slow.time) + 1.0f );
- }
- // If the object isn't near its goal, just drop it in place.
- if ( !ent->IsType( idProjectile::Type ) && ( dropOnly || drag.GetDistanceToGoal() > DRAG_FAIL_LEN ) ) {
- ent->GetPhysics()->SetLinearVelocity( vec3_origin );
- thePlayer->StartSoundShader( declManager->FindSound( "grabber_maindrop" ), SND_CHANNEL_WEAPON, 0, false, NULL );
- if ( ent->IsType( idExplodingBarrel::Type ) ) {
- idExplodingBarrel *ebarrel = static_cast<idExplodingBarrel*>(ent);
- ebarrel->SetStability( true );
- ebarrel->StopBurning();
- }
- } else {
- // Shoot the object forward
- ent->ApplyImpulse( thePlayer, 0, ent->GetPhysics()->GetOrigin(), thePlayer->firstPersonViewAxis[0] * THROW_SCALE * ent->GetPhysics()->GetMass() );
- thePlayer->StartSoundShader( declManager->FindSound( "grabber_release" ), SND_CHANNEL_WEAPON, 0, false, NULL );
- // Orient projectiles away from the player
- if ( ent->IsType( idProjectile::Type ) ) {
- idPlayer *player = owner.GetEntity();
- idAngles ang = player->firstPersonViewAxis[0].ToAngles();
- ang.pitch += 90.f;
- ent->GetPhysics()->SetAxis( ang.ToMat3() );
- ent->GetPhysics()->SetAngularVelocity( vec3_origin );
- // Restore projectile contents
- ent->GetPhysics()->SetContents( savedContents );
- ent->GetPhysics()->SetClipMask( savedClipmask );
- } else if ( ent->IsType( idMoveable::Type ) ) {
- // Turn on damage for this object
- idMoveable *obj = static_cast<idMoveable*>(ent);
- obj->EnableDamage( true, 2.5f );
- obj->SetAttacker( thePlayer );
- if ( ent->IsType( idExplodingBarrel::Type ) ) {
- idExplodingBarrel *ebarrel = static_cast<idExplodingBarrel*>(ent);
- ebarrel->SetStability( false );
- }
- } else if ( ent->IsType( idMoveableItem::Type ) ) {
- ent->GetPhysics()->SetClipMask( MASK_MONSTERSOLID );
- }
- }
- // Remove the Force_Drag's control of the entity
- drag.RemovePhysics( ent->GetPhysics() );
- }
- if ( warpId != -1 ) {
- thePlayer->playerView.FreeWarp( warpId );
- warpId = -1;
- }
- lastFiredTime = gameLocal.time;
- dragEnt = NULL;
- endTime = 0;
- }
- /*
- ==============
- idGrabber::Update
- ==============
- */
- int idGrabber::Update( idPlayer *player, bool hide ) {
- trace_t trace;
- idEntity *newEnt;
- // pause before allowing refire
- if ( lastFiredTime + FIRING_DELAY > gameLocal.time ) {
- return 3;
- }
- // Dead players release the trigger
- if ( hide || player->health <= 0 ) {
- StopDrag( true );
- if ( hide ) {
- lastFiredTime = gameLocal.time - FIRING_DELAY + 250;
- }
- return 3;
- }
- // Check if object being held has been removed (dead demon, projectile, etc.)
- if ( endTime > gameLocal.time ) {
- bool abort = !dragEnt.IsValid();
- if ( !abort && dragEnt.GetEntity()->IsType( idProjectile::Type ) ) {
- idProjectile *proj = (idProjectile *)dragEnt.GetEntity();
- if ( proj->GetProjectileState() >= 3 ) {
- abort = true;
- }
- }
- if ( !abort && dragEnt.GetEntity()->IsHidden() ) {
- abort = true;
- }
- // Not in multiplayer :: Pressing "reload" lets you carefully drop an item
- if ( !gameLocal.isMultiplayer && !abort && (( player->usercmd.flags & UCF_IMPULSE_SEQUENCE ) != ( oldUcmdFlags & UCF_IMPULSE_SEQUENCE )) && (player->usercmd.impulse == IMPULSE_13) ) {
- abort = true;
- }
-
- if ( abort ) {
- StopDrag( true );
- return 3;
- }
- }
- owner = player;
- // if no entity selected for dragging
- if ( !dragEnt.GetEntity() ) {
- idBounds bounds;
- idVec3 end = player->firstPersonViewOrigin + player->firstPersonViewAxis[0] * dragTraceDist;
- bounds.Zero();
- bounds.ExpandSelf( TRACE_BOUNDS_SIZE );
- gameLocal.clip.TraceBounds( trace, player->firstPersonViewOrigin, end, bounds, MASK_SHOT_RENDERMODEL|CONTENTS_PROJECTILE|CONTENTS_MOVEABLECLIP, player );
- // If the trace hit something
- if ( trace.fraction < 1.0f ) {
- newEnt = gameLocal.entities[ trace.c.entityNum ];
- // if entity is already being grabbed then bypass
- if ( gameLocal.isMultiplayer && newEnt->IsGrabbed() ) {
- return 0;
- }
- // Check if this is a valid entity to hold
- if ( newEnt && ( newEnt->IsType( idMoveable::Type ) ||
- newEnt->IsType( idMoveableItem::Type ) ||
- newEnt->IsType( idProjectile::Type ) ||
- newEnt->IsType( idAFEntity_Gibbable::Type ) ) &&
- newEnt->noGrab == false &&
- newEnt->GetPhysics()->GetBounds().GetRadius() < MAX_PICKUP_SIZE &&
- newEnt->GetPhysics()->GetLinearVelocity().LengthSqr() < MAX_PICKUP_VELOCITY ) {
- bool validAF = true;
- if ( newEnt->IsType( idAFEntity_Gibbable::Type ) ) {
- idAFEntity_Gibbable *afEnt = static_cast<idAFEntity_Gibbable*>(newEnt);
- if ( grabbableAI( newEnt->spawnArgs.GetString( "classname" ) ) ) {
- // Make sure it's also active
- if ( !afEnt->IsActive() ) {
- validAF = false;
- }
- } else if ( !afEnt->IsActiveAF() ) {
- validAF = false;
- }
- }
- if ( validAF && player->usercmd.buttons & BUTTON_ATTACK ) {
- // Grab this entity and start dragging it around
- StartDrag( newEnt, trace.c.id );
- } else if ( validAF ) {
- // A holdable object is ready to be grabbed
- return 1;
- }
- }
- }
- }
- // check backwards server time in multiplayer
- bool allow = true;
- if ( gameLocal.isMultiplayer ) {
- // if we've marched backwards
- if ( gameLocal.slow.time < startDragTime ) {
- allow = false;
- }
- }
- // if there is an entity selected for dragging
- if ( dragEnt.GetEntity() && allow ) {
- idPhysics *entPhys = dragEnt.GetEntity()->GetPhysics();
- idVec3 goalPos;
- // If the player lets go of attack, or time is up
- if ( !( player->usercmd.buttons & BUTTON_ATTACK ) ) {
- StopDrag( false );
- return 3;
- }
- if ( gameLocal.time > endTime ) {
- StopDrag( true );
- return 3;
- }
- // Check if the player is standing on the object
- if ( !holdingAF ) {
- 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.f;
- playerBounds.AddPoint( newPoint );
- playerBounds.ExpandSelf( 8.f );
- // If it intersects the object bounds, then drop it
- if ( playerBounds.IntersectsBounds( objectBounds ) ) {
- StopDrag( true );
- return 3;
- }
- }
- // Shake the object at the end of the hold
- if ( g_grabberEnableShake.GetBool() && !gameLocal.isMultiplayer ) {
- ApplyShake();
- }
- // Set and evaluate drag force
- goalPos = player->firstPersonViewOrigin + localPlayerPoint * player->firstPersonViewAxis;
- drag.SetGoalPosition( goalPos );
- drag.Evaluate( gameLocal.time );
- // If an object is flying too fast toward the player, stop it hard
- if ( g_grabberHardStop.GetBool() ) {
- idPlane theWall;
- idVec3 toPlayerVelocity, objectCenter;
- float toPlayerSpeed;
- toPlayerVelocity = -player->firstPersonViewAxis[0];
- toPlayerSpeed = entPhys->GetLinearVelocity() * toPlayerVelocity;
- if ( toPlayerSpeed > 64.f ) {
- objectCenter = entPhys->GetAbsBounds().GetCenter();
- theWall.SetNormal( player->firstPersonViewAxis[0] );
- theWall.FitThroughPoint( goalPos );
- if ( theWall.Side( objectCenter, 0.1f ) == PLANESIDE_BACK ) {
- int i, num;
- num = entPhys->GetNumClipModels();
- for ( i=0; i<num; i++ ) {
- entPhys->SetLinearVelocity( vec3_origin, i );
- }
- }
- }
- // Make sure the object isn't spinning too fast
- const float MAX_ROTATION_SPEED = 12.f;
- idVec3 angVel = entPhys->GetAngularVelocity();
- float rotationSpeed = angVel.LengthFast();
- if ( rotationSpeed > MAX_ROTATION_SPEED ) {
- angVel.NormalizeFast();
- angVel *= MAX_ROTATION_SPEED;
- entPhys->SetAngularVelocity( angVel );
- }
- }
- // Orient projectiles away from the player
- if ( dragEnt.GetEntity()->IsType( idProjectile::Type ) ) {
- idAngles ang = player->firstPersonViewAxis[0].ToAngles();
- ang.pitch += 90.f;
- entPhys->SetAxis( ang.ToMat3() );
- }
- // Some kind of effect from gun to object?
- UpdateBeams();
- // 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.slow.time - 500) ) {
- StopDrag( true );
- return 3;
- }
- } else {
- dragFailTime = gameLocal.slow.time;
- }
- // Currently holding an object
- return 2;
- }
- // Not holding, nothing to hold
- return 0;
- }
- /*
- ======================
- idGrabber::UpdateBeams
- ======================
- */
- void idGrabber::UpdateBeams( void ) {
- jointHandle_t muzzle_joint;
- idVec3 muzzle_origin;
- idMat3 muzzle_axis;
- renderEntity_t *re;
- if ( !beam ) {
- return;
- }
- if ( dragEnt.IsValid() ) {
- idPlayer *thePlayer = owner.GetEntity();
- if ( beamTarget ) {
- beamTarget->SetOrigin( dragEnt.GetEntity()->GetPhysics()->GetAbsBounds().GetCenter() );
- }
- muzzle_joint = thePlayer->weapon.GetEntity()->GetAnimator()->GetJointHandle( "particle_upper" );
- if ( muzzle_joint != INVALID_JOINT ) {
- thePlayer->weapon.GetEntity()->GetJointWorldTransform( muzzle_joint, gameLocal.time, muzzle_origin, muzzle_axis );
- } else {
- muzzle_origin = thePlayer->GetPhysics()->GetOrigin();
- }
- beam->SetOrigin( muzzle_origin );
- re = beam->GetRenderEntity();
- re->origin = muzzle_origin;
- beam->UpdateVisuals();
- beam->Present();
- }
- }
- /*
- ==============
- idGrabber::ApplyShake
- ==============
- */
- void idGrabber::ApplyShake( void ) {
- float u = 1 - (float)( endTime - gameLocal.time ) / ( g_grabberHoldSeconds.GetFloat() * 1000 );
- if ( u >= 0.8f ) {
- idVec3 point, impulse;
- float shakeForceMagnitude = 450.f;
- float mass = dragEnt.GetEntity()->GetPhysics()->GetMass();
- shakeForceFlip = !shakeForceFlip;
- // get point to rotate around
- point = dragEnt.GetEntity()->GetPhysics()->GetOrigin();
- point.y += 1;
- // Articulated figures get less violent shake
- if ( holdingAF ) {
- shakeForceMagnitude = 120.f;
- }
- // calc impulse
- if ( shakeForceFlip ) {
- impulse.Set( 0, 0, shakeForceMagnitude * u * mass );
- }
- else {
- impulse.Set( 0, 0, -shakeForceMagnitude * u * mass );
- }
- dragEnt.GetEntity()->ApplyImpulse( NULL, 0, point, impulse );
- }
- }
- /*
- ==============
- idGrabber::grabbableAI
- ==============
- */
- bool idGrabber::grabbableAI( const char *aiName ) {
- // skip "monster_"
- aiName += 8;
- if (!idStr::Cmpn( aiName, "flying_lostsoul", 15 ) ||
- !idStr::Cmpn( aiName, "demon_trite", 11 ) ||
- !idStr::Cmp( aiName, "flying_forgotten" ) ||
- !idStr::Cmp( aiName, "demon_cherub" ) ||
- !idStr::Cmp( aiName, "demon_tick" )) {
- return true;
- }
- return false;
- }
- #endif
|