Skip to content

Commit

Permalink
Fixes for idSpring (func_spring) from FraggingFree by IvanTheB, fix #31
Browse files Browse the repository at this point in the history
In addition to Ivans code I made two small changes:
- Add "compress" and "pullEnt1" spawnargs so those can be set when
  initializing the underlying idForce_Spring
- Made "pullEnt1" true by default (in FraggingFree it's hardcoded
  to false)

"pullEnt1" specifies whether the entity connected through "ent1" can be
moved by the spring - if it's set to 0, only ent2 can be moved by the
spring and ent1 is either stationary or moved by other means/forces,
so with "pullEnt1" "0", ent1 drags ent2 along, but not the other way
around.
"compress" is like "constant" (aka Kstretch), but for compressing when
below the "restlength" instead of stretching when above it.
  • Loading branch information
DanielGibson committed Jan 22, 2025
1 parent 63b84a8 commit c72353c
Show file tree
Hide file tree
Showing 8 changed files with 426 additions and 84 deletions.
140 changes: 114 additions & 26 deletions neo/d3xp/Misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,44 +665,70 @@ void idExplodable::Event_Explode( idEntity *activator ) {
idSpring
Enhancements (like Save/Restore functions) taken from FraggingFree by IvanTheB
https://github.com/IvanTheB/fraggingfree-dhewm3-sdk
https://www.moddb.com/mods/fragging-free
===============================================================================
*/

CLASS_DECLARATION( idEntity, idSpring )
EVENT( EV_PostSpawn, idSpring::Event_LinkSpring )
END_CLASS

/*
================
idSpring::idSpring
================
*/
idSpring::idSpring( void ){
ent1 = NULL;
ent2 = NULL;
id1 = 0;
id2 = 0;
p1 = vec3_origin;
p2 = vec3_origin;
enabled = false;
}

/*
================
idSpring::Think
================
*/
void idSpring::Think( void ) {
idVec3 start, end, origin;
idMat3 axis;

// run physics
RunPhysics();

if ( thinkFlags & TH_THINK ) {
// evaluate force
spring.Evaluate( gameLocal.time );
if ( enabled && ent1.GetEntity() && ent2.GetEntity() ) {
// evaluate force
spring.Evaluate( gameLocal.time );

if ( g_debugMover.GetBool() ) { //ivan
idVec3 start, end, origin;
idMat3 axis;

start = p1;
if ( ent1.GetEntity()->GetPhysics() ) {
axis = ent1.GetEntity()->GetPhysics()->GetAxis();
origin = ent1.GetEntity()->GetPhysics()->GetOrigin();
start = origin + start * axis;
}

start = p1;
if ( ent1->GetPhysics() ) {
axis = ent1->GetPhysics()->GetAxis();
origin = ent1->GetPhysics()->GetOrigin();
start = origin + start * axis;
}
end = p2;
if ( ent2.GetEntity()->GetPhysics() ) {
axis = ent2.GetEntity()->GetPhysics()->GetAxis();
origin = ent2.GetEntity()->GetPhysics()->GetOrigin();
end = origin + p2 * axis;
}

end = p2;
if ( ent2->GetPhysics() ) {
axis = ent2->GetPhysics()->GetAxis();
origin = ent2->GetPhysics()->GetOrigin();
end = origin + p2 * axis;
gameRenderWorld->DebugLine( idVec4(1, 1, 0, 1), start, end, 0, true );
}
} else {
BecomeInactive( TH_THINK );
}

gameRenderWorld->DebugLine( idVec4(1, 1, 0, 1), start, end, 0, true );
}

Present();
Expand All @@ -721,8 +747,8 @@ void idSpring::Event_LinkSpring( void ) {

if ( name1.Length() ) {
ent1 = gameLocal.FindEntity( name1 );
if ( !ent1 ) {
gameLocal.Error( "idSpring '%s' at (%s): cannot find first entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name1.c_str() );
if ( !ent1.GetEntity() ) {
gameLocal.Warning( "idSpring '%s' at (%s): cannot find first entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name1.c_str() );
}
}
else {
Expand All @@ -731,15 +757,20 @@ void idSpring::Event_LinkSpring( void ) {

if ( name2.Length() ) {
ent2 = gameLocal.FindEntity( name2 );
if ( !ent2 ) {
gameLocal.Error( "idSpring '%s' at (%s): cannot find second entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name2.c_str() );
if ( !ent2.GetEntity() ) {
gameLocal.Warning( "idSpring '%s' at (%s): cannot find second entity '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), name2.c_str() );
}
}
else {
ent2 = gameLocal.entities[ENTITYNUM_WORLD];
}
spring.SetPosition( ent1->GetPhysics(), id1, p1, ent2->GetPhysics(), id2, p2 );
BecomeActive( TH_THINK );

if ( ent1.GetEntity() && ent2.GetEntity() ) {
spring.SetPosition( ent1.GetEntity()->GetPhysics(), id1, p1, ent2.GetEntity()->GetPhysics(), id2, p2 );
if( enabled ){
BecomeActive( TH_THINK );
}
}
}

/*
Expand All @@ -748,23 +779,80 @@ idSpring::Spawn
================
*/
void idSpring::Spawn( void ) {
float Kstretch, damping, restLength;
float Kstretch, Kcompress, damping, restLength, maxLength;
bool pullEnt1 = true;

enabled = !spawnArgs.GetBool( "start_off" );
spawnArgs.GetInt( "id1", "0", id1 );
spawnArgs.GetInt( "id2", "0", id2 );
spawnArgs.GetVector( "point1", "0 0 0", p1 );
spawnArgs.GetVector( "point2", "0 0 0", p2 );
spawnArgs.GetFloat( "constant", "100.0f", Kstretch );
spawnArgs.GetFloat( "damping", "10.0f", damping );
spawnArgs.GetFloat( "restlength", "0.0f", restLength );
spawnArgs.GetFloat( "maxLength", "200.0f", maxLength );
// DG: added compress and pullEntity1 so the corresponding parameter of idForce_Spring can be set
spawnArgs.GetFloat( "compress", "0.0f", Kcompress );
spawnArgs.GetBool( "pullEnt1", "1", pullEnt1 );

spring.InitSpring( Kstretch, 0.0f, damping, restLength );
spring.InitSpring( Kstretch, Kcompress, damping, restLength, maxLength, pullEnt1 );

ent1 = ent2 = NULL;

PostEventMS( &EV_PostSpawn, 0 );
}

/*
===============
idSpring::Activate
================
*/
void idSpring::Event_Activate( idEntity *activator ) {
enabled = !enabled;
if ( enabled ) {
BecomeActive( TH_THINK );
} else {
BecomeInactive( TH_THINK );
}
}

/*
================
idSpring::Save
================
*/
void idSpring::Save( idSaveGame *savefile ) const {
ent1.Save( savefile );
ent2.Save( savefile );
savefile->WriteInt( id1 );
savefile->WriteInt( id2 );
savefile->WriteVec3( p1 );
savefile->WriteVec3( p2 );
savefile->WriteBool( enabled );

savefile->WriteStaticObject( spring );
}

/*
================
idSpring::Restore
================
*/
void idSpring::Restore( idRestoreGame *savefile ) {
ent1.Restore( savefile );
ent2.Restore( savefile );
savefile->ReadInt( id1 );
savefile->ReadInt( id2 );
savefile->ReadVec3( p1 );
savefile->ReadVec3( p2 );
savefile->ReadBool( enabled );

savefile->ReadStaticObject( spring );

PostEventMS( &EV_PostSpawn, 0 ); //initialize the spring asap but not now!
}


/*
===============================================================================
Expand Down
33 changes: 22 additions & 11 deletions neo/d3xp/Misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,27 +203,38 @@ class idExplodable : public idEntity {
idSpring
Enhancements (like Save/Restore functions) taken from FraggingFree by IvanTheB
https://github.com/IvanTheB/fraggingfree-dhewm3-sdk
https://www.moddb.com/mods/fragging-free
===============================================================================
*/

class idSpring : public idEntity {
public:
CLASS_PROTOTYPE( idSpring );

void Spawn( void );
idSpring(); //ivan
void Spawn( void );

virtual void Think( void );
void Save( idSaveGame *savefile ) const; //ivan
void Restore( idRestoreGame *savefile ); //ivan

virtual void Think( void );

private:
idEntity * ent1;
idEntity * ent2;
int id1;
int id2;
idVec3 p1;
idVec3 p2;
idForce_Spring spring;

void Event_LinkSpring( void );
idEntityPtr<idEntity> ent1;
idEntityPtr<idEntity> ent2;
int id1;
int id2;
idVec3 p1;
idVec3 p2;
idForce_Spring spring;
bool enabled; //ivan

void Event_LinkSpring( void );
void Event_Activate( idEntity *activator );
};


Expand Down
70 changes: 67 additions & 3 deletions neo/d3xp/physics/Force_Spring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ If you have questions concerning this license or the applicable additional terms

#include "sys/platform.h"
#include "physics/Physics.h"
#include "gamesys/SaveGame.h"

#include "physics/Force_Spring.h"

Expand All @@ -44,6 +45,9 @@ idForce_Spring::idForce_Spring( void ) {
Kcompress = 100.0f;
damping = 0.0f;
restLength = 0.0f;
maxLength = 0.0f; // added by ivan for FraggingFree
pullEntity1 = false; // added by ivan for FraggingFree

physics1 = NULL;
id1 = 0;
p1 = vec3_zero;
Expand All @@ -60,16 +64,72 @@ idForce_Spring::~idForce_Spring
idForce_Spring::~idForce_Spring( void ) {
}

//ivan start
/*
================
idForce_Spring::Save
================
*/
void idForce_Spring::Save( idSaveGame *savefile ) const {
savefile->WriteFloat( Kstretch );
savefile->WriteFloat( Kcompress );
savefile->WriteFloat( damping );
savefile->WriteFloat( restLength );
savefile->WriteFloat( maxLength );
savefile->WriteBool( pullEntity1 );

/*
//Not saved:
savefile->WriteInt( id1 );
savefile->WriteInt( id2 );
savefile->WriteVec3( p1 );
savefile->WriteVec3( p2 );
physics1
physics2
*/
}

/*
================
idForce_Spring::Restore
================
*/
void idForce_Spring::Restore( idRestoreGame *savefile ) {
savefile->ReadFloat( Kstretch );
savefile->ReadFloat( Kcompress );
savefile->ReadFloat( damping );
savefile->ReadFloat( restLength );
savefile->ReadFloat( maxLength );
savefile->ReadBool( pullEntity1 );

/*
// Owner needs to call SetPosition before Evaluate!!
//Not saved:
savefile->ReadInt( id1 );
savefile->ReadInt( id2 );
savefile->ReadVec3( p1 );
savefile->ReadVec3( p2 );
physics1
physics2
*/
}
//ivan end

/*
================
idForce_Spring::InitSpring
================
*/
void idForce_Spring::InitSpring( float Kstretch, float Kcompress, float damping, float restLength ) {
void idForce_Spring::InitSpring( float Kstretch, float Kcompress, float damping, float restLength, float maxLength, bool pullEntity1 ) {
this->Kstretch = Kstretch;
this->Kcompress = Kcompress;
this->damping = damping;
this->restLength = restLength;
this->maxLength = maxLength;
this->pullEntity1 = pullEntity1;
}

/*
Expand Down Expand Up @@ -125,11 +185,15 @@ void idForce_Spring::Evaluate( int time ) {
dampingForce = ( damping * ( ((velocity2 - velocity1) * force) / (force * force) ) ) * force;
length = force.Normalize();

if ( length > maxLength ) { //ff1.3
length = maxLength;
}

// if the spring is stretched
if ( length > restLength ) {
if ( Kstretch > 0.0f ) {
force = ( Square( length - restLength ) * Kstretch ) * force - dampingForce;
if ( physics1 ) {
if ( pullEntity1 && physics1 ) {
physics1->AddForce( id1, pos1, force );
}
if ( physics2 ) {
Expand All @@ -140,7 +204,7 @@ void idForce_Spring::Evaluate( int time ) {
else {
if ( Kcompress > 0.0f ) {
force = ( Square( length - restLength ) * Kcompress ) * force - dampingForce;
if ( physics1 ) {
if ( pullEntity1 && physics1 ) {
physics1->AddForce( id1, pos1, -force );
}
if ( physics2 ) {
Expand Down
Loading

0 comments on commit c72353c

Please sign in to comment.