375 lines
7.7 KiB
Plaintext
375 lines
7.7 KiB
Plaintext
/*
|
|
* Copyright (c) 2023-2024 Vera Visions LLC.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
.vector movedir;
|
|
.entity aiment;
|
|
|
|
void
|
|
NSPhysicsConstraint::NSPhysicsConstraint(void)
|
|
{
|
|
m_flTorqueLimit = 0.0f;
|
|
m_flForceLimit = 0.0f;
|
|
m_strEnt1 = __NULL__;
|
|
m_strEnt2 = __NULL__;
|
|
m_strBreakSound = __NULL__;
|
|
m_strOnBreak = __NULL__;
|
|
m_strConstraintSystem = __NULL__;
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::ConstraintThink(void)
|
|
{
|
|
NSPhysicsEntity target1 = (NSPhysicsEntity)GetEntity1();
|
|
NSPhysicsEntity target2 = (NSPhysicsEntity)GetEntity1();
|
|
|
|
/* never run again */
|
|
if (m_flForceLimit <= 0 && m_flTorqueLimit <= 0)
|
|
return;
|
|
|
|
if (m_flForceLimit > 0)
|
|
if (vlen(target1.GetVelocity()) > m_flForceLimit) {
|
|
Break(this);
|
|
return;
|
|
}
|
|
|
|
if (m_flTorqueLimit > 0)
|
|
if (vlen(target1.GetAngularVelocity()) > m_flTorqueLimit) {
|
|
Break(this);
|
|
return;
|
|
}
|
|
|
|
if (m_flForceLimit > 0)
|
|
if (vlen(target2.GetVelocity()) > m_flForceLimit) {
|
|
Break(this);
|
|
return;
|
|
}
|
|
|
|
if (m_flTorqueLimit > 0)
|
|
if (vlen(target2.GetAngularVelocity()) > m_flTorqueLimit) {
|
|
Break(this);
|
|
return;
|
|
}
|
|
SetNextThink(0.0f);
|
|
}
|
|
|
|
#ifdef SERVER
|
|
void
|
|
NSPhysicsConstraint::Save(float handle)
|
|
{
|
|
super::Save(handle);
|
|
SaveFloat(handle, "m_flTorqueLimit", m_flTorqueLimit);
|
|
SaveFloat(handle, "m_flForceLimit", m_flForceLimit);
|
|
SaveString(handle, "m_strEnt1", m_strEnt1);
|
|
SaveString(handle, "m_strEnt2", m_strEnt2);
|
|
SaveString(handle, "m_strBreakSound", m_strBreakSound);
|
|
SaveString(handle, "m_strOnBreak", m_strOnBreak);
|
|
SaveString(handle, "m_strConstraintSystem", m_strConstraintSystem);
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::Restore(string strKey, string strValue)
|
|
{
|
|
switch (strKey) {
|
|
case "m_flTorqueLimit":
|
|
m_flTorqueLimit = ReadFloat(strValue);
|
|
break;
|
|
case "m_flForceLimit":
|
|
m_flForceLimit = ReadFloat(strValue);
|
|
break;
|
|
case "m_strEnt1":
|
|
m_strEnt1 = ReadString(strValue);
|
|
break;
|
|
case "m_strEnt2":
|
|
m_strEnt2 = ReadString(strValue);
|
|
break;
|
|
case "m_strBreakSound":
|
|
m_strBreakSound = ReadString(strValue);
|
|
break;
|
|
case "m_strOnBreak":
|
|
m_strOnBreak = ReadString(strValue);
|
|
break;
|
|
case "m_strConstraintSystem":
|
|
m_strConstraintSystem = ReadString(strValue);
|
|
break;
|
|
default:
|
|
super::Restore(strKey, strValue);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
NSPhysicsConstraint::SpawnKey(string keyName, string setValue)
|
|
{
|
|
switch (keyName) {
|
|
case "attach1":
|
|
m_strEnt1 = ReadString(setValue);
|
|
break;
|
|
case "attach2":
|
|
m_strEnt2 = ReadString(setValue);
|
|
break;
|
|
case "torquelimit":
|
|
m_flTorqueLimit = ReadFloat(setValue);
|
|
break;
|
|
case "forcelimit":
|
|
m_flForceLimit = ReadFloat(setValue);
|
|
break;
|
|
case "breaksound":
|
|
m_strBreakSound = ReadString(setValue);
|
|
break;
|
|
case "teleportfollowdistance":
|
|
break;
|
|
case "constraintsystem":
|
|
m_strConstraintSystem = ReadString(setValue);
|
|
break;
|
|
#ifdef SERVER
|
|
case "OnBreak":
|
|
m_strOnBreak = PrepareOutput(m_strOnBreak, setValue);
|
|
break;
|
|
#endif
|
|
default:
|
|
super::SpawnKey(keyName, setValue);
|
|
break;
|
|
}
|
|
}
|
|
|
|
float
|
|
NSPhysicsConstraint::GetConstraintSystemID(void)
|
|
{
|
|
entity system;
|
|
|
|
/* default to group 0 */
|
|
if (!m_strConstraintSystem)
|
|
return 0;
|
|
|
|
system = find(world, ::targetname, m_strConstraintSystem);
|
|
|
|
/* must have been invalid/mappers error */
|
|
if (!system) {
|
|
return 0;
|
|
}
|
|
|
|
return system.jointgroup;
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::Spawned(void)
|
|
{
|
|
super::Spawned();
|
|
|
|
#ifdef SERVER
|
|
if (m_strOnBreak)
|
|
m_strOnBreak = CreateOutput(m_strOnBreak);
|
|
#endif
|
|
}
|
|
|
|
#ifdef SERVER
|
|
void
|
|
NSPhysicsConstraint::Input(entity activatorEnt, string inputName, string dataString)
|
|
{
|
|
switch (inputName) {
|
|
case "Break":
|
|
Break(activatorEnt);
|
|
break;
|
|
case "TurnOn":
|
|
break;
|
|
case "TurnOff":
|
|
break;
|
|
default:
|
|
super::Input(activatorEnt, inputName, dataString);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
NSPhysicsConstraint::Break(entity activatingEnt)
|
|
{
|
|
#ifdef SERVER
|
|
if (m_strOnBreak)
|
|
UseOutput(activatingEnt, m_strOnBreak);
|
|
#endif
|
|
|
|
if (m_strBreakSound)
|
|
StartSoundDef(m_strBreakSound, CHAN_AUTO, true);
|
|
|
|
Destroy();
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::OnRemoveEntity(void)
|
|
{
|
|
WakeTargets();
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::WakeTargets(void)
|
|
{
|
|
NSPhysicsEntity physTarget;
|
|
|
|
if (enemy.isPhysics) {
|
|
physTarget = (NSPhysicsEntity)enemy;
|
|
physTarget.Wake();
|
|
}
|
|
if (aiment.isPhysics) {
|
|
physTarget = (NSPhysicsEntity)aiment;
|
|
physTarget.Wake();
|
|
}
|
|
}
|
|
|
|
constraint_t
|
|
NSPhysicsConstraint::GetConstraintType(void)
|
|
{
|
|
return (constraint_t )jointtype;
|
|
}
|
|
|
|
entity
|
|
NSPhysicsConstraint::GetEntity1(void)
|
|
{
|
|
return enemy;
|
|
}
|
|
|
|
entity
|
|
NSPhysicsConstraint::GetEntity2(void)
|
|
{
|
|
return aiment;
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::SetConstraintType(constraint_t setValue)
|
|
{
|
|
jointtype = (float)setValue;
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::SetEntity1(entity targetEnt)
|
|
{
|
|
enemy = targetEnt;
|
|
jointgroup = GetConstraintSystemID();
|
|
|
|
/* give it some time to think. */
|
|
ScheduleThink(ConstraintThink, 0.25f);
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::SetEntity2(entity targetEnt)
|
|
{
|
|
aiment = targetEnt;
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::SetSliderVelocity(float slideVel)
|
|
{
|
|
movedir[0] = slideVel;
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::SetSliderMaxVelocity(float maxVel)
|
|
{
|
|
movedir[1] = -fabs(maxVel);
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::SetSliderStop(float stopVal)
|
|
{
|
|
movedir[2] = stopVal;
|
|
}
|
|
|
|
void
|
|
NSPhysicsConstraint::SetSliderFriction(float frictionValue)
|
|
{
|
|
friction = frictionValue;
|
|
}
|
|
|
|
float
|
|
NSPhysicsConstraint::GetSliderVelocity(void)
|
|
{
|
|
return movedir[0];
|
|
}
|
|
|
|
float
|
|
NSPhysicsConstraint::GetSliderMaxVelocity(void)
|
|
{
|
|
return movedir[1];
|
|
}
|
|
|
|
float
|
|
NSPhysicsConstraint::GetSliderStop(void)
|
|
{
|
|
return movedir[2];
|
|
}
|
|
|
|
float
|
|
NSPhysicsConstraint::GetSliderFriction(void)
|
|
{
|
|
return friction;
|
|
}
|
|
|
|
NSPhysicsConstraint
|
|
NSPhysicsConstraint::Ballsocket(entity firstEnt, entity secondEnt, vector pos1, vector pos2, float forceLimit, bool noCollide)
|
|
{
|
|
NSPhysicsConstraint new = spawn(NSPhysicsConstraint);
|
|
new.SetConstraintType(CONSTRAINT_POINT);
|
|
new.SetEntity1(firstEnt);
|
|
new.SetEntity2(secondEnt);
|
|
new.origin = pos1;
|
|
new.velocity = pos2;
|
|
new.WakeTargets();
|
|
|
|
EntLog("Created ballsocket between %S and %S.", firstEnt.classname, secondEnt.classname);
|
|
return new;
|
|
}
|
|
|
|
NSPhysicsConstraint
|
|
NSPhysicsConstraint::Weld(entity firstEnt, entity secondEnt, float bone1, float bone2, float forceLimit, bool noCollide, bool deleteEnt1OnBreak)
|
|
{
|
|
if (firstEnt == secondEnt) {
|
|
EntError("Cannot weld the entity with itself!");
|
|
return __NULL__;
|
|
}
|
|
|
|
NSPhysicsConstraint new = spawn(NSPhysicsConstraint);
|
|
new.SetConstraintType(CONSTRAINT_FIXED);
|
|
new.SetEntity1(firstEnt);
|
|
new.SetEntity2(secondEnt);
|
|
new.WakeTargets();
|
|
|
|
EntLog("Created weld between %S and %S.", firstEnt.classname, secondEnt.classname);
|
|
return new;
|
|
}
|
|
|
|
NSPhysicsConstraint
|
|
NSPhysicsConstraint::Rope(entity firstEnt, entity secondEnt, vector pos1, vector pos2)
|
|
{
|
|
NSPhysicsConstraint new = spawn(NSPhysicsConstraint);
|
|
new.SetConstraintType(CONSTRAINT_POINT);
|
|
new.SetEntity1(firstEnt);
|
|
new.SetEntity2(secondEnt);
|
|
new.origin = pos1;
|
|
new.velocity = pos2;
|
|
new.WakeTargets();
|
|
|
|
EntLog("Created rope between %S and %S", firstEnt.classname, secondEnt.classname);
|
|
return new;
|
|
}
|
|
|
|
.float max_angular;
|
|
NSPhysicsConstraint
|
|
NSPhysicsConstraint::KeepUpright(entity firstEnt, vector uprightAngle, float angleLimit)
|
|
{
|
|
firstEnt.angles = uprightAngle;
|
|
firstEnt.max_angular = angleLimit;
|
|
return __NULL__;
|
|
} |