Add the following physics entities from Source: phys_ballsocket, phys_constraint, phys_constraintsystem, phys_convert, phys_hinge, phys_keepupright, phys_slideconstraint & env_physexplosion
Add new class phys_rope, which will handle move_rope and keyframe_rope from Source.
This commit is contained in:
parent
81a498d49e
commit
11deea5b3d
|
@ -123,15 +123,17 @@ varying mat3 invsurface;
|
||||||
|
|
||||||
#if defined(BUMP) && r_skipEnvmap==0
|
#if defined(BUMP) && r_skipEnvmap==0
|
||||||
vec3 cube_c;
|
vec3 cube_c;
|
||||||
#if r_showEnvCubemap == 0
|
float refl = 1.0 - texture2D(s_normalmap, tex_c).a;
|
||||||
float refl = 1.0 - texture2D(s_normalmap, tex_c).a;
|
|
||||||
#else
|
cube_c = reflect(normalize(eyevector), norm);
|
||||||
float refl = 1.0;
|
|
||||||
#endif
|
|
||||||
cube_c = reflect(normalize(eyevector), normal_f.rgb);
|
|
||||||
cube_c = cube_c.x * invsurface[0] + cube_c.y * invsurface[1] + cube_c.z * invsurface[2];
|
cube_c = cube_c.x * invsurface[0] + cube_c.y * invsurface[1] + cube_c.z * invsurface[2];
|
||||||
cube_c = (m_model * vec4(cube_c.xyz, 0.0)).xyz;
|
cube_c = (m_model * vec4(cube_c.xyz, 0.0)).xyz;
|
||||||
|
|
||||||
|
#if r_showEnvCubemap == 0
|
||||||
diff_f.rgb += textureCube(s_reflectcube, cube_c).rgb * refl;
|
diff_f.rgb += textureCube(s_reflectcube, cube_c).rgb * refl;
|
||||||
|
#else
|
||||||
|
diff_f.rgb = textureCube(s_reflectcube, cube_c).rgb;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(FULLBRIGHT) && r_skipFullbright==0
|
#if defined(FULLBRIGHT) && r_skipFullbright==0
|
||||||
|
|
|
@ -14,13 +14,6 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Begin calculating a route.
|
|
||||||
* The callback function will be called once the route has finished being calculated.
|
|
||||||
* The route must be memfreed once it is no longer needed.
|
|
||||||
* The route must be followed in reverse order (ie: the first node that must be reached
|
|
||||||
* is at index numnodes-1). If no route is available then the callback will be called with no nodes.
|
|
||||||
*/
|
|
||||||
int
|
int
|
||||||
Route_RoundDistance(float flDist)
|
Route_RoundDistance(float flDist)
|
||||||
{
|
{
|
||||||
|
@ -37,7 +30,7 @@ Route_RoundDistance(float flDist)
|
||||||
|
|
||||||
|
|
||||||
/* returns a botinfo point that's nearest to us */
|
/* returns a botinfo point that's nearest to us */
|
||||||
entity
|
NSEntity
|
||||||
Route_SelectFarthest(float type, vector org, optional vector lastpoi = [0,0,0])
|
Route_SelectFarthest(float type, vector org, optional vector lastpoi = [0,0,0])
|
||||||
{
|
{
|
||||||
entity temp;
|
entity temp;
|
||||||
|
@ -61,7 +54,7 @@ Route_SelectFarthest(float type, vector org, optional vector lastpoi = [0,0,0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns a botinfo point that's nearest to us */
|
/* returns a botinfo point that's nearest to us */
|
||||||
entity
|
NSEntity
|
||||||
Route_SelectNearest(float type, vector org, optional vector lastpoi = [0,0,0])
|
Route_SelectNearest(float type, vector org, optional vector lastpoi = [0,0,0])
|
||||||
{
|
{
|
||||||
entity temp;
|
entity temp;
|
||||||
|
@ -85,7 +78,7 @@ Route_SelectNearest(float type, vector org, optional vector lastpoi = [0,0,0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns a botinfo point belonging to our team */
|
/* returns a botinfo point belonging to our team */
|
||||||
entity
|
NSEntity
|
||||||
Route_SelectNearestTeam(float type, vector org, float tt)
|
Route_SelectNearestTeam(float type, vector org, float tt)
|
||||||
{
|
{
|
||||||
entity temp;
|
entity temp;
|
||||||
|
@ -110,7 +103,7 @@ Route_SelectNearestTeam(float type, vector org, float tt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns a botinfo point belonging to the enemy team */
|
/* returns a botinfo point belonging to the enemy team */
|
||||||
entity
|
NSEntity
|
||||||
Route_SelectNearestEnemyTeam(float type, vector org, float tt)
|
Route_SelectNearestEnemyTeam(float type, vector org, float tt)
|
||||||
{
|
{
|
||||||
entity temp;
|
entity temp;
|
||||||
|
@ -140,7 +133,7 @@ Route_SelectNearestEnemyTeam(float type, vector org, float tt)
|
||||||
Spawn_SelectRandom
|
Spawn_SelectRandom
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
entity
|
NSEntity
|
||||||
Route_SelectRandom(string sEntname)
|
Route_SelectRandom(string sEntname)
|
||||||
{
|
{
|
||||||
static entity eLastSpot;
|
static entity eLastSpot;
|
||||||
|
@ -153,7 +146,7 @@ Route_SelectRandom(string sEntname)
|
||||||
Route_SelectRandomSpot
|
Route_SelectRandomSpot
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
entity
|
NSEntity
|
||||||
Route_SelectRandomSpot(void)
|
Route_SelectRandomSpot(void)
|
||||||
{
|
{
|
||||||
static entity eLastSpot;
|
static entity eLastSpot;
|
||||||
|
|
|
@ -369,7 +369,9 @@ NSView::UpdateView(void)
|
||||||
/* all 2D operations happen after this point */
|
/* all 2D operations happen after this point */
|
||||||
for (entity b = world; (b = findfloat(b, ::isCSQC, 1));) {
|
for (entity b = world; (b = findfloat(b, ::isCSQC, 1));) {
|
||||||
NSEntity pf = (NSEntity) b;
|
NSEntity pf = (NSEntity) b;
|
||||||
pf.postdraw();
|
|
||||||
|
if (pf.postdraw)
|
||||||
|
pf.postdraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the blinding stuff */
|
/* the blinding stuff */
|
||||||
|
|
|
@ -122,6 +122,9 @@ Entity_EntityUpdate(float type, float new)
|
||||||
case ENT_PROPROPE:
|
case ENT_PROPROPE:
|
||||||
NSENTITY_READENTITY(prop_rope, new)
|
NSENTITY_READENTITY(prop_rope, new)
|
||||||
break;
|
break;
|
||||||
|
case ENT_PHYSROPE:
|
||||||
|
NSENTITY_READENTITY(phys_rope, new)
|
||||||
|
break;
|
||||||
case ENT_BUBBLES:
|
case ENT_BUBBLES:
|
||||||
NSENTITY_READENTITY(env_bubbles, new)
|
NSENTITY_READENTITY(env_bubbles, new)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -16,27 +16,26 @@
|
||||||
|
|
||||||
var string g_strSkyName;
|
var string g_strSkyName;
|
||||||
|
|
||||||
bool
|
|
||||||
Sky_SourceBSPCheck(string sky)
|
|
||||||
{
|
|
||||||
if not (whichpack(strcat("materials/skybox/", sky, "bk.vmt")))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Sky_Update(int force)
|
Sky_Update(int force)
|
||||||
{
|
{
|
||||||
if (g_strSkyName != serverkey("skyname") || force == TRUE) {
|
if (g_strSkyName != serverkey("skyname") || force == TRUE) {
|
||||||
|
string skyPath;
|
||||||
|
string skyPrefix;
|
||||||
|
|
||||||
g_strSkyName = serverkey("skyname");
|
g_strSkyName = serverkey("skyname");
|
||||||
|
skyPrefix = substring(g_strSkyName, 0, 4);
|
||||||
|
|
||||||
|
print(sprintf("SKY PREFIX: %S\n", skyPrefix));
|
||||||
|
|
||||||
/* is it a Source Engine material? */
|
/* is it a Source Engine material? */
|
||||||
if (Sky_SourceBSPCheck(g_strSkyName))
|
if (skyPrefix == "sky_") {
|
||||||
localcmd(sprintf("sky \"materials/skybox/%s\"\n", g_strSkyName));
|
skyPath = strcat("materials/skybox/", g_strSkyName);
|
||||||
else
|
} else {
|
||||||
localcmd(sprintf("sky \"%s\"\n", g_strSkyName));
|
skyPath = g_strSkyName;
|
||||||
|
}
|
||||||
|
|
||||||
print(sprintf("sky update applying %s.\n", g_strSkyName));
|
localcmd(sprintf("sky \"%s\"\n", skyPath));
|
||||||
|
print(sprintf("sky update applying %s.\n", skyPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,5 +19,4 @@ client/infodecal.qc
|
||||||
client/sky_camera.qc
|
client/sky_camera.qc
|
||||||
client/info_notnull.qc
|
client/info_notnull.qc
|
||||||
client/point_message.qc
|
client/point_message.qc
|
||||||
client/prop_static.qc
|
|
||||||
#endlist
|
#endlist
|
||||||
|
|
|
@ -17,6 +17,7 @@ server/env_fade.qc
|
||||||
server/env_hudhint.qc
|
server/env_hudhint.qc
|
||||||
server/env_spark.qc
|
server/env_spark.qc
|
||||||
server/env_explosion.qc
|
server/env_explosion.qc
|
||||||
|
server/env_physexplosion.qc
|
||||||
server/env_render.qc
|
server/env_render.qc
|
||||||
server/env_shake.qc
|
server/env_shake.qc
|
||||||
server/env_message.qc
|
server/env_message.qc
|
||||||
|
@ -64,6 +65,14 @@ server/player_weaponstrip.qc
|
||||||
server/player_loadsaved.qc
|
server/player_loadsaved.qc
|
||||||
server/prop_dynamic.qc
|
server/prop_dynamic.qc
|
||||||
server/prop_physics.qc
|
server/prop_physics.qc
|
||||||
|
server/phys_ballsocket.qc
|
||||||
|
server/phys_convert.qc
|
||||||
|
server/phys_constraint.qc
|
||||||
|
server/phys_keepupright.qc
|
||||||
|
server/phys_hinge.qc
|
||||||
|
server/phys_slideconstraint.qc
|
||||||
|
//server/phys_constraintsystem.qc
|
||||||
|
server/prop_static.qc
|
||||||
server/point_camera.qc
|
server/point_camera.qc
|
||||||
server/point_servercommand.qc
|
server/point_servercommand.qc
|
||||||
server/point_trigger.qc
|
server/point_trigger.qc
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!QUAKED env_physexplosion (1 .5 0) (-8 -8 -8) (8 8 8) NODAMAGE PUSHCLIENTS RADIAL TRACE SHAKE
|
||||||
|
# OVERVIEW
|
||||||
|
A force-centered explosion, primarily targetted at physics objects and optionally, players/clients.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
- "magnitude" : Amount of force applied.
|
||||||
|
- "radius" : Optional, overrides the radius of the 'explosion'.
|
||||||
|
- "targetentityname" : Optional, will only target the named entity if specified.
|
||||||
|
- "inner_radius" : Optional, will test from within this inner radius when TRACE (8) is set.
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- NODAMAGE (1) : Do not damage physics entities.
|
||||||
|
- PUSHCLIENTS (2) : Allow pushing of players.
|
||||||
|
- RADIAL (4) : Disables any up/down forces from being applied.
|
||||||
|
- TRACE (8) : Does a collision test with its targets.
|
||||||
|
- SHAKE (16) : Push the view of the players around a bit.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
env_physexplosion:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void env_physexplosion(void);
|
||||||
|
|
||||||
|
/* overrides */
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string,string);
|
||||||
|
virtual void SpawnKey(string, string);
|
||||||
|
virtual void Respawn(void);
|
||||||
|
virtual void Input(entity, string, string);
|
||||||
|
|
||||||
|
nonvirtual void TriggerExplosion(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_flMagnitude;
|
||||||
|
float m_flRadius;
|
||||||
|
string m_strTargetEntity;
|
||||||
|
float m_flInnerRadius;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
env_physexplosion::env_physexplosion(void)
|
||||||
|
{
|
||||||
|
m_flMagnitude = 0.0f;
|
||||||
|
m_flRadius = 0.0f;
|
||||||
|
m_strTargetEntity = __NULL__;
|
||||||
|
m_flInnerRadius = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env_physexplosion::Save(float handle)
|
||||||
|
{
|
||||||
|
super::Save(handle);
|
||||||
|
SaveFloat(handle, "m_flMagnitude", m_flMagnitude);
|
||||||
|
SaveFloat(handle, "m_flRadius", m_flRadius);
|
||||||
|
SaveString(handle, "m_strTargetEntity", m_strTargetEntity);
|
||||||
|
SaveFloat(handle, "m_flInnerRadius", m_flInnerRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env_physexplosion::Restore(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "m_flMagnitude":
|
||||||
|
m_flMagnitude = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flRadius":
|
||||||
|
m_flRadius = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "m_strTargetEntity":
|
||||||
|
m_strTargetEntity = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flInnerRadius":
|
||||||
|
m_flInnerRadius = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Restore(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env_physexplosion::SpawnKey(string keyName, string setValue)
|
||||||
|
{
|
||||||
|
switch (keyName) {
|
||||||
|
case "magnitude":
|
||||||
|
m_flMagnitude = ReadFloat(setValue);
|
||||||
|
break;
|
||||||
|
case "radius":
|
||||||
|
m_flRadius = ReadFloat(setValue);
|
||||||
|
break;
|
||||||
|
case "targetentityname":
|
||||||
|
m_strTargetEntity = ReadString(setValue);
|
||||||
|
break;
|
||||||
|
case "inner_radius":
|
||||||
|
m_flInnerRadius = ReadFloat(setValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::SpawnKey(keyName, setValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env_physexplosion::Respawn(void)
|
||||||
|
{
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env_physexplosion::TriggerExplosion(void)
|
||||||
|
{
|
||||||
|
float entityDistance = 0.0f;
|
||||||
|
float targetForce = 0.0f;
|
||||||
|
float explosionRadius = m_flRadius;
|
||||||
|
NSPhysicsEntity physEnt;
|
||||||
|
|
||||||
|
if (m_flRadius == 0.0) {
|
||||||
|
explosionRadius = m_flMagnitude * 2.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only target them if set */
|
||||||
|
if (m_strTargetEntity) {
|
||||||
|
physEnt = (NSPhysicsEntity)find(world, ::targetname, m_strTargetEntity);
|
||||||
|
|
||||||
|
if (!physEnt) {
|
||||||
|
NSEntWarning("Target set, but not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entityDistance = vlen(GetOrigin() - physEnt.WorldSpaceCenter());
|
||||||
|
|
||||||
|
if (entityDistance <= explosionRadius) {
|
||||||
|
targetForce = (explosionRadius - entityDistance) / explosionRadius;
|
||||||
|
targetForce = rint(m_flMagnitude * targetForce);
|
||||||
|
physEnt.ApplyForceOffset(v_forward * targetForce, origin);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entity e = world; (e = findfloat(e, ::isPhysics, true));) {
|
||||||
|
physEnt = (NSPhysicsEntity)e;
|
||||||
|
entityDistance = vlen(GetOrigin() - physEnt.WorldSpaceCenter());
|
||||||
|
|
||||||
|
if (entityDistance <= explosionRadius) {
|
||||||
|
makevectors(vectoangles(physEnt.WorldSpaceCenter() - GetOrigin()));
|
||||||
|
targetForce = (explosionRadius - entityDistance) / explosionRadius;
|
||||||
|
targetForce = rint(m_flMagnitude * targetForce);
|
||||||
|
physEnt.ApplyForceOffset(v_forward * targetForce, origin);
|
||||||
|
physEnt.velocity += v_forward * targetForce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env_physexplosion::Input(entity activatorEnt, string inputName, string dataString)
|
||||||
|
{
|
||||||
|
switch (inputName) {
|
||||||
|
case "Explode":
|
||||||
|
TriggerExplosion();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Input(activatorEnt, inputName, dataString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -106,6 +106,8 @@ private:
|
||||||
string m_strSndStop;
|
string m_strSndStop;
|
||||||
|
|
||||||
int m_waterType;
|
int m_waterType;
|
||||||
|
|
||||||
|
string m_strFullyClosed;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -133,6 +135,7 @@ func_door::func_door(void)
|
||||||
m_strSndStop = __NULL__;
|
m_strSndStop = __NULL__;
|
||||||
|
|
||||||
m_waterType = 0i;
|
m_waterType = 0i;
|
||||||
|
m_strFullyClosed = __NULL__;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -158,6 +161,7 @@ func_door::Save(float handle)
|
||||||
SaveString(handle, "m_strSndMove", m_strSndMove);
|
SaveString(handle, "m_strSndMove", m_strSndMove);
|
||||||
SaveString(handle, "targetClose", targetClose);
|
SaveString(handle, "targetClose", targetClose);
|
||||||
SaveInt(handle, "m_waterType", m_waterType);
|
SaveInt(handle, "m_waterType", m_waterType);
|
||||||
|
SaveString(handle, "m_strFullyClosed", m_strFullyClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -215,6 +219,9 @@ func_door::Restore(string strKey, string strValue)
|
||||||
case "m_waterType":
|
case "m_waterType":
|
||||||
m_waterType = ReadInt(strValue);
|
m_waterType = ReadInt(strValue);
|
||||||
break;
|
break;
|
||||||
|
case "m_strFullyClosed":
|
||||||
|
m_strFullyClosed = ReadString(strValue);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
super::Restore(strKey, strValue);
|
super::Restore(strKey, strValue);
|
||||||
}
|
}
|
||||||
|
@ -281,6 +288,10 @@ func_door::SpawnKey(string strKey, string strValue)
|
||||||
x = stoi(strValue);
|
x = stoi(strValue);
|
||||||
m_strUnlockedSfx = sprintf("func_button.hlsfx_%i", x+1i);
|
m_strUnlockedSfx = sprintf("func_button.hlsfx_%i", x+1i);
|
||||||
break;
|
break;
|
||||||
|
/* I/O */
|
||||||
|
case "OnFullyClosed":
|
||||||
|
m_strFullyClosed = PrepareOutput(m_strFullyClosed, strValue);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
super::SpawnKey(strKey, strValue);
|
super::SpawnKey(strKey, strValue);
|
||||||
}
|
}
|
||||||
|
@ -305,6 +316,10 @@ func_door::Spawned(void)
|
||||||
Sound_Precache(m_strLockedSfx);
|
Sound_Precache(m_strLockedSfx);
|
||||||
if (m_strUnlockedSfx)
|
if (m_strUnlockedSfx)
|
||||||
Sound_Precache(m_strUnlockedSfx);
|
Sound_Precache(m_strUnlockedSfx);
|
||||||
|
|
||||||
|
/* I/O */
|
||||||
|
if (m_strFullyClosed)
|
||||||
|
m_strFullyClosed = CreateOutput(m_strFullyClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -371,10 +386,10 @@ func_door::Input(entity eAct, string strInput, string strData)
|
||||||
{
|
{
|
||||||
switch (strInput) {
|
switch (strInput) {
|
||||||
case "Open":
|
case "Open":
|
||||||
Trigger(eAct, TRIG_OFF);
|
Trigger(eAct, TRIG_ON);
|
||||||
break;
|
break;
|
||||||
case "Close":
|
case "Close":
|
||||||
Trigger(eAct, TRIG_ON);
|
Trigger(eAct, TRIG_OFF);
|
||||||
break;
|
break;
|
||||||
case "Toggle":
|
case "Toggle":
|
||||||
Trigger(eAct, TRIG_TOGGLE);
|
Trigger(eAct, TRIG_TOGGLE);
|
||||||
|
@ -420,6 +435,9 @@ func_door::MoverFinishesMoving(void)
|
||||||
if (m_strSndMove)
|
if (m_strSndMove)
|
||||||
StartSound("common/null.wav", CHAN_WEAPON, 0, true);
|
StartSound("common/null.wav", CHAN_WEAPON, 0, true);
|
||||||
|
|
||||||
|
if (m_strFullyClosed)
|
||||||
|
UseOutput(this, m_strFullyClosed);
|
||||||
|
|
||||||
} else if (GetMoverState() == MOVER_POS2) {
|
} else if (GetMoverState() == MOVER_POS2) {
|
||||||
if (m_strSndStop) {
|
if (m_strSndStop) {
|
||||||
StartSoundDef(m_strSndStop, CHAN_VOICE, true);
|
StartSoundDef(m_strSndStop, CHAN_VOICE, true);
|
||||||
|
|
|
@ -49,9 +49,9 @@ func_physbox::Respawn(void)
|
||||||
NSPhysicsEntity::Respawn();
|
NSPhysicsEntity::Respawn();
|
||||||
|
|
||||||
if (HasSpawnFlags(FNCPHYBX_ASLEEP))
|
if (HasSpawnFlags(FNCPHYBX_ASLEEP))
|
||||||
PhysicsDisable();
|
Sleep();
|
||||||
else
|
else
|
||||||
PhysicsEnable();
|
Wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -85,7 +85,7 @@ func_physbox::Death(void)
|
||||||
void
|
void
|
||||||
func_physbox::Respawn(void)
|
func_physbox::Respawn(void)
|
||||||
{
|
{
|
||||||
NSSurfacePropEntity::Respawn();
|
super::Respawn();
|
||||||
health = GetSpawnHealth();
|
health = GetSpawnHealth();
|
||||||
SetTakedamage(DAMAGE_YES);
|
SetTakedamage(DAMAGE_YES);
|
||||||
SetSolid(SOLID_BBOX);
|
SetSolid(SOLID_BBOX);
|
||||||
|
|
|
@ -82,7 +82,7 @@ private:
|
||||||
void
|
void
|
||||||
logic_auto::logic_auto(void)
|
logic_auto::logic_auto(void)
|
||||||
{
|
{
|
||||||
m_iFromSaveGame = 0;
|
m_iFromSaveGame = 0i;
|
||||||
m_strOnMapSpawn = __NULL__;
|
m_strOnMapSpawn = __NULL__;
|
||||||
m_strOnNewGame = __NULL__;
|
m_strOnNewGame = __NULL__;
|
||||||
m_strOnLoadGame = __NULL__;
|
m_strOnLoadGame = __NULL__;
|
||||||
|
@ -108,7 +108,7 @@ logic_auto::Save(float handle)
|
||||||
void
|
void
|
||||||
logic_auto::Restore(string strKey, string strValue)
|
logic_auto::Restore(string strKey, string strValue)
|
||||||
{
|
{
|
||||||
m_iFromSaveGame = 1;
|
m_iFromSaveGame = 1i;
|
||||||
|
|
||||||
switch (strKey) {
|
switch (strKey) {
|
||||||
case "m_strOnMapSpawn":
|
case "m_strOnMapSpawn":
|
||||||
|
@ -198,8 +198,6 @@ logic_auto::Spawned(void)
|
||||||
void
|
void
|
||||||
logic_auto::Respawn(void)
|
logic_auto::Respawn(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
m_iFromSaveGame = 1;
|
|
||||||
ScheduleThink(Processing, 0.2f);
|
ScheduleThink(Processing, 0.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +218,9 @@ logic_auto::Processing(void)
|
||||||
cvar_set("_bsp_change_auto", "");
|
cvar_set("_bsp_change_auto", "");
|
||||||
} else
|
} else
|
||||||
UseOutput(this, m_strOnLoadGame);
|
UseOutput(this, m_strOnLoadGame);
|
||||||
} else
|
} else {
|
||||||
UseOutput(this, m_strOnNewGame);
|
UseOutput(this, m_strOnNewGame);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* TODO: more reliable way of figuring out round restarts */
|
/* TODO: more reliable way of figuring out round restarts */
|
||||||
if (time > 5)
|
if (time > 5)
|
||||||
|
|
|
@ -39,8 +39,8 @@ Compares an input value sent from another entity with one of the constant values
|
||||||
|
|
||||||
# INPUTS
|
# INPUTS
|
||||||
- "InValue" : Compares the input in the data field with one of the constant values, then firing a matching output.
|
- "InValue" : Compares the input in the data field with one of the constant values, then firing a matching output.
|
||||||
- "PickRandom" : Not yet implemented. Triggers a random, valid output.
|
- "PickRandom" : Triggers a random, valid output.
|
||||||
- "PickRandomShuffle" : Not yet implemented. Triggers a random, valid output, but without repeats.
|
- "PickRandomShuffle" : Triggers a random, valid output, but without repeats.
|
||||||
|
|
||||||
# OUTPUTS
|
# OUTPUTS
|
||||||
- "OnCase01" - Triggered when Case01 matches the InValue input data.
|
- "OnCase01" - Triggered when Case01 matches the InValue input data.
|
||||||
|
@ -81,6 +81,8 @@ public:
|
||||||
virtual void Input(entity, string, string);
|
virtual void Input(entity, string, string);
|
||||||
|
|
||||||
nonvirtual void CompareCase(entity, string);
|
nonvirtual void CompareCase(entity, string);
|
||||||
|
nonvirtual void PickRandom(entity);
|
||||||
|
nonvirtual void PickRandomShuffle(entity);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -476,16 +478,28 @@ logic_case::Input(entity activatorEntity, string inputName, string dataField)
|
||||||
CompareCase(activatorEntity, dataField);
|
CompareCase(activatorEntity, dataField);
|
||||||
break;
|
break;
|
||||||
case "PickRandom":
|
case "PickRandom":
|
||||||
error("Not implemented.");
|
PickRandom(activatorEntity);
|
||||||
break;
|
break;
|
||||||
case "PickRandomShuffle":
|
case "PickRandomShuffle":
|
||||||
error("Not implemented.");
|
PickRandomShuffle(activatorEntity);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
super::Input(activatorEntity, inputName, dataField);
|
super::Input(activatorEntity, inputName, dataField);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logic_case::PickRandom(entity activatorEntity)
|
||||||
|
{
|
||||||
|
NSEntWarning("Not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logic_case::PickRandomShuffle(entity activatorEntity)
|
||||||
|
{
|
||||||
|
NSEntWarning("Not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
logic_case::CompareCase(entity activatorEntity, string inputValue)
|
logic_case::CompareCase(entity activatorEntity, string inputValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,7 +51,7 @@ path_corner:NSPointTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void path_corner(void);
|
void path_corner(void);
|
||||||
|
|
||||||
virtual void Save(float);
|
virtual void Save(float);
|
||||||
virtual void Restore(string,string);
|
virtual void Restore(string,string);
|
||||||
virtual void SpawnKey(string,string);
|
virtual void SpawnKey(string,string);
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!QUAKED phys_ballsocket (.5 .3 0) (-8 -8 -8) (8 8 8) BREAKCOLL x INACTIVE MASS NOCONNECT
|
||||||
|
# OVERVIEW
|
||||||
|
Creates a connection between two entities in the form of a 'ballsocket'.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
- "attach1" : Entity 1
|
||||||
|
- "attach2" : Entity 2
|
||||||
|
|
||||||
|
# INPUTS
|
||||||
|
- "Break" : Forcefully break the constraint.
|
||||||
|
- "TurnOn" : Turn
|
||||||
|
- "TurnOff" : Disables the constraint
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- BREAKCOLL (1) : No collision until the connection breaks.
|
||||||
|
- INACTIVE (4) : Starts inactive.
|
||||||
|
- MASS (8) : Mass Hack.
|
||||||
|
- NOCONNECT (16) : Will not connect entities until turned on via Inputs.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
phys_ballsocket:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_ballsocket(void);
|
||||||
|
|
||||||
|
virtual void Respawn(void);
|
||||||
|
nonvirtual void AfterSpawn(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_ballsocket::phys_ballsocket(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_ballsocket::Respawn(void)
|
||||||
|
{
|
||||||
|
ScheduleThink(AfterSpawn, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_ballsocket::AfterSpawn(void)
|
||||||
|
{
|
||||||
|
vector centerPos;
|
||||||
|
SetConstraintType(CONSTRAINT_POINT);
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
|
||||||
|
SetEntity1(find(world, ::targetname, m_strEnt1));
|
||||||
|
|
||||||
|
if (m_strEnt2)
|
||||||
|
SetEntity2(find(world, ::targetname, m_strEnt2));
|
||||||
|
else
|
||||||
|
SetEntity2(this);
|
||||||
|
|
||||||
|
centerPos = (enemy.origin + aiment.origin) / 2;
|
||||||
|
origin = velocity = centerPos;
|
||||||
|
|
||||||
|
WakeTargets();
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!QUAKED phys_constraint (.5 .3 0) (-8 -8 -8) (8 8 8) BREAKCOLL x INACTIVE MASS NOCONNECT
|
||||||
|
# OVERVIEW
|
||||||
|
Creates a fixed connection between two entities.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
- "attach1" : Entity 1
|
||||||
|
- "attach2" : Entity 2
|
||||||
|
|
||||||
|
# INPUTS
|
||||||
|
- "Break" : Forcefully break the constraint.
|
||||||
|
- "TurnOn" : Turn
|
||||||
|
- "TurnOff" : Disables the constraint
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- BREAKCOLL (1) : No collision until the connection breaks.
|
||||||
|
- INACTIVE (4) : Starts inactive.
|
||||||
|
- MASS (8) : Mass Hack.
|
||||||
|
- NOCONNECT (16) : Will not connect entities until turned on via Inputs.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
phys_constraint:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_constraint(void);
|
||||||
|
|
||||||
|
virtual void Respawn(void);
|
||||||
|
nonvirtual void AfterSpawn(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_constraint::phys_constraint(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_constraint::Respawn(void)
|
||||||
|
{
|
||||||
|
ScheduleThink(AfterSpawn, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_constraint::AfterSpawn(void)
|
||||||
|
{
|
||||||
|
SetConstraintType(CONSTRAINT_FIXED);
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
|
||||||
|
SetEntity1(find(world, ::targetname, m_strEnt1));
|
||||||
|
|
||||||
|
if (m_strEnt2)
|
||||||
|
SetEntity2(find(world, ::targetname, m_strEnt2));
|
||||||
|
else
|
||||||
|
SetEntity2(this);
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var int g_phys_constraintsystems;
|
||||||
|
|
||||||
|
/*!QUAKED phys_constraintsystem (.5 .3 0) (-8 -8 -8) (8 8 8)
|
||||||
|
# OVERVIEW
|
||||||
|
Turns a series of constraints into a ragdoll, so it can be managed better by the physics simulator.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
|
||||||
|
# NOTES
|
||||||
|
|
||||||
|
You specify the constraintsystem that the constraints belong to not in this entity, but
|
||||||
|
in the individual constraints themselves. Set the 'constraintsystem' key to an instance of this entity.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
phys_constraintsystem:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_constraintsystem(void);
|
||||||
|
|
||||||
|
virtual void Respawn(void);
|
||||||
|
nonvirtual void AfterSpawn(void);
|
||||||
|
nonvirtual float GetSystemID(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_constraintsystem::phys_constraintsystem(void)
|
||||||
|
{
|
||||||
|
g_phys_constraintsystems += 1;
|
||||||
|
jointgroup = (float)g_phys_constraintsystems;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_constraintsystem::Respawn(void)
|
||||||
|
{
|
||||||
|
ScheduleThink(AfterSpawn, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_constraintsystem::AfterSpawn(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
phys_constraintsystem::GetSystemID(void)
|
||||||
|
{
|
||||||
|
return jointgroup;
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!QUAKED phys_convert (.5 .3 0) (-8 -8 -8) (8 8 8) ASLEEP DEBRIS
|
||||||
|
# OVERVIEW
|
||||||
|
Turns a standard entity into a physically simulated one.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
- "target" : Entity 1
|
||||||
|
- "swapmodel" : Model override.
|
||||||
|
- "massoverride" : Optional new mass.
|
||||||
|
|
||||||
|
# INPUTS
|
||||||
|
- "ConvertTarget" : Triggers the conversion.
|
||||||
|
|
||||||
|
# OUTPUTS
|
||||||
|
- "OnConvert" : Triggered after successful conversion.
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- ASLEEP (1) : Don't activate motion when conversion is done.
|
||||||
|
- DEBRIS (2) : Makes converted entity non-solid.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
phys_convert:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_convert(void);
|
||||||
|
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string,string);
|
||||||
|
virtual void SpawnKey(string, string);
|
||||||
|
virtual void Spawned(void);
|
||||||
|
virtual void Respawn(void);
|
||||||
|
virtual void Input(entity, string, string);
|
||||||
|
nonvirtual void AfterSpawn(void);
|
||||||
|
nonvirtual void ConvertTarget(entity);
|
||||||
|
|
||||||
|
private:
|
||||||
|
string m_strSwapModel;
|
||||||
|
float m_flMassOverride;
|
||||||
|
string m_strOnConvert;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::phys_convert(void)
|
||||||
|
{
|
||||||
|
m_strSwapModel = __NULL__;
|
||||||
|
m_flMassOverride = 0.0f;
|
||||||
|
m_strOnConvert = __NULL__;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::Save(float handle)
|
||||||
|
{
|
||||||
|
super::Save(handle);
|
||||||
|
SaveString(handle, "m_strSwapModel", m_strSwapModel);
|
||||||
|
SaveFloat(handle, "m_flMassOverride", m_flMassOverride);
|
||||||
|
SaveString(handle, "m_strOnConvert", m_strOnConvert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::Restore(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "m_strSwapModel":
|
||||||
|
m_strSwapModel = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flMassOverride":
|
||||||
|
m_flMassOverride = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "m_strOnConvert":
|
||||||
|
m_strOnConvert = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Restore(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::SpawnKey(string keyName, string setValue)
|
||||||
|
{
|
||||||
|
switch (keyName) {
|
||||||
|
case "target":
|
||||||
|
m_strEnt1 = ReadString(setValue);
|
||||||
|
break;
|
||||||
|
case "swapmodel":
|
||||||
|
m_strSwapModel = ReadString(setValue);
|
||||||
|
break;
|
||||||
|
case "massoverride":
|
||||||
|
m_flMassOverride = ReadFloat(setValue);
|
||||||
|
break;
|
||||||
|
case "OnConvert":
|
||||||
|
m_strOnConvert = PrepareOutput(m_strOnConvert, setValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::SpawnKey(keyName, setValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::Spawned(void)
|
||||||
|
{
|
||||||
|
super::Spawned();
|
||||||
|
|
||||||
|
if (m_strOnConvert)
|
||||||
|
m_strOnConvert = CreateOutput(m_strOnConvert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::Respawn(void)
|
||||||
|
{
|
||||||
|
ScheduleThink(AfterSpawn, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::AfterSpawn(void)
|
||||||
|
{
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
SetEntity1(find(world, ::targetname, m_strEnt1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::ConvertTarget(entity activatorEnt)
|
||||||
|
{
|
||||||
|
NSEntity targetEnt = (NSEntity)GetEntity1();
|
||||||
|
string targetModel;
|
||||||
|
vector targetAngle;
|
||||||
|
vector targetPos;
|
||||||
|
vector targetVelocity;
|
||||||
|
string targetName;
|
||||||
|
NSPhysicsEntity new;
|
||||||
|
|
||||||
|
if (!targetEnt) {
|
||||||
|
NSEntWarning("Cannot find target to convert.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetModel = targetEnt.GetModel();
|
||||||
|
targetAngle = targetEnt.GetAngles();
|
||||||
|
targetPos = targetEnt.GetOrigin();
|
||||||
|
targetVelocity = targetEnt.GetVelocity();
|
||||||
|
targetName = targetEnt.targetname;
|
||||||
|
|
||||||
|
new = spawn(NSPhysicsEntity);
|
||||||
|
new.Respawn();
|
||||||
|
|
||||||
|
/* may have an override */
|
||||||
|
if (m_strSwapModel) {
|
||||||
|
targetModel = m_strSwapModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
new.SetModel(targetModel);
|
||||||
|
new.SetOrigin(targetPos);
|
||||||
|
new.SetAngles(targetAngle);
|
||||||
|
new.SetVelocity(targetVelocity);
|
||||||
|
new.targetname = (targetName);
|
||||||
|
|
||||||
|
if (m_flMassOverride > 0.0f) {
|
||||||
|
new.SetMass(m_flMassOverride);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spawnflags ASLEEP */
|
||||||
|
if (HasSpawnFlags(1)) {
|
||||||
|
new.Sleep();
|
||||||
|
} else {
|
||||||
|
new.Wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spawnflag DEBRIS */
|
||||||
|
if (HasSpawnFlags(2)) {
|
||||||
|
new.SetSolid(SOLID_NOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
targetEnt.Destroy();
|
||||||
|
|
||||||
|
if (m_strOnConvert)
|
||||||
|
UseOutput(activatorEnt, m_strOnConvert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_convert::Input(entity activatorEnt, string inputName, string dataString)
|
||||||
|
{
|
||||||
|
switch (inputName) {
|
||||||
|
case "ConvertTarget":
|
||||||
|
ConvertTarget(activatorEnt);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Input(activatorEnt, inputName, dataString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!QUAKED phys_hinge (.5 .3 0) (-8 -8 -8) (8 8 8) BREAKCOLL x INACTIVE MASS NOCONNECT
|
||||||
|
# OVERVIEW
|
||||||
|
Creates a connection between two entities in the form of a hinge.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
- "attach1" : Entity 1
|
||||||
|
- "attach2" : Entity 2
|
||||||
|
- "hingefriction" : Friction in the hinge.
|
||||||
|
- "hingeaxis" : Axis of the hinge. Technically the position it is aiming at.
|
||||||
|
|
||||||
|
# INPUTS
|
||||||
|
- "Break" : Forcefully break the constraint.
|
||||||
|
- "TurnOn" : Turn
|
||||||
|
- "TurnOff" : Disables the constraint
|
||||||
|
- "SetAngularVelocity" : Applies rotation to the hinge motor.
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- BREAKCOLL (1) : No collision until the connection breaks.
|
||||||
|
- INACTIVE (4) : Starts inactive.
|
||||||
|
- MASS (8) : Mass Hack.
|
||||||
|
- NOCONNECT (16) : Will not connect entities until turned on via Inputs.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
phys_hinge:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_hinge(void);
|
||||||
|
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string,string);
|
||||||
|
virtual void SpawnKey(string, string);
|
||||||
|
virtual void Input(entity, string, string);
|
||||||
|
virtual void Respawn(void);
|
||||||
|
nonvirtual void AfterSpawn(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_flHingeFriction;
|
||||||
|
vector m_vecHingeAxis;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_hinge::phys_hinge(void)
|
||||||
|
{
|
||||||
|
m_flHingeFriction = 1.0f;
|
||||||
|
m_vecHingeAxis = g_vec_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_hinge::Save(float handle)
|
||||||
|
{
|
||||||
|
super::Save(handle);
|
||||||
|
SaveFloat(handle, "m_flHingeFriction", m_flHingeFriction);
|
||||||
|
SaveVector(handle, "m_vecHingeAxis", m_vecHingeAxis);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_hinge::Restore(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "m_flHingeFriction":
|
||||||
|
m_flHingeFriction = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "m_vecHingeAxis":
|
||||||
|
m_vecHingeAxis = ReadVector(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Restore(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_hinge::SpawnKey(string keyName, string setValue)
|
||||||
|
{
|
||||||
|
switch (keyName) {
|
||||||
|
case "hingefriction":
|
||||||
|
m_flHingeFriction = ReadFloat(setValue);
|
||||||
|
break;
|
||||||
|
case "hingeaxis":
|
||||||
|
m_vecHingeAxis = ReadVector(setValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::SpawnKey(keyName, setValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_hinge::Respawn(void)
|
||||||
|
{
|
||||||
|
ScheduleThink(AfterSpawn, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_hinge::AfterSpawn(void)
|
||||||
|
{
|
||||||
|
SetConstraintType(CONSTRAINT_HINGE);
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
|
||||||
|
SetEntity1(find(world, ::targetname, m_strEnt1));
|
||||||
|
|
||||||
|
if (m_strEnt2)
|
||||||
|
SetEntity2(find(world, ::targetname, m_strEnt2));
|
||||||
|
else
|
||||||
|
SetEntity2(this);
|
||||||
|
|
||||||
|
SetAngles(vectoangles(m_vecHingeAxis - GetOrigin()));
|
||||||
|
SetSliderMaxVelocity(99999);
|
||||||
|
SetSliderFriction(m_flHingeFriction);
|
||||||
|
|
||||||
|
WakeTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_hinge::Input(entity activatorEnt, string inputName, string dataString)
|
||||||
|
{
|
||||||
|
switch (inputName) {
|
||||||
|
case "SetAngularVelocity":
|
||||||
|
SetSliderVelocity(stof(dataString));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Input(activatorEnt, inputName, dataString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!QUAKED phys_keepupright (.5 .3 0) (-8 -8 -8) (8 8 8) INACTIVE
|
||||||
|
# OVERVIEW
|
||||||
|
Keep an entity upright.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
- "attach1" : Entity 1
|
||||||
|
- "angularlimit" : The limit of angular velocity this can clamp.
|
||||||
|
|
||||||
|
# INPUTS
|
||||||
|
- "TurnOn" : Make Entity 1 upright.
|
||||||
|
- "TurnOff" : Make Entity 1 no longer upright.
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- INACTIVE (1) : Starts inactive.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
phys_keepupright:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_keepupright(void);
|
||||||
|
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string,string);
|
||||||
|
virtual void SpawnKey(string, string);
|
||||||
|
virtual void Respawn(void);
|
||||||
|
nonvirtual void AfterSpawn(void);
|
||||||
|
virtual void Input(entity, string, string);
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_flAngularLimit;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_keepupright::phys_keepupright(void)
|
||||||
|
{
|
||||||
|
m_flAngularLimit = -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_keepupright::Save(float handle)
|
||||||
|
{
|
||||||
|
super::Save(handle);
|
||||||
|
SaveFloat(handle, "m_flAngularLimit", m_flAngularLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_keepupright::Restore(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "m_flAngularLimit":
|
||||||
|
m_flAngularLimit = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Restore(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_keepupright::SpawnKey(string keyName, string setValue)
|
||||||
|
{
|
||||||
|
switch (keyName) {
|
||||||
|
case "angularlimit":
|
||||||
|
m_flAngularLimit = ReadFloat(setValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::SpawnKey(keyName, setValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_keepupright::Respawn(void)
|
||||||
|
{
|
||||||
|
if (HasSpawnFlags(1) == false)
|
||||||
|
ScheduleThink(AfterSpawn, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_keepupright::AfterSpawn(void)
|
||||||
|
{
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
SetEntity1(find(world, ::targetname, m_strEnt1));
|
||||||
|
NSEntity targetEnt = (NSEntity)GetEntity1();
|
||||||
|
KeepUpright(targetEnt, targetEnt.GetSpawnAngles(), m_flAngularLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_keepupright::Input(entity activatorEnt, string inputName, string dataString)
|
||||||
|
{
|
||||||
|
NSEntity targetEnt;
|
||||||
|
|
||||||
|
switch (inputName) {
|
||||||
|
case "TurnOn":
|
||||||
|
targetEnt = (NSEntity)GetEntity1();
|
||||||
|
KeepUpright(targetEnt, targetEnt.GetSpawnAngles(), m_flAngularLimit);
|
||||||
|
break;
|
||||||
|
case "TurnOff":
|
||||||
|
targetEnt = (NSEntity)GetEntity1();
|
||||||
|
KeepUpright(targetEnt, targetEnt.GetSpawnAngles(), -1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Input(activatorEnt, inputName, dataString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!QUAKED phys_slideconstraint (.5 .3 0) (-8 -8 -8) (8 8 8) BREAKCOLL LIMITENDS
|
||||||
|
# OVERVIEW
|
||||||
|
Will slide an entity along a segment.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "targetname" : Name
|
||||||
|
- "attach1" : Entity 1
|
||||||
|
- "attach2" : Entity 2
|
||||||
|
- "slideaxis" : Axis onto which the entity slides along. Technically the position it is aiming at.
|
||||||
|
- "slidefriction" : Friction the entity experiences along the slide.
|
||||||
|
|
||||||
|
# INPUTS
|
||||||
|
- "Break" : Forcefully break the constraint.
|
||||||
|
- "TurnOn" : Turn
|
||||||
|
- "TurnOff" : Disables the constraint
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- BREAKCOLL (1) : No collision until the connection breaks.
|
||||||
|
- LIMITENDS (2) : Limit endpoints.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
class
|
||||||
|
phys_slideconstraint:NSPhysicsConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_slideconstraint(void);
|
||||||
|
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string,string);
|
||||||
|
virtual void SpawnKey(string, string);
|
||||||
|
virtual void Input(entity, string, string);
|
||||||
|
virtual void Respawn(void);
|
||||||
|
nonvirtual void AfterSpawn(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector m_vecSliderAxis;
|
||||||
|
float m_flSliderFriction;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_slideconstraint::phys_slideconstraint(void)
|
||||||
|
{
|
||||||
|
m_vecSliderAxis = g_vec_null;
|
||||||
|
m_flSliderFriction = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_slideconstraint::Save(float handle)
|
||||||
|
{
|
||||||
|
super::Save(handle);
|
||||||
|
SaveVector(handle, "m_vecSliderAxis", m_vecSliderAxis);
|
||||||
|
SaveFloat(handle, "m_flSliderFriction", m_flSliderFriction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_slideconstraint::Restore(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "m_vecSliderAxis":
|
||||||
|
m_vecSliderAxis = ReadVector(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flSliderFriction":
|
||||||
|
m_flSliderFriction = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Restore(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_slideconstraint::SpawnKey(string keyName, string setValue)
|
||||||
|
{
|
||||||
|
switch (keyName) {
|
||||||
|
case "slideaxis":
|
||||||
|
m_vecSliderAxis = ReadVector(setValue);
|
||||||
|
break;
|
||||||
|
case "slidefriction":
|
||||||
|
m_flSliderFriction = ReadFloat(setValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::SpawnKey(keyName, setValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_slideconstraint::Respawn(void)
|
||||||
|
{
|
||||||
|
ScheduleThink(AfterSpawn, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_slideconstraint::AfterSpawn(void)
|
||||||
|
{
|
||||||
|
SetConstraintType(CONSTRAINT_SLIDER);
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
|
||||||
|
SetEntity1(find(world, ::targetname, m_strEnt1));
|
||||||
|
|
||||||
|
if (m_strEnt2)
|
||||||
|
SetEntity2(find(world, ::targetname, m_strEnt2));
|
||||||
|
else
|
||||||
|
SetEntity2(this);
|
||||||
|
|
||||||
|
SetAngles(vectoangles(m_vecSliderAxis - GetOrigin()));
|
||||||
|
SetSliderMaxVelocity(99999);
|
||||||
|
SetSliderFriction(m_flSliderFriction);
|
||||||
|
|
||||||
|
if (HasSpawnFlags(2))
|
||||||
|
SetSliderStop(vlen(m_vecSliderAxis - GetOrigin()));
|
||||||
|
|
||||||
|
WakeTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_slideconstraint::Input(entity activatorEnt, string inputName, string dataString)
|
||||||
|
{
|
||||||
|
switch (inputName) {
|
||||||
|
case "SetVelocity":
|
||||||
|
if (GetSliderVelocity() > 0.0f)
|
||||||
|
SetSliderVelocity(-stof(dataString));
|
||||||
|
else
|
||||||
|
SetSliderVelocity(stof(dataString));
|
||||||
|
|
||||||
|
WakeTargets();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Input(activatorEnt, inputName, dataString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,3 +86,6 @@ prop_dynamic::Respawn(void)
|
||||||
if (HasSpawnFlags(PRPDYN_NONSOLID))
|
if (HasSpawnFlags(PRPDYN_NONSOLID))
|
||||||
SetSolid(SOLID_NOT);
|
SetSolid(SOLID_NOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLASSEXPORT(prop_dynamic_override, prop_dynamic)
|
||||||
|
CLASSEXPORT(prop_dynamic_respawnable, prop_dynamic)
|
||||||
|
|
|
@ -15,9 +15,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PHYSICS_STATIC
|
#ifndef PHYSICS_STATIC
|
||||||
#define PRPPHYS_ASLEEP 1
|
|
||||||
|
|
||||||
/*!QUAKED prop_physics (1 0 0) (-16 -16 -16) (16 16 16) PRPPHYS_ASLEEP
|
enumflags
|
||||||
|
{
|
||||||
|
PHYSPROPSFL_ASLEEP,
|
||||||
|
PHYSPROPSFL_NOPHYSDMG,
|
||||||
|
PHYSPROPSFL_DEBRIS,
|
||||||
|
PHYSPROPSFL_NOMOTION,
|
||||||
|
PHYSPROPSFL_UNUSED1,
|
||||||
|
PHYSPROPSFL_UNUSED2,
|
||||||
|
PHYSPROPSFL_PHYSDEVICE,
|
||||||
|
PHYSPROPSFL_NOROTOR,
|
||||||
|
PHYSPROPSFL_USEOUT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!QUAKED prop_physics (1 0 0) (-16 -16 -16) (16 16 16) ASLEEP NOPHYSDMG DEBRIS NOMOTION x x PHYSDEVICE NOROTOR USEOUT
|
||||||
# OVERVIEW
|
# OVERVIEW
|
||||||
Physics model
|
Physics model
|
||||||
|
|
||||||
|
@ -25,7 +37,13 @@ Physics model
|
||||||
- "targetname" : Name
|
- "targetname" : Name
|
||||||
|
|
||||||
# SPAWNFLAGS
|
# SPAWNFLAGS
|
||||||
- PRPPHYS_ASLEEP (1) : Prop starts without physics and stays until it is impacted.
|
- ASLEEP (1) : Prop starts without physics and stays until it is impacted.
|
||||||
|
- NOPHYSDMG (2) : Will not take physics damage.
|
||||||
|
- DEBRIS (4) : Will not collide with players, or other types of debris
|
||||||
|
- NOMOTION (8) : Disable motion
|
||||||
|
- PHYSDEVICE (64) : Enable motion when grabbed with a physics device.
|
||||||
|
- NOROTOR (128) : Unaffected by rotor contraptions.
|
||||||
|
- USEOUT (256) : Generate output on +use.
|
||||||
|
|
||||||
# TRIVIA
|
# TRIVIA
|
||||||
This entity was introduced in Half-Life 2 (2004).
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
@ -50,19 +68,27 @@ prop_physics::SpawnKey(string strKey, string strValue)
|
||||||
{
|
{
|
||||||
switch (strKey) {
|
switch (strKey) {
|
||||||
default:
|
default:
|
||||||
NSPhysicsEntity::SpawnKey(strKey, strValue);
|
super::SpawnKey(strKey, strValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
prop_physics::Respawn(void)
|
prop_physics::Respawn(void)
|
||||||
{
|
{
|
||||||
NSPhysicsEntity::Respawn();
|
super::Respawn();
|
||||||
|
|
||||||
if (HasSpawnFlags(PRPPHYS_ASLEEP))
|
if (HasSpawnFlags(PHYSPROPSFL_ASLEEP))
|
||||||
PhysicsDisable();
|
Sleep();
|
||||||
else
|
else
|
||||||
PhysicsEnable();
|
Wake();
|
||||||
|
|
||||||
|
if (HasSpawnFlags(PHYSPROPSFL_NOMOTION))
|
||||||
|
Sleep();
|
||||||
|
|
||||||
|
if (HasSpawnFlags(PHYSPROPSFL_PHYSDEVICE))
|
||||||
|
Sleep();
|
||||||
|
|
||||||
|
//Sleep();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
class
|
class
|
||||||
|
@ -85,3 +111,6 @@ prop_physics::Respawn(void)
|
||||||
SetSolid(SOLID_BBOX);
|
SetSolid(SOLID_BBOX);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CLASSEXPORT(prop_physics_override, prop_physics)
|
||||||
|
CLASSEXPORT(prop_physics_respawnable, prop_physics)
|
||||||
|
|
|
@ -39,7 +39,7 @@ waste disk space and memory. Use wisely.
|
||||||
This entity was introduced in Half-Life 2 (2004).
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
*/
|
*/
|
||||||
class
|
class
|
||||||
prop_static:NSRenderableEntity
|
prop_static:NSPhysicsEntity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void prop_static(void);
|
void prop_static(void);
|
||||||
|
@ -56,10 +56,13 @@ prop_static::prop_static(void)
|
||||||
void
|
void
|
||||||
prop_static::Respawn(void)
|
prop_static::Respawn(void)
|
||||||
{
|
{
|
||||||
SetSolid(SOLID_NOT);
|
|
||||||
SetModel(GetSpawnModel());
|
SetModel(GetSpawnModel());
|
||||||
mins = [0,0,0];
|
|
||||||
maxs = [0,0,0];
|
|
||||||
SetSize(mins, maxs);
|
|
||||||
SetOrigin(GetSpawnOrigin());
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
SetMovetype(MOVETYPE_PHYSICS);
|
||||||
|
SetSolid(SOLID_PHYSICS_BOX);
|
||||||
|
geomtype = GEOMTYPE_TRIMESH;
|
||||||
|
|
||||||
|
Sleep();
|
||||||
|
SetTakedamage(DAMAGE_NO);
|
||||||
|
touch = __NULL__;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,5 +35,6 @@ shared/point_spotlight.qc
|
||||||
shared/trigger_push.qc
|
shared/trigger_push.qc
|
||||||
shared/func_conveyor.qc
|
shared/func_conveyor.qc
|
||||||
shared/prop_rope.qc
|
shared/prop_rope.qc
|
||||||
|
shared/phys_rope.qc
|
||||||
shared/worldspawn.qc
|
shared/worldspawn.qc
|
||||||
#endlist
|
#endlist
|
||||||
|
|
|
@ -37,6 +37,8 @@ public:
|
||||||
void env_muzzleflash(void);
|
void env_muzzleflash(void);
|
||||||
|
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string,string);
|
||||||
virtual void SpawnKey(string, string);
|
virtual void SpawnKey(string, string);
|
||||||
virtual void Input(entity, string, string);
|
virtual void Input(entity, string, string);
|
||||||
virtual void Input(entity, string, string);
|
virtual void Input(entity, string, string);
|
||||||
|
@ -63,10 +65,50 @@ env_muzzleflash::env_muzzleflash(void)
|
||||||
m_eOwner = __NULL__;
|
m_eOwner = __NULL__;
|
||||||
m_strModel = __NULL__;
|
m_strModel = __NULL__;
|
||||||
m_strParticle = __NULL__;
|
m_strParticle = __NULL__;
|
||||||
|
m_eMuzzler = __NULL__;
|
||||||
scale = 1.0f;
|
scale = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
|
void
|
||||||
|
env_muzzleflash::Save(float handle)
|
||||||
|
{
|
||||||
|
super::Save(handle);
|
||||||
|
SaveString(handle, "m_strAttachmentName", m_strAttachmentName);
|
||||||
|
SaveInt(handle, "m_iAttachment", m_iAttachment);
|
||||||
|
SaveEntity(handle, "m_eOwner", m_eOwner);
|
||||||
|
SaveString(handle, "m_strModel", m_strModel);
|
||||||
|
SaveString(handle, "m_strParticle", m_strParticle);
|
||||||
|
SaveEntity(handle, "m_eMuzzler", m_eMuzzler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env_muzzleflash::Restore(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "m_strAttachmentName":
|
||||||
|
m_strAttachmentName = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
case "m_iAttachment":
|
||||||
|
m_iAttachment = ReadInt(strValue);
|
||||||
|
break;
|
||||||
|
case "m_eOwner":
|
||||||
|
m_eOwner = (NSRenderableEntity)ReadEntity(strValue);
|
||||||
|
break;
|
||||||
|
case "m_strModel":
|
||||||
|
m_strModel = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
case "m_strParticle":
|
||||||
|
m_strParticle = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
case "m_eMuzzler":
|
||||||
|
m_eMuzzler = ReadEntity(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Restore(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
env_muzzleflash::SpawnKey(string keyName, string setValue)
|
env_muzzleflash::SpawnKey(string keyName, string setValue)
|
||||||
{
|
{
|
||||||
|
@ -107,11 +149,16 @@ env_muzzleflash::Input(entity eAct, string strKey, string strValue)
|
||||||
void
|
void
|
||||||
env_muzzleflash::Trigger(entity theActivator, triggermode_t triggerState)
|
env_muzzleflash::Trigger(entity theActivator, triggermode_t triggerState)
|
||||||
{
|
{
|
||||||
NSEntity targetEnt;
|
NSEntity targetEnt = __NULL__;
|
||||||
vector targetPosition = GetOrigin();
|
vector targetPosition = GetOrigin();
|
||||||
|
|
||||||
if (m_parent) {
|
if (m_parent) {
|
||||||
targetEnt = (NSEntity)find(world, ::targetname, m_parent);
|
targetEnt = (NSEntity)find(world, ::targetname, m_parent);
|
||||||
|
|
||||||
|
if (!targetEnt) {
|
||||||
|
NSEntWarning("Entity specified but not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
||||||
|
@ -155,7 +202,7 @@ EV_MuzzleFlash_Parse(void)
|
||||||
{
|
{
|
||||||
env_muzzleflash tempMuzzle = spawn(env_muzzleflash);
|
env_muzzleflash tempMuzzle = spawn(env_muzzleflash);
|
||||||
|
|
||||||
tempMuzzle.m_eOwner = findfloat(world, entnum, readentitynum());
|
tempMuzzle.m_eOwner = (NSRenderableEntity)findfloat(world, entnum, readentitynum());
|
||||||
tempMuzzle.m_iAttachment = readbyte();
|
tempMuzzle.m_iAttachment = readbyte();
|
||||||
tempMuzzle.scale = readfloat();
|
tempMuzzle.scale = readfloat();
|
||||||
tempMuzzle.modelindex = readshort();
|
tempMuzzle.modelindex = readshort();
|
||||||
|
@ -171,7 +218,7 @@ EV_MuzzleFlash_Create(entity muzzleOwner, int attachmentID, float muzzleScale, i
|
||||||
{
|
{
|
||||||
env_muzzleflash tempMuzzle = spawn(env_muzzleflash);
|
env_muzzleflash tempMuzzle = spawn(env_muzzleflash);
|
||||||
|
|
||||||
tempMuzzle.m_eOwner = muzzleOwner;
|
tempMuzzle.m_eOwner = (NSRenderableEntity)muzzleOwner;
|
||||||
tempMuzzle.m_iAttachment = attachmentID;
|
tempMuzzle.m_iAttachment = attachmentID;
|
||||||
tempMuzzle.scale = muzzleScale;
|
tempMuzzle.scale = muzzleScale;
|
||||||
tempMuzzle.alpha = 1.0f;
|
tempMuzzle.alpha = 1.0f;
|
||||||
|
|
|
@ -86,7 +86,7 @@ env_shockwave::env_shockwave(void)
|
||||||
m_flHeight = 32.0f;
|
m_flHeight = 32.0f;
|
||||||
m_flNoiseAmp = 0.0f;
|
m_flNoiseAmp = 0.0f;
|
||||||
m_vecColor = [1,1,1];
|
m_vecColor = [1,1,1];
|
||||||
m_flBrightness = 1.0f;;
|
m_flBrightness = 1.0f;
|
||||||
m_flScrollSpeed = 0.0f;
|
m_flScrollSpeed = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,363 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enumflags
|
||||||
|
{
|
||||||
|
PHYSROPE_CHANGED_MAT,
|
||||||
|
PHYSROPE_CHANGED_SAG,
|
||||||
|
PHYSROPE_CHANGED_SWING,
|
||||||
|
PHYSROPE_CHANGED_SEGMENTS,
|
||||||
|
PHYSROPE_CHANGED_ORIGIN,
|
||||||
|
PHYSROPE_CHANGED_TARGET,
|
||||||
|
PHYSROPE_CHANGED_FLAGS,
|
||||||
|
PHYSROPE_CHANGED_WIDTH
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!QUAKED phys_rope (1 0 0) (-8 -8 -8) (8 8 8) ROPE_VERTICAL
|
||||||
|
# OVERVIEW
|
||||||
|
Client-side decorative rope entity.
|
||||||
|
Connect the entity to a named info_notnull and watch it swing around.
|
||||||
|
|
||||||
|
# KEYS
|
||||||
|
- "sag" : Multiplier on how much sagginess will be applied to the rope.
|
||||||
|
- "segments" : Number of total segments. Default is "16".
|
||||||
|
- "material" : The texture to use on the rope.
|
||||||
|
- "swingfactor" : Multiplier on how much the rope swings about.
|
||||||
|
- "target" : The info_notnull to connect the rope to.
|
||||||
|
|
||||||
|
# SPAWNFLAGS
|
||||||
|
- ROPE_VERTICAL (1) : Only draw the first half of the rope, useful for vertical setups.
|
||||||
|
|
||||||
|
# TRIVIA
|
||||||
|
This entity was introduced in The Wastes (2018).
|
||||||
|
*/
|
||||||
|
class phys_rope:NSEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void phys_rope(void);
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
virtual float predraw(void);
|
||||||
|
virtual void ReceiveEntity(float,float);
|
||||||
|
virtual void DrawSegment(vector, vector, vector);
|
||||||
|
#else
|
||||||
|
virtual void SpawnKey(string,string);
|
||||||
|
virtual void Respawn(void);
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string, string);
|
||||||
|
virtual void EvaluateEntity(void);
|
||||||
|
virtual float SendEntity(entity,float);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
string m_strShader;
|
||||||
|
PREDICTED_FLOAT(m_flSag)
|
||||||
|
PREDICTED_FLOAT(m_flSwingFactor)
|
||||||
|
PREDICTED_INT(m_iSegments)
|
||||||
|
PREDICTED_VECTOR(m_vecTarget)
|
||||||
|
PREDICTED_FLOAT(m_flWidth)
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_rope::DrawSegment(vector pos1, vector pos2, vector vecPlayer)
|
||||||
|
{
|
||||||
|
vector lit1 = /*[0.1,0.1,0.1] */ getlight(pos1) / 255;
|
||||||
|
vector lit2 = /*[0.1,0.1,0.1] */ getlight(pos2) / 255;
|
||||||
|
|
||||||
|
R_BeginPolygon(m_strShader, 0, 0);
|
||||||
|
R_PolygonVertex(pos1, [0,0], lit1, 1.0f);
|
||||||
|
R_PolygonVertex(pos2, [0,1], lit2, 1.0f);
|
||||||
|
R_EndPolygonRibbon(1, [-1,0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
phys_rope::predraw(void)
|
||||||
|
{
|
||||||
|
vector pos1;
|
||||||
|
vector pos2;
|
||||||
|
float segments;
|
||||||
|
vector vecPlayer;
|
||||||
|
NSClientPlayer pl;
|
||||||
|
|
||||||
|
int s = (float)getproperty(VF_ACTIVESEAT);
|
||||||
|
pSeat = &g_seats[s];
|
||||||
|
pl = (NSClientPlayer)pSeat->m_ePlayer;
|
||||||
|
vecPlayer = pl.GetEyePos();
|
||||||
|
|
||||||
|
/* draw the start/end without segments */
|
||||||
|
if (autocvar_rope_debug == TRUE) {
|
||||||
|
R_BeginPolygon("", 0, 0);
|
||||||
|
R_PolygonVertex(origin, [0,1], [0,1,0], 1.0f);
|
||||||
|
R_PolygonVertex(m_vecTarget, [1,1], [0,1,0], 1.0f);
|
||||||
|
R_EndPolygon();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autocvar_rope_maxsegments > 0)
|
||||||
|
segments = bound(1, autocvar_rope_maxsegments, (float)m_iSegments);
|
||||||
|
else
|
||||||
|
segments = (float)m_iSegments;
|
||||||
|
|
||||||
|
float travel = 1.0f / segments;
|
||||||
|
float progress= 0.0f;
|
||||||
|
pos1 = origin;
|
||||||
|
|
||||||
|
makevectors(getproperty(VF_CL_VIEWANGLES));
|
||||||
|
setproperty(VF_ORIGIN, vecPlayer);
|
||||||
|
|
||||||
|
/* get the direction */
|
||||||
|
makevectors(vectoangles(m_vecTarget - origin));
|
||||||
|
|
||||||
|
for (float i = 0; i < segments; i++) {
|
||||||
|
float sag = 0.0f;
|
||||||
|
float swing = 0.0f;
|
||||||
|
progress += travel;
|
||||||
|
float c1 = (ropecos(progress) * M_PI) * 2.25f;
|
||||||
|
|
||||||
|
/* loose hanging rope */
|
||||||
|
if (flags & 1) {
|
||||||
|
sag = c1 * m_flSag;
|
||||||
|
swing = c1 * m_flSwingFactor;
|
||||||
|
} else {
|
||||||
|
sag = c1 * m_flSag;
|
||||||
|
swing = c1 * m_flSwingFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* travel further and sag */
|
||||||
|
pos2[0] = Math_Lerp(origin[0], m_vecTarget[0], progress);
|
||||||
|
pos2[1] = Math_Lerp(origin[1], m_vecTarget[1], progress);
|
||||||
|
pos2[2] = Math_Lerp(origin[2], m_vecTarget[2], progress);
|
||||||
|
pos2 += (v_up * -sag) * autocvar_rope_sag;
|
||||||
|
|
||||||
|
if (!autocvar_rope_fast)
|
||||||
|
pos2 += ((v_right * swing) * sin(time)) * autocvar_rope_swing;
|
||||||
|
|
||||||
|
DrawSegment(pos1, pos2, vecPlayer);
|
||||||
|
pos1 = pos2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PREDRAW_NEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_rope::ReceiveEntity(float new, float flSendFlags)
|
||||||
|
{
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_MAT)
|
||||||
|
m_strShader = readstring();
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_SAG)
|
||||||
|
m_flSag = readfloat();
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_SWING)
|
||||||
|
m_flSwingFactor = readfloat();
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_SEGMENTS)
|
||||||
|
m_iSegments = readint();
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_ORIGIN) {
|
||||||
|
origin[0] = readcoord();
|
||||||
|
origin[1] = readcoord();
|
||||||
|
origin[2] = readcoord();
|
||||||
|
setsize(this, [0,0,0], [0,0,0]);
|
||||||
|
setorigin(this, origin);
|
||||||
|
}
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_TARGET) {
|
||||||
|
m_vecTarget[0] = readcoord();
|
||||||
|
m_vecTarget[1] = readcoord();
|
||||||
|
m_vecTarget[2] = readcoord();
|
||||||
|
}
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_FLAGS)
|
||||||
|
flags = readfloat();
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_WIDTH)
|
||||||
|
m_flWidth = readfloat();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
phys_rope::Respawn(void)
|
||||||
|
{
|
||||||
|
if (HasSpawnFlags(1)) {
|
||||||
|
flags = 1;
|
||||||
|
}
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
SetSize([0,0,0], [0,0,0]);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
phys_rope::EvaluateEntity(void)
|
||||||
|
{
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entity eFind = find(world, ::targetname, target);
|
||||||
|
|
||||||
|
if (!eFind) {
|
||||||
|
print(sprintf("phys_rope: Unable to find target %S\n", target));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vecTarget = eFind.origin;
|
||||||
|
|
||||||
|
if (ATTR_CHANGED(m_flSag)) {
|
||||||
|
SetSendFlags(PHYSROPE_CHANGED_SAG);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(m_flSwingFactor)) {
|
||||||
|
SetSendFlags(PHYSROPE_CHANGED_SWING);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(m_iSegments)) {
|
||||||
|
SetSendFlags(PHYSROPE_CHANGED_SEGMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ATTR_CHANGED(origin)) {
|
||||||
|
SetSendFlags(PHYSROPE_CHANGED_ORIGIN);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(m_vecTarget)) {
|
||||||
|
SetSendFlags(PHYSROPE_CHANGED_TARGET);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(flags)) {
|
||||||
|
SetSendFlags(PHYSROPE_CHANGED_FLAGS);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(m_flWidth)) {
|
||||||
|
SetSendFlags(PHYSROPE_CHANGED_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAVE_STATE(m_flSag)
|
||||||
|
SAVE_STATE(m_flSwingFactor)
|
||||||
|
SAVE_STATE(m_iSegments)
|
||||||
|
SAVE_STATE(origin)
|
||||||
|
SAVE_STATE(m_vecTarget)
|
||||||
|
SAVE_STATE(flags)
|
||||||
|
SAVE_STATE(m_flWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
phys_rope::SendEntity(entity ePVEnt, float flSendFlags)
|
||||||
|
{
|
||||||
|
if (!target)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
WriteByte(MSG_ENTITY, ENT_PHYSROPE);
|
||||||
|
WriteFloat(MSG_ENTITY, flSendFlags);
|
||||||
|
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_MAT)
|
||||||
|
WriteString(MSG_ENTITY, m_strShader);
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_SAG)
|
||||||
|
WriteFloat(MSG_ENTITY, m_flSag);
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_SWING)
|
||||||
|
WriteFloat(MSG_ENTITY, m_flSwingFactor);
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_SEGMENTS)
|
||||||
|
WriteInt(MSG_ENTITY, m_iSegments);
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_ORIGIN) {
|
||||||
|
WriteCoord(MSG_ENTITY, origin[0]);
|
||||||
|
WriteCoord(MSG_ENTITY, origin[1]);
|
||||||
|
WriteCoord(MSG_ENTITY, origin[2]);
|
||||||
|
}
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_TARGET) {
|
||||||
|
WriteCoord(MSG_ENTITY, m_vecTarget[0]);
|
||||||
|
WriteCoord(MSG_ENTITY, m_vecTarget[1]);
|
||||||
|
WriteCoord(MSG_ENTITY, m_vecTarget[2]);
|
||||||
|
}
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_FLAGS) {
|
||||||
|
WriteFloat(MSG_ENTITY, flags);
|
||||||
|
}
|
||||||
|
if (flSendFlags & PHYSROPE_CHANGED_WIDTH) {
|
||||||
|
WriteFloat(MSG_ENTITY, m_flWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_rope::SpawnKey(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "sag":
|
||||||
|
m_flSag = stof(strValue);
|
||||||
|
break;
|
||||||
|
case "segments":
|
||||||
|
m_iSegments = stoi(strValue);
|
||||||
|
break;
|
||||||
|
case "shader":
|
||||||
|
m_strShader = strValue;
|
||||||
|
break;
|
||||||
|
case "swingfactor":
|
||||||
|
m_flSwingFactor = stof(strValue);
|
||||||
|
break;
|
||||||
|
case "NextKey":
|
||||||
|
target = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
case "Width":
|
||||||
|
m_flWidth = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::SpawnKey(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_rope::Save(float handle)
|
||||||
|
{
|
||||||
|
super::Save(handle);
|
||||||
|
|
||||||
|
SaveString(handle, "m_strShader", m_strShader);
|
||||||
|
SaveFloat(handle, "m_flSag", m_flSag);
|
||||||
|
SaveFloat(handle, "m_flSwingFactor", m_flSwingFactor);
|
||||||
|
SaveInt(handle, "m_iSegments", m_iSegments);
|
||||||
|
SaveVector(handle, "m_vecTarget", m_vecTarget);
|
||||||
|
SaveFloat(handle, "m_flWidth", m_flWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_rope::Restore(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "RopeMaterial":
|
||||||
|
m_strShader = ReadString(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flSag":
|
||||||
|
m_flSag = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flSwingFactor":
|
||||||
|
m_flSwingFactor = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "Subdiv":
|
||||||
|
m_iSegments = ReadInt(strValue);
|
||||||
|
break;
|
||||||
|
case "m_vecTarget":
|
||||||
|
m_vecTarget = ReadVector(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flWidth":
|
||||||
|
m_flWidth = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::Restore(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
phys_rope::phys_rope(void)
|
||||||
|
{
|
||||||
|
#ifdef SERVER
|
||||||
|
m_flSwingFactor = random();
|
||||||
|
m_flSag = 15.0f;
|
||||||
|
m_iSegments = 16;
|
||||||
|
m_flWidth = 2.0f;
|
||||||
|
m_strShader = "materials/cable/cable.vmt";
|
||||||
|
#else
|
||||||
|
/* this is empty for a good reason */
|
||||||
|
drawmask = MASK_ENGINE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CLASSEXPORT(move_rope, phys_rope)
|
||||||
|
CLASSEXPORT(keyframe_rope, phys_rope)
|
|
@ -75,9 +75,9 @@ prop_physics_multiplayer::TouchThink(void)
|
||||||
|
|
||||||
if (trace_ent.flags & FL_CLIENT) {
|
if (trace_ent.flags & FL_CLIENT) {
|
||||||
//print(sprintf("%s %f\n", trace_ent.classname, trace_fraction));
|
//print(sprintf("%s %f\n", trace_ent.classname, trace_fraction));
|
||||||
PhysicsEnable();
|
Wake();
|
||||||
makevectors(origin - trace_ent.origin);
|
makevectors(origin - trace_ent.origin);
|
||||||
ApplyForceCenter(v_forward * 64);
|
ApplyForceOffset(v_forward * 64, trace_endpos);
|
||||||
velocity = v_forward * 64;
|
velocity = v_forward * 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ prop_physics_multiplayer::TouchThink(void)
|
||||||
} else {
|
} else {
|
||||||
if (vlen(velocity) < 2) {
|
if (vlen(velocity) < 2) {
|
||||||
velocity = [0,0,0];
|
velocity = [0,0,0];
|
||||||
PhysicsDisable();
|
Sleep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,9 +127,9 @@ prop_physics_multiplayer::Respawn(void)
|
||||||
super::Respawn();
|
super::Respawn();
|
||||||
|
|
||||||
if (HasSpawnFlags(PRPPHYS_ASLEEP))
|
if (HasSpawnFlags(PRPPHYS_ASLEEP))
|
||||||
PhysicsDisable();
|
Sleep();
|
||||||
else
|
else
|
||||||
PhysicsEnable();
|
Wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -451,7 +451,7 @@ NSGameRules::DamageRadius(vector org, entity attacker, float dmg, float r, int c
|
||||||
new_dmg = rint(dmg * diff);
|
new_dmg = rint(dmg * diff);
|
||||||
|
|
||||||
if (diff > 0) {
|
if (diff > 0) {
|
||||||
g_dmg_vecLocation = org;
|
g_dmg_vecLocation = trace_endpos;
|
||||||
DamageApply(e, attacker, new_dmg, w, DMG_EXPLODE);
|
DamageApply(e, attacker, new_dmg, w, DMG_EXPLODE);
|
||||||
|
|
||||||
/* approximate, feel free to tweak */
|
/* approximate, feel free to tweak */
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CONSTRAINT_FIXED = -1, /**< Fixed constraint, aka weld, aka phys_constraint. */
|
||||||
|
CONSTRAINT_INVALID, /**< Nothing. Default. */
|
||||||
|
CONSTRAINT_POINT, /**< Point constraint, aka ballsocket or ball constraint, like phys_ballsocket. */
|
||||||
|
CONSTRAINT_HINGE, /**< Hinge joint constraint. Like phys_hinge */
|
||||||
|
CONSTRAINT_SLIDER, /**< Slider setup. Like phys_slideconstraint. */
|
||||||
|
CONSTRAINT_UNIVERSAL, /**< Universal? TBA. */
|
||||||
|
CONSTRAINT_HINGE2 /**< Hinge 2. TBA. */
|
||||||
|
} constraint_t;
|
||||||
|
|
||||||
|
/** This entity class represents constraints for physically-simulated entities.
|
||||||
|
|
||||||
|
If you want to create an easy 'weld' type connection, a ballsocket or even a rope
|
||||||
|
type connection - this class is what you need.*/
|
||||||
|
class
|
||||||
|
NSPhysicsConstraint:NSEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void NSPhysicsConstraint(void);
|
||||||
|
|
||||||
|
|
||||||
|
virtual void SpawnKey(string, string);
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
virtual void Save(float);
|
||||||
|
virtual void Restore(string,string);
|
||||||
|
virtual void Input(entity, string, string);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
virtual void Spawned(void);
|
||||||
|
virtual void OnRemoveEntity(void);
|
||||||
|
|
||||||
|
/** Awakes the entities this constraint is connected to. */
|
||||||
|
nonvirtual void WakeTargets(void);
|
||||||
|
|
||||||
|
/** Breaks the constraint. */
|
||||||
|
nonvirtual void Break(entity);
|
||||||
|
|
||||||
|
/** Returns the type of this constraint entity. */
|
||||||
|
nonvirtual constraint_t GetConstraintType(void);
|
||||||
|
/** Returns the first entity connection. Should not return world/__NULL__ */
|
||||||
|
nonvirtual entity GetEntity1(void);
|
||||||
|
/** Returns the second entity connection. Can also return world/__NULL__ */
|
||||||
|
nonvirtual entity GetEntity2(void);
|
||||||
|
|
||||||
|
/** Will override the constraint type this entity represents. See constraint_t for choices. */
|
||||||
|
nonvirtual void SetConstraintType(constraint_t);
|
||||||
|
/** Sets the first entity in the connection. Needs to be set. */
|
||||||
|
nonvirtual void SetEntity1(entity);
|
||||||
|
/** Sets the second entity in the connection. Can be world. */
|
||||||
|
nonvirtual void SetEntity2(entity);
|
||||||
|
//nonvirtual void SetBone1(float);
|
||||||
|
//nonvirtual void SetBone2(float);
|
||||||
|
|
||||||
|
/** Sets the velocity on a CONSTRAINT_SLIDER type NSPhysicsConstraint. */
|
||||||
|
nonvirtual void SetSliderVelocity(float);
|
||||||
|
/** Sets the max velocity on a CONSTRAINT_SLIDER type NSPhysicsConstraint. */
|
||||||
|
nonvirtual void SetSliderMaxVelocity(float);
|
||||||
|
/** Sets the maximum travel distance of the slider. */
|
||||||
|
nonvirtual void SetSliderStop(float);
|
||||||
|
/** Sets the friction of the slider. */
|
||||||
|
nonvirtual void SetSliderFriction(float);
|
||||||
|
|
||||||
|
/** Returns the velocity of a CONSTRAINT_SLIDER type NSPhysicsConstraint. */
|
||||||
|
nonvirtual float GetSliderVelocity(void);
|
||||||
|
/** Returns the max velocity of a CONSTRAINT_SLIDER type NSPhysicsConstraint. */
|
||||||
|
nonvirtual float GetSliderMaxVelocity(void);
|
||||||
|
/** Returns the maximum travel distance of the slider. */
|
||||||
|
nonvirtual float GetSliderStop(void);
|
||||||
|
/** Returns the friction of the slider. */
|
||||||
|
nonvirtual float GetSliderFriction(void);
|
||||||
|
/** Returns the unique joint group ID associated with a phys_constraintsystem. */
|
||||||
|
nonvirtual float GetConstraintSystemID(void);
|
||||||
|
|
||||||
|
/** Creates a ballsocket constraint and returns it. */
|
||||||
|
nonvirtual NSPhysicsConstraint Ballsocket(entity, entity, vector, vector, float, bool);
|
||||||
|
/** Creates a ballsocket constraint and returns it. */
|
||||||
|
nonvirtual NSPhysicsConstraint Weld(entity, entity, float, float, float, bool, bool);
|
||||||
|
/** Creates a ballsocket constraint and returns it. */
|
||||||
|
nonvirtual NSPhysicsConstraint Rope(entity, entity, vector, vector);
|
||||||
|
|
||||||
|
nonvirtual NSPhysicsConstraint KeepUpright(entity, vector, float);
|
||||||
|
|
||||||
|
nonvirtual void ConstraintThink(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
float m_flTorqueLimit;
|
||||||
|
float m_flForceLimit;
|
||||||
|
string m_strEnt1;
|
||||||
|
string m_strEnt2;
|
||||||
|
string m_strBreakSound;
|
||||||
|
string m_strOnBreak;
|
||||||
|
string m_strConstraintSystem;
|
||||||
|
};
|
|
@ -0,0 +1,375 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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();
|
||||||
|
|
||||||
|
print(sprintf("Created ballsocket between %s and %s\n", 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) {
|
||||||
|
print("^1Cannot weld the entity with itself!\n");
|
||||||
|
return __NULL__;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSPhysicsConstraint new = spawn(NSPhysicsConstraint);
|
||||||
|
new.SetConstraintType(CONSTRAINT_FIXED);
|
||||||
|
new.SetEntity1(firstEnt);
|
||||||
|
new.SetEntity2(secondEnt);
|
||||||
|
new.WakeTargets();
|
||||||
|
|
||||||
|
print(sprintf("Created weld between %s and %s\n", 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();
|
||||||
|
|
||||||
|
print(sprintf("Created rope between %s and %s\n", 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__;
|
||||||
|
}
|
|
@ -14,6 +14,27 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var bool autocvar_phys_developer = false;
|
||||||
|
void
|
||||||
|
_NSPhysics_Log(string msg)
|
||||||
|
{
|
||||||
|
if (autocvar_phys_developer == true)
|
||||||
|
print(sprintf("%f %s\n", time, msg));
|
||||||
|
}
|
||||||
|
#define NSPhysics_Log(...) _NSPhysics_Log(sprintf(__VA_ARGS__))
|
||||||
|
|
||||||
|
|
||||||
|
var float autocvar_phys_pushscale = 1.0f;
|
||||||
|
var float autocvar_phys_impactforcescale = 1.0f;
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
var bool autocvar_r_showPhysicsInfo = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.float damp_linear;
|
||||||
|
.float damp_angular;
|
||||||
|
.float jointgroup;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PHYSM_BOX,
|
PHYSM_BOX,
|
||||||
|
@ -54,7 +75,13 @@ typedef enumflags
|
||||||
PHYENT_CHANGED_RENDERMODE,
|
PHYENT_CHANGED_RENDERMODE,
|
||||||
} nsphyricsentity_changed_t;
|
} nsphyricsentity_changed_t;
|
||||||
|
|
||||||
/** This entity class represents physically-simulated entities. */
|
/** This entity class represents physically-simulated entities.
|
||||||
|
|
||||||
|
The physics simulator used is controlled by the engine and may be
|
||||||
|
subject to change.
|
||||||
|
|
||||||
|
Units of mass is defined in kilograms, a standard unit of measurement.
|
||||||
|
You will find the API to be mostly compatible of that offered by Garry's Mod. */
|
||||||
class NSPhysicsEntity:NSSurfacePropEntity
|
class NSPhysicsEntity:NSSurfacePropEntity
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -63,11 +90,20 @@ private:
|
||||||
int m_iMaterial;
|
int m_iMaterial;
|
||||||
int m_iFlags;
|
int m_iFlags;
|
||||||
float m_flInertiaScale;
|
float m_flInertiaScale;
|
||||||
|
float m_flBuoyancyRatio;
|
||||||
|
|
||||||
|
/* performance sanity checks */
|
||||||
|
vector m_vecPrevOrigin;
|
||||||
|
vector m_vecPrevAngles;
|
||||||
|
float m_flCheckTime;
|
||||||
|
|
||||||
virtual void _TouchThink(void);
|
virtual void _TouchThink(void);
|
||||||
|
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
PREDICTED_VECTOR(m_vecNetAngles)
|
PREDICTED_VECTOR(m_vecNetAngles)
|
||||||
|
PREDICTED_FLOAT_N(mass)
|
||||||
|
|
||||||
|
string m_strOnDamaged;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -77,49 +113,101 @@ public:
|
||||||
virtual void Respawn(void);
|
virtual void Respawn(void);
|
||||||
virtual void SpawnKey(string,string);
|
virtual void SpawnKey(string,string);
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
|
virtual void Spawned(void);
|
||||||
virtual void Pain(void);
|
virtual void Pain(void);
|
||||||
virtual void Death(void);
|
virtual void Death(void);
|
||||||
virtual void EvaluateEntity(void);
|
virtual void EvaluateEntity(void);
|
||||||
virtual float SendEntity(entity,float);
|
virtual float SendEntity(entity,float);
|
||||||
virtual void Save(float);
|
virtual void Save(float);
|
||||||
virtual void Restore(string,string);
|
virtual void Restore(string,string);
|
||||||
|
virtual void Touch(entity);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CLIENT
|
#ifdef CLIENT
|
||||||
virtual void ReceiveEntity(float,float);
|
virtual void ReceiveEntity(float,float);
|
||||||
|
virtual void postdraw(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Sets the mass of the entity in ??? */
|
|
||||||
nonvirtual void SetMass(float);
|
|
||||||
/** Returns the mass of the entity. */
|
|
||||||
nonvirtual float GetMass(void);
|
|
||||||
/** Sets the friction multiplier for this entity. Default is 1.0 */
|
/** Sets the friction multiplier for this entity. Default is 1.0 */
|
||||||
nonvirtual void SetFriction(float);
|
nonvirtual void SetFriction(float);
|
||||||
/** Returns the friction multiplayer for this entity. */
|
/** Returns the friction multiplayer for this entity. */
|
||||||
nonvirtual float GetFriction(void);
|
nonvirtual float GetFriction(void);
|
||||||
/** Sets the bounce factor for this entity. Default is 1.0 */
|
|
||||||
nonvirtual void SetBounceFactor(float);
|
/** Called by the physics routine to figure out the impact damage. */
|
||||||
/** Returns the bounce factor of this entity. */
|
nonvirtual float CalculateImpactDamage(int,int);
|
||||||
nonvirtual float GetBounceFactor(void);
|
|
||||||
/** Sets the bounce stop factor for this entity. */
|
/* this merely mirrors the GMod API: https://wiki.facepunch.com/gmod/PhysObj */
|
||||||
nonvirtual void SetBounceStop(float);
|
|
||||||
/** Returns the bounce stop factor of this entity. */
|
/** Call to align angles of the object to the ones passed. */
|
||||||
nonvirtual float GetBounceStop(void);
|
nonvirtual vector AlignAngles(vector, vector);
|
||||||
/** Sets the inertia modifier for this entity. */
|
|
||||||
nonvirtual void SetInertia(float);
|
|
||||||
/** Returns the inertia modifier of this entity. */
|
|
||||||
nonvirtual float GetInertia(void);
|
|
||||||
/** Call to enable physics simulation on this entity. */
|
|
||||||
nonvirtual void PhysicsEnable(void);
|
|
||||||
/** Call to freeze physics simulation on this entity. */
|
|
||||||
nonvirtual void PhysicsDisable(void);
|
|
||||||
/** Call to apply a force (absolute velocity vector) to the center of the entity. */
|
/** Call to apply a force (absolute velocity vector) to the center of the entity. */
|
||||||
nonvirtual void ApplyForceCenter(vector);
|
nonvirtual void ApplyForceCenter(vector);
|
||||||
/** Call to apply force (absolute velocity vector) to a specific position on the entity. */
|
/** Call to apply force (absolute velocity vector) to an absolute position on the entity. */
|
||||||
nonvirtual void ApplyForceOffset(vector,vector);
|
nonvirtual void ApplyForceOffset(vector,vector);
|
||||||
/** Call to apply torque (angular velocity vector) to the center of the entity. */
|
/** Call to apply torque (angular velocity vector) to the center of the entity. */
|
||||||
nonvirtual void ApplyTorqueCenter(vector);
|
nonvirtual void ApplyTorqueCenter(vector);
|
||||||
/** Called by the physics routine to figure out the impact damage. */
|
/** Call to set whether the entity should be affected by drag. */
|
||||||
nonvirtual float CalculateImpactDamage(int,int);
|
nonvirtual void EnableDrag(bool);
|
||||||
|
/** Call to set whether the entity should be affected by gravity. */
|
||||||
|
nonvirtual void EnableGravity(bool);
|
||||||
|
/** Call to set whether the entity should be able to move. */
|
||||||
|
nonvirtual void EnableMotion(bool);
|
||||||
|
/** Returns the linear damping of the entity. */
|
||||||
|
nonvirtual float GetLinearDamping(void);
|
||||||
|
/** Returns the angular damping of the entity. */
|
||||||
|
nonvirtual float GetAngularDamping(void);
|
||||||
|
/** Returns the linear and rotational kinetic energy combined. */
|
||||||
|
nonvirtual float GetEnergy(void);
|
||||||
|
/** Returns the inertia modifier of this entity. */
|
||||||
|
nonvirtual float GetInertia(void);
|
||||||
|
/** Returns 1 divided by the angular inertia of this entity. */
|
||||||
|
nonvirtual float GetInvInertia(void);
|
||||||
|
/** Returns 1 divided by the mass of this entity. */
|
||||||
|
nonvirtual float GetInvMass(void);
|
||||||
|
/** Returns the mass of the entity. */
|
||||||
|
nonvirtual float GetMass(void);
|
||||||
|
/** Returns the center of mass of the entity. */
|
||||||
|
nonvirtual vector GetMassCenter(void);
|
||||||
|
/** Returns the rotational damping of the entity. */
|
||||||
|
nonvirtual float GetRotDamping(void);
|
||||||
|
/** Returns the speed damping of the entity. */
|
||||||
|
nonvirtual float GetSpeedDamping(void);
|
||||||
|
/** Returns the surface area of the entity. */
|
||||||
|
nonvirtual float GetSurfaceArea(void);
|
||||||
|
/** Returns the volume of the entity. */
|
||||||
|
nonvirtual float GetVolume(void);
|
||||||
|
/** Returns whether the entity is at rest and not moving. */
|
||||||
|
nonvirtual bool IsAsleep(void);
|
||||||
|
/** Returns whether the entity is able to collide with anything. */
|
||||||
|
nonvirtual bool IsCollisionEnabled(void);
|
||||||
|
/** Returns whether the entity is affected by drag. */
|
||||||
|
nonvirtual bool IsDragEnabled(void);
|
||||||
|
/** Returns whether the entity is affected by gravity. */
|
||||||
|
nonvirtual bool IsGravityEnabled(void);
|
||||||
|
/** Returns whether the entity is able to move by itself. */
|
||||||
|
nonvirtual bool IsMotionEnabled(void);
|
||||||
|
/** Returns whether the entity is able to move. */
|
||||||
|
nonvirtual bool IsMoveable(void);
|
||||||
|
/** Returns whether the entity is penetrating another object. */
|
||||||
|
nonvirtual bool IsPenetrating(void);
|
||||||
|
|
||||||
|
/** Call to set the amount of rotational drag the entity experiences. */
|
||||||
|
nonvirtual void SetAngleDragCoefficient(float);
|
||||||
|
/** Call to set the buoyancy ratio of the entity. 0 is not buoyant, 1 is very buoyant. */
|
||||||
|
nonvirtual void SetBuoyancyRatio(float);
|
||||||
|
/** Call to set the linear and angular damping of the entity. */
|
||||||
|
nonvirtual void SetDamping(float, float);
|
||||||
|
/** Call to set how much drag affects the entity. */
|
||||||
|
nonvirtual void SetDragCoefficient(float);
|
||||||
|
|
||||||
|
/** Sets the angular inertia for this entity. */
|
||||||
|
nonvirtual void SetInertia(float);
|
||||||
|
/** Sets the mass of the entity in kilograms. */
|
||||||
|
nonvirtual void SetMass(float);
|
||||||
|
|
||||||
|
/** Call to enable physics simulation on this entity. */
|
||||||
|
nonvirtual void Wake(void);
|
||||||
|
/** Call to freeze physics simulation on this entity. */
|
||||||
|
nonvirtual void Sleep(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
noref .bool isPhysics;
|
noref .bool isPhysics;
|
|
@ -14,30 +14,64 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ODE_MODE 1
|
.float max_angular;
|
||||||
|
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::NSPhysicsEntity(void)
|
NSPhysicsEntity::NSPhysicsEntity(void)
|
||||||
{
|
{
|
||||||
isPhysics = true;
|
|
||||||
mass = 1.0f;
|
mass = 1.0f;
|
||||||
|
isPhysics = true;
|
||||||
m_flInertiaScale = 1.0f;
|
m_flInertiaScale = 1.0f;
|
||||||
|
|
||||||
m_iEnabled = 0i;
|
m_iEnabled = 0i;
|
||||||
m_iShape = PHYSM_BOX;
|
m_iShape = PHYSM_BOX;
|
||||||
m_iMaterial = 0i;
|
m_iMaterial = 0i;
|
||||||
m_iFlags = 0i;
|
m_iFlags = 0i;
|
||||||
|
damp_linear = 1.0f;
|
||||||
|
damp_angular = 1.0f;
|
||||||
|
max_angular = -1.0f;
|
||||||
|
|
||||||
#ifdef ODE_MODE
|
|
||||||
cvar_set("physics_ode_iterationsperframe", "1");
|
cvar_set("physics_ode_quadtree_depth", "10");
|
||||||
cvar_set("physics_ode_movelimit", "0.1");
|
cvar_set("physics_ode_contactsurfacelayer", "0");
|
||||||
#else
|
cvar_set("physics_ode_worldquickstep", "1");
|
||||||
cvar_set("physics_bullet_maxiterationsperframe", "10");
|
cvar_set("physics_ode_worldquickstep_iterations", "20");
|
||||||
cvar_set("physics_bullet_framerate", "60");
|
cvar_set("physics_ode_contact_mu", "-1");
|
||||||
|
cvar_set("physics_ode_contact_erp", "0.96");
|
||||||
|
cvar_set("physics_ode_contact_cfm", "0.001");
|
||||||
|
cvar_set("physics_ode_world_damping", "1");
|
||||||
|
cvar_set("physics_ode_world_damping_linear", "-1");
|
||||||
|
cvar_set("physics_ode_world_damping_linear_threshold", "-1");
|
||||||
|
cvar_set("physics_ode_world_damping_angular", "-1");
|
||||||
|
cvar_set("physics_ode_world_damping_angular_threshold", "-1");
|
||||||
|
cvar_set("physics_ode_world_erp", "-1");
|
||||||
|
cvar_set("physics_ode_world_cfm", "-1");
|
||||||
|
cvar_set("physics_ode_iterationsperframe", "4");
|
||||||
|
cvar_set("physics_ode_movelimit", "0.5");
|
||||||
|
cvar_set("physics_ode_spinlimit", "10000");
|
||||||
|
cvar_set("physics_ode_autodisable", "1");
|
||||||
|
cvar_set("physics_ode_autodisable_steps", "10");
|
||||||
|
cvar_set("physics_ode_autodisable_time", "0.1");
|
||||||
|
cvar_set("physics_ode_autodisable_threshold_linear", "0.2");
|
||||||
|
cvar_set("physics_ode_autodisable_threshold_angular", "0.3");
|
||||||
|
cvar_set("physics_ode_autodisable_threshold_samples", "5");
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
m_strOnDamaged = __NULL__;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::Spawned(void)
|
||||||
|
{
|
||||||
|
super::Spawned();
|
||||||
|
|
||||||
|
/* I/O */
|
||||||
|
if (m_strOnDamaged)
|
||||||
|
m_strOnDamaged = CreateOutput(m_strOnDamaged);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::Save(float handle)
|
NSPhysicsEntity::Save(float handle)
|
||||||
{
|
{
|
||||||
|
@ -47,6 +81,7 @@ NSPhysicsEntity::Save(float handle)
|
||||||
SaveInt(handle, "m_iMaterial", m_iMaterial);
|
SaveInt(handle, "m_iMaterial", m_iMaterial);
|
||||||
SaveInt(handle, "m_iFlags", m_iFlags);
|
SaveInt(handle, "m_iFlags", m_iFlags);
|
||||||
SaveFloat(handle, "m_flInertiaScale", m_flInertiaScale);
|
SaveFloat(handle, "m_flInertiaScale", m_flInertiaScale);
|
||||||
|
SaveString(handle, "m_strOnDamaged", m_strOnDamaged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -68,6 +103,9 @@ NSPhysicsEntity::Restore(string strKey, string strValue)
|
||||||
case "m_flInertiaScale":
|
case "m_flInertiaScale":
|
||||||
m_flInertiaScale = ReadFloat(strValue);
|
m_flInertiaScale = ReadFloat(strValue);
|
||||||
break;
|
break;
|
||||||
|
case "m_strOnDamaged":
|
||||||
|
m_strOnDamaged = ReadString(strValue);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
super::Restore(strKey, strValue);
|
super::Restore(strKey, strValue);
|
||||||
}
|
}
|
||||||
|
@ -141,6 +179,7 @@ NSPhysicsEntity::EvaluateEntity(void)
|
||||||
EVALUATE_FIELD(m_flBoneControl3, RDENT_CHANGED_CONTROLLER)
|
EVALUATE_FIELD(m_flBoneControl3, RDENT_CHANGED_CONTROLLER)
|
||||||
EVALUATE_FIELD(m_flBoneControl4, RDENT_CHANGED_CONTROLLER)
|
EVALUATE_FIELD(m_flBoneControl4, RDENT_CHANGED_CONTROLLER)
|
||||||
EVALUATE_FIELD(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
EVALUATE_FIELD(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
||||||
|
EVALUATE_FIELD(mass, RDENT_CHANGED_SOLIDMOVETYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
@ -229,6 +268,9 @@ NSPhysicsEntity::SendEntity(entity ePEnt, float flChanged)
|
||||||
SENDENTITY_ANGLE(m_flBoneControl4, RDENT_CHANGED_CONTROLLER)
|
SENDENTITY_ANGLE(m_flBoneControl4, RDENT_CHANGED_CONTROLLER)
|
||||||
SENDENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
SENDENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
||||||
|
|
||||||
|
/* physics specific flags */
|
||||||
|
SENDENTITY_FLOAT(mass, RDENT_CHANGED_SOLIDMOVETYPE)
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -290,6 +332,9 @@ NSPhysicsEntity::ReceiveEntity(float flNew, float flChanged)
|
||||||
READENTITY_ANGLE(m_flBoneControl4, RDENT_CHANGED_CONTROLLER)
|
READENTITY_ANGLE(m_flBoneControl4, RDENT_CHANGED_CONTROLLER)
|
||||||
READENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
READENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
||||||
|
|
||||||
|
/* physics specific flags */
|
||||||
|
READENTITY_FLOAT(mass, RDENT_CHANGED_SOLIDMOVETYPE)
|
||||||
|
|
||||||
if (scale == 0.0)
|
if (scale == 0.0)
|
||||||
scale = 1.0f;
|
scale = 1.0f;
|
||||||
|
|
||||||
|
@ -300,47 +345,23 @@ NSPhysicsEntity::ReceiveEntity(float flNew, float flChanged)
|
||||||
|
|
||||||
movetype = MOVETYPE_NONE;
|
movetype = MOVETYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::postdraw(void)
|
||||||
|
{
|
||||||
|
if not (autocvar_r_showPhysicsInfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if not (PointMessage_Visible(WorldSpaceCenter(), g_view.GetCameraOrigin(), g_view.GetCameraAngle()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
string renderString = sprintf("Mass: %f\nEnergy: %f\nInertia:%d",
|
||||||
|
GetMass(), GetEnergy(), GetInertia());
|
||||||
|
|
||||||
|
PointMessage_StringAtPos(WorldSpaceCenter(), renderString);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::PhysicsEnable(void)
|
|
||||||
{
|
|
||||||
if (physics_supported() == TRUE) {
|
|
||||||
SetMovetype(MOVETYPE_PHYSICS);
|
|
||||||
SetSolid(SOLID_PHYSICS_BOX + m_iShape);
|
|
||||||
physics_enable(this, TRUE);
|
|
||||||
} else {
|
|
||||||
SetMovetype(MOVETYPE_BOUNCE);
|
|
||||||
SetSolid(SOLID_CORPSE);
|
|
||||||
}
|
|
||||||
m_iEnabled = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::PhysicsDisable(void)
|
|
||||||
{
|
|
||||||
if (physics_supported() == TRUE) {
|
|
||||||
physics_enable(this, FALSE);
|
|
||||||
SetMovetype(MOVETYPE_NONE);
|
|
||||||
} else {
|
|
||||||
SetMovetype(MOVETYPE_NONE);
|
|
||||||
SetSolid(SOLID_BBOX);
|
|
||||||
}
|
|
||||||
m_iEnabled = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::SetMass(float val)
|
|
||||||
{
|
|
||||||
mass = val;
|
|
||||||
}
|
|
||||||
float
|
|
||||||
NSPhysicsEntity::GetMass(void)
|
|
||||||
{
|
|
||||||
return mass;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::SetFriction(float val)
|
NSPhysicsEntity::SetFriction(float val)
|
||||||
{
|
{
|
||||||
|
@ -352,38 +373,6 @@ NSPhysicsEntity::GetFriction(void)
|
||||||
return friction;
|
return friction;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::SetBounceFactor(float val)
|
|
||||||
{
|
|
||||||
bouncefactor = val;
|
|
||||||
}
|
|
||||||
float
|
|
||||||
NSPhysicsEntity::GetBounceFactor(void)
|
|
||||||
{
|
|
||||||
return bouncefactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::SetBounceStop(float val)
|
|
||||||
{
|
|
||||||
bouncestop = val;
|
|
||||||
}
|
|
||||||
float
|
|
||||||
NSPhysicsEntity::GetBounceStop(void)
|
|
||||||
{
|
|
||||||
return bouncestop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::SetInertia(float val)
|
|
||||||
{
|
|
||||||
m_flInertiaScale = val;
|
|
||||||
}
|
|
||||||
float
|
|
||||||
NSPhysicsEntity::GetInertia(void)
|
|
||||||
{
|
|
||||||
return m_flInertiaScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
float
|
||||||
NSPhysicsEntity::CalculateImpactDamage(int iDamage, int dmgType)
|
NSPhysicsEntity::CalculateImpactDamage(int iDamage, int dmgType)
|
||||||
|
@ -403,57 +392,30 @@ NSPhysicsEntity::CalculateImpactDamage(int iDamage, int dmgType)
|
||||||
filter |= (dmgType & DMG_SLOWFREEZE);
|
filter |= (dmgType & DMG_SLOWFREEZE);
|
||||||
|
|
||||||
if (filter == 0i)
|
if (filter == 0i)
|
||||||
return (float)iDamage * 100;
|
return (float)iDamage * autocvar_phys_impactforcescale;
|
||||||
else
|
else
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
NSPhysicsEntity::ApplyForceCenter(vector vecForce)
|
NSPhysicsEntity_Contents(vector org)
|
||||||
{
|
{
|
||||||
if (physics_supported() == TRUE) {
|
int oldhitcontents = self.hitcontentsmaski;
|
||||||
physics_addforce(this, vecForce, [0,0,0]);
|
self.hitcontentsmaski = -1;
|
||||||
#ifdef ODE_MODE
|
traceline(org, org, MOVE_EVERYTHING, self);
|
||||||
//velocity += vecForce;
|
self.hitcontentsmaski = oldhitcontents;
|
||||||
|
return trace_endcontentsi;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::Touch(entity eToucher)
|
||||||
|
{
|
||||||
|
if (eToucher)
|
||||||
|
if (eToucher.movetype)
|
||||||
|
Wake();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
|
||||||
velocity += vecForce;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure touch think is called */
|
|
||||||
nextthink = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::ApplyForceOffset(vector vecForce, vector vecOffset)
|
|
||||||
{
|
|
||||||
if (physics_supported() == TRUE) {
|
|
||||||
physics_addforce(this, vecForce, vecOffset);
|
|
||||||
#ifdef ODE_MODE
|
|
||||||
//velocity += vecForce;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
velocity += vecForce;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure touch think is called */
|
|
||||||
nextthink = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::ApplyTorqueCenter(vector vecTorque)
|
|
||||||
{
|
|
||||||
if (physics_supported() == TRUE)
|
|
||||||
physics_addtorque(this, vecTorque * m_flInertiaScale);
|
|
||||||
else {
|
|
||||||
avelocity = vecTorque;
|
|
||||||
velocity = vecTorque;
|
|
||||||
velocity[2] = 96;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure touch think is called */
|
|
||||||
nextthink = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::_TouchThink(void)
|
NSPhysicsEntity::_TouchThink(void)
|
||||||
|
@ -473,21 +435,36 @@ NSPhysicsEntity::_TouchThink(void)
|
||||||
if (trace_startsolid) {
|
if (trace_startsolid) {
|
||||||
if (trace_ent.flags & FL_CLIENT) {
|
if (trace_ent.flags & FL_CLIENT) {
|
||||||
if (trace_ent.absmin[2] < absmax[2]) {
|
if (trace_ent.absmin[2] < absmax[2]) {
|
||||||
PhysicsEnable();
|
Wake();
|
||||||
makevectors(vectoangles(origin - trace_ent.origin));
|
makevectors(vectoangles(trace_endpos - trace_ent.origin));
|
||||||
ApplyTorqueCenter(v_forward * 240);
|
ApplyTorqueCenter(v_forward * 240);
|
||||||
} else {
|
} else {
|
||||||
PhysicsDisable();
|
Sleep();
|
||||||
velocity = [0,0,0];
|
velocity = [0,0,0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (m_flCheckTime < time) {
|
||||||
|
bool should
|
||||||
|
if (vlen(m_vecPrevAngles - angles) < 1) {
|
||||||
|
avelocity = [0,0,0];
|
||||||
|
}
|
||||||
|
if (vlen(m_vecPrevOrigin - origin) < 1) {
|
||||||
|
velocity = [0,0,0];
|
||||||
|
}
|
||||||
|
m_flCheckTime = time + 1.0f;
|
||||||
|
m_vecPrevOrigin = origin;
|
||||||
|
m_vecPrevAngles = angles;
|
||||||
|
}
|
||||||
|
|
||||||
/* If we barely move, disable the physics simulator */
|
/* If we barely move, disable the physics simulator */
|
||||||
if (vlen(velocity) <= 1) {
|
if (velocity == g_vec_null && avelocity == g_vec_null) {
|
||||||
if (m_iEnabled) {
|
if (m_iEnabled) {
|
||||||
PhysicsDisable();
|
NSPhysics_Log("%s is now sleeping.", classname);
|
||||||
|
Sleep();
|
||||||
velocity = [0,0,0];
|
velocity = [0,0,0];
|
||||||
avelocity = [0,0,0];
|
avelocity = [0,0,0];
|
||||||
}
|
}
|
||||||
|
@ -508,6 +485,18 @@ NSPhysicsEntity::_TouchThink(void)
|
||||||
angles = vectoangles(newangle);
|
angles = vectoangles(newangle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (m_flBuoyancyRatio > 0.0)
|
||||||
|
if (NSPhysicsEntity_Contents(origin) & CONTENTBIT_WATER) {
|
||||||
|
makevectors([0,0,0]);
|
||||||
|
velocity[2] += m_flBuoyancyRatio;
|
||||||
|
print(sprintf("in water... applying %v\n", v_up * (GetMass() * m_flBuoyancyRatio)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hitcontentsmaski &= ~CONTENTBITS_FLUID;
|
||||||
|
|
||||||
if (physics_supported() == FALSE) {
|
if (physics_supported() == FALSE) {
|
||||||
/* don't let players collide */
|
/* don't let players collide */
|
||||||
|
@ -524,18 +513,22 @@ NSPhysicsEntity::_TouchThink(void)
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::Pain(void)
|
NSPhysicsEntity::Pain(void)
|
||||||
{
|
{
|
||||||
|
vector forceDir;
|
||||||
float force;
|
float force;
|
||||||
|
|
||||||
|
if (m_strOnDamaged)
|
||||||
|
UseOutput(this, m_strOnDamaged);
|
||||||
|
|
||||||
if (m_iFlags & BPHY_NODMGPUSH)
|
if (m_iFlags & BPHY_NODMGPUSH)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PhysicsEnable();
|
Wake();
|
||||||
|
|
||||||
makevectors(vectoangles(origin - trace_endpos));
|
forceDir = normalize(GetOrigin() - g_dmg_vecLocation);
|
||||||
force = CalculateImpactDamage(g_dmg_iDamage, g_dmg_iFlags);
|
force = CalculateImpactDamage(g_dmg_iDamage, g_dmg_iFlags);
|
||||||
|
|
||||||
if (force > 0.0f)
|
if (force > 0.0f)
|
||||||
ApplyForceOffset(v_forward * force, origin - trace_endpos);
|
ApplyForceOffset(forceDir * force, g_dmg_vecLocation);
|
||||||
|
|
||||||
/* if we don't have prop data, don't consider death */
|
/* if we don't have prop data, don't consider death */
|
||||||
if (HasPropData() == false)
|
if (HasPropData() == false)
|
||||||
|
@ -564,28 +557,35 @@ NSPhysicsEntity::Death(void)
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::Respawn(void)
|
NSPhysicsEntity::Respawn(void)
|
||||||
{
|
{
|
||||||
|
ClearVelocity();
|
||||||
SetMovetype(MOVETYPE_PHYSICS);
|
SetMovetype(MOVETYPE_PHYSICS);
|
||||||
SetSolid(SOLID_PHYSICS_BOX + m_iShape);
|
SetSolid(SOLID_BSP);
|
||||||
SetModel(GetSpawnModel());
|
SetModel(GetSpawnModel());
|
||||||
|
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
SetTakedamage(DAMAGE_YES);
|
SetTakedamage(DAMAGE_YES);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ODE_MODE
|
Sleep();
|
||||||
PhysicsDisable();
|
SetMass(10.0f);
|
||||||
SetFriction(4.0f);
|
|
||||||
SetBounceFactor(0.05f);
|
|
||||||
SetMass(1.0f);
|
|
||||||
#else
|
|
||||||
PhysicsDisable();
|
|
||||||
SetMass(1.0f);
|
|
||||||
SetFriction(1.0f);
|
SetFriction(1.0f);
|
||||||
SetBounceFactor(0.1f);
|
SetBuoyancyRatio(1.0f);
|
||||||
|
bouncefactor = 0.9f;
|
||||||
|
bouncestop = 0.1f / cvar("sv_gravity");
|
||||||
|
|
||||||
|
//bouncefactor = 0.0f;
|
||||||
|
//bouncestop = 0.0f;
|
||||||
|
|
||||||
geomtype = GEOMTYPE_TRIMESH;
|
geomtype = GEOMTYPE_TRIMESH;
|
||||||
#endif
|
friction = 100.0f;
|
||||||
|
|
||||||
SetOrigin(GetSpawnOrigin());
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
m_flBuoyancyRatio = 1.0f;
|
||||||
|
|
||||||
|
SetDamping(0.0f, 0.0f);
|
||||||
|
EnableGravity(true);
|
||||||
|
|
||||||
|
hitcontentsmaski &= ~CONTENTBITS_FLUID;
|
||||||
|
|
||||||
if (physics_supported() == FALSE) {
|
if (physics_supported() == FALSE) {
|
||||||
/* don't let players collide */
|
/* don't let players collide */
|
||||||
|
@ -641,8 +641,292 @@ NSPhysicsEntity::SpawnKey(string strKey, string strValue)
|
||||||
if (tempCheck == true)
|
if (tempCheck == true)
|
||||||
m_iFlags |= BPHY_SHARP;
|
m_iFlags |= BPHY_SHARP;
|
||||||
break;
|
break;
|
||||||
|
#ifdef SERVER
|
||||||
|
case "OnDamaged":
|
||||||
|
m_strOnDamaged = PrepareOutput(m_strOnDamaged, strValue);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
super::SpawnKey(strKey, strValue);
|
super::SpawnKey(strKey, strValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GMod API starts here */
|
||||||
|
|
||||||
|
vector
|
||||||
|
NSPhysicsEntity::AlignAngles(vector from, vector to)
|
||||||
|
{
|
||||||
|
NSEntWarning("Not implemented");
|
||||||
|
return angles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::ApplyForceCenter(vector vecForce)
|
||||||
|
{
|
||||||
|
Wake();
|
||||||
|
|
||||||
|
if (physics_supported() == TRUE) {
|
||||||
|
vector finalForce = vecForce;
|
||||||
|
physics_addforce(this, finalForce, GetMassCenter());
|
||||||
|
|
||||||
|
NSPhysics_Log("%s::ApplyForceCenter: %v (val: %v)",
|
||||||
|
classname, finalForce, vecForce);
|
||||||
|
} else {
|
||||||
|
velocity += vecForce;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure touch think is called */
|
||||||
|
nextthink = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::ApplyForceOffset(vector vecForce, vector vecOffset)
|
||||||
|
{
|
||||||
|
Wake();
|
||||||
|
|
||||||
|
if (physics_supported() == TRUE) {
|
||||||
|
vector finalForce = vecForce;
|
||||||
|
physics_addforce(this, finalForce, vecOffset);
|
||||||
|
|
||||||
|
NSPhysics_Log("%s::ApplyForceOffset: %v at pos %v (val: %v)",
|
||||||
|
classname, finalForce, vecOffset, vecForce);
|
||||||
|
|
||||||
|
#ifdef ODE_MODE
|
||||||
|
//velocity += vecForce;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
velocity += vecForce;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure touch think is called */
|
||||||
|
nextthink = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::ApplyTorqueCenter(vector vecTorque)
|
||||||
|
{
|
||||||
|
Wake();
|
||||||
|
|
||||||
|
if (physics_supported() == TRUE) {
|
||||||
|
vector finalTorque = vecTorque * m_flInertiaScale;
|
||||||
|
physics_addtorque(this, finalTorque);
|
||||||
|
|
||||||
|
NSPhysics_Log("%s::ApplyTorqueCenter: %v (val: %v, scale: %f)",
|
||||||
|
classname, finalTorque, vecTorque, m_flInertiaScale);
|
||||||
|
} else {
|
||||||
|
avelocity = vecTorque;
|
||||||
|
velocity = vecTorque;
|
||||||
|
velocity[2] = 96;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure touch think is called */
|
||||||
|
nextthink = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::EnableDrag(bool setEnabled)
|
||||||
|
{
|
||||||
|
NSEntWarning("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::EnableGravity(bool setEnabled)
|
||||||
|
{
|
||||||
|
/* the engine checks if .gravity is < 0.01...) */
|
||||||
|
gravity = setEnabled ? 1.0f : 0.005;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::EnableMotion(bool setEnabled)
|
||||||
|
{
|
||||||
|
NSEntWarning("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetLinearDamping(void)
|
||||||
|
{
|
||||||
|
return damp_linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetAngularDamping(void)
|
||||||
|
{
|
||||||
|
return damp_angular;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetEnergy(void)
|
||||||
|
{
|
||||||
|
float linearEnergy;
|
||||||
|
float rotationalEnergy;
|
||||||
|
|
||||||
|
linearEnergy = (0.5f * GetMass() * vlen(GetVelocity()));
|
||||||
|
linearEnergy *= linearEnergy;
|
||||||
|
|
||||||
|
rotationalEnergy = (0.5f * GetMass() * vlen(GetAngularVelocity()));
|
||||||
|
rotationalEnergy *= rotationalEnergy;
|
||||||
|
|
||||||
|
return linearEnergy + rotationalEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetInertia(void)
|
||||||
|
{
|
||||||
|
return m_flInertiaScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetInvInertia(void)
|
||||||
|
{
|
||||||
|
return 1.0f / m_flInertiaScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetInvMass(void)
|
||||||
|
{
|
||||||
|
return 1.0f / mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetMass(void)
|
||||||
|
{
|
||||||
|
return mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector
|
||||||
|
NSPhysicsEntity::GetMassCenter(void)
|
||||||
|
{
|
||||||
|
return WorldSpaceCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetRotDamping(void)
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetSpeedDamping(void)
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetSurfaceArea(void)
|
||||||
|
{
|
||||||
|
return vlen(size) / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetVolume(void)
|
||||||
|
{
|
||||||
|
return vlen(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NSPhysicsEntity::IsAsleep(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NSPhysicsEntity::IsCollisionEnabled(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NSPhysicsEntity::IsDragEnabled(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NSPhysicsEntity::IsGravityEnabled(void)
|
||||||
|
{
|
||||||
|
return (gravity < 0.01) ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NSPhysicsEntity::IsMotionEnabled(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NSPhysicsEntity::IsMoveable(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NSPhysicsEntity::IsPenetrating(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::SetAngleDragCoefficient(float setValue)
|
||||||
|
{
|
||||||
|
NSEntWarning("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::SetBuoyancyRatio(float setValue)
|
||||||
|
{
|
||||||
|
m_flBuoyancyRatio = setValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::SetDamping(float linearDamp, float angleDamp)
|
||||||
|
{
|
||||||
|
damp_linear = linearDamp;
|
||||||
|
damp_angular = angleDamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::SetDragCoefficient(float dragValue)
|
||||||
|
{
|
||||||
|
NSEntWarning("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::SetInertia(float val)
|
||||||
|
{
|
||||||
|
m_flInertiaScale = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::SetMass(float val)
|
||||||
|
{
|
||||||
|
mass = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::Wake(void)
|
||||||
|
{
|
||||||
|
if (physics_supported() == TRUE) {
|
||||||
|
SetMovetype(MOVETYPE_PHYSICS);
|
||||||
|
SetSolid(SOLID_BSP);
|
||||||
|
physics_enable(this, TRUE);
|
||||||
|
} else {
|
||||||
|
SetMovetype(MOVETYPE_BOUNCE);
|
||||||
|
SetSolid(SOLID_CORPSE);
|
||||||
|
}
|
||||||
|
m_iEnabled = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::Sleep(void)
|
||||||
|
{
|
||||||
|
if (physics_supported() == TRUE) {
|
||||||
|
ClearVelocity();
|
||||||
|
physics_enable(this, FALSE);
|
||||||
|
SetMovetype(MOVETYPE_NONE);
|
||||||
|
} else {
|
||||||
|
SetMovetype(MOVETYPE_NONE);
|
||||||
|
SetSolid(SOLID_BBOX);
|
||||||
|
}
|
||||||
|
m_iEnabled = FALSE;
|
||||||
}
|
}
|
|
@ -87,6 +87,7 @@ string __fullspawndata;
|
||||||
#include "NSRenderableEntity.h"
|
#include "NSRenderableEntity.h"
|
||||||
#include "NSSurfacePropEntity.h"
|
#include "NSSurfacePropEntity.h"
|
||||||
#include "NSMoverEntity.h"
|
#include "NSMoverEntity.h"
|
||||||
|
#include "NSPhysicsConstraint.h"
|
||||||
#include "NSPhysicsEntity.h"
|
#include "NSPhysicsEntity.h"
|
||||||
#include "NSBrushTrigger.h"
|
#include "NSBrushTrigger.h"
|
||||||
#include "NSPointTrigger.h"
|
#include "NSPointTrigger.h"
|
||||||
|
|
|
@ -50,6 +50,7 @@ typedef enum
|
||||||
ENT_VEH_TANKMORTAR, /**< of type func_tankmortar */
|
ENT_VEH_TANKMORTAR, /**< of type func_tankmortar */
|
||||||
ENT_VEH_4WHEEL, /**< of type prop_vehicle_driveable */
|
ENT_VEH_4WHEEL, /**< of type prop_vehicle_driveable */
|
||||||
ENT_PROPROPE, /**< of type prop_rope */
|
ENT_PROPROPE, /**< of type prop_rope */
|
||||||
|
ENT_PHYSROPE, /**< of type phys_rope */
|
||||||
ENT_BUBBLES, /**< of type env_bubbles */
|
ENT_BUBBLES, /**< of type env_bubbles */
|
||||||
ENT_CONVEYOR, /**< of type func_conveyor */
|
ENT_CONVEYOR, /**< of type func_conveyor */
|
||||||
ENT_WAYPOINT, /**< of type info_waypoint */
|
ENT_WAYPOINT, /**< of type info_waypoint */
|
||||||
|
|
|
@ -7,6 +7,7 @@ NSTimer.qc
|
||||||
NSRenderableEntity.qc
|
NSRenderableEntity.qc
|
||||||
NSSurfacePropEntity.qc
|
NSSurfacePropEntity.qc
|
||||||
NSMoverEntity.qc
|
NSMoverEntity.qc
|
||||||
|
NSPhysicsConstraint.qc
|
||||||
NSPhysicsEntity.qc
|
NSPhysicsEntity.qc
|
||||||
NSBrushTrigger.qc
|
NSBrushTrigger.qc
|
||||||
NSPointTrigger.qc
|
NSPointTrigger.qc
|
||||||
|
|
Loading…
Reference in New Issue