prop_physics_multiplayer: Initial implementation. Developed with the ODE plugin in mind.
This commit is contained in:
parent
c24c8b2435
commit
8e15f04c38
14 changed files with 993 additions and 417 deletions
|
@ -32,6 +32,9 @@ Entity_EntityUpdate(float type, float new)
|
||||||
}
|
}
|
||||||
rend.ReceiveEntity(new, readfloat());
|
rend.ReceiveEntity(new, readfloat());
|
||||||
break;
|
break;
|
||||||
|
case ENT_PHYSICS:
|
||||||
|
NSPhysicsEntity_ReadEntity(new);
|
||||||
|
break;
|
||||||
case ENT_MONSTER:
|
case ENT_MONSTER:
|
||||||
NSMonster_ReadEntity(new);
|
NSMonster_ReadEntity(new);
|
||||||
self.customphysics = Empty;
|
self.customphysics = Empty;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
baseentity.h
|
baseentity.h
|
||||||
decals.h
|
decals.h
|
||||||
server/NSOutput.qc
|
server/NSOutput.qc
|
||||||
server/NSPhysicsEntity.qc
|
|
||||||
shared/NSVehicle.h
|
shared/NSVehicle.h
|
||||||
server/info_null.qc
|
server/info_null.qc
|
||||||
server/info_notnull.qc
|
server/info_notnull.qc
|
||||||
|
|
|
@ -1,362 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ODE_MODE 1
|
|
||||||
|
|
||||||
/* all the documented phys vars...*/
|
|
||||||
.float geomtype;
|
|
||||||
.float friction;
|
|
||||||
.float erp;
|
|
||||||
.float jointtype;
|
|
||||||
.float mass;
|
|
||||||
.float bouncefactor;
|
|
||||||
.float bouncestop;
|
|
||||||
|
|
||||||
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
|
|
||||||
NSPhysicsEntity::SetFriction(float val)
|
|
||||||
{
|
|
||||||
friction = val;
|
|
||||||
}
|
|
||||||
float
|
|
||||||
NSPhysicsEntity::GetFriction(void)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
NSPhysicsEntity::CalculateImpactDamage(int iDamage, int dmgType)
|
|
||||||
{
|
|
||||||
int filter = 0i;
|
|
||||||
|
|
||||||
/* if we're any of these dmg types, we don't transfer any kinetic energy */
|
|
||||||
filter |= (dmgType & DMG_BURN);
|
|
||||||
filter |= (dmgType & DMG_ELECTRO);
|
|
||||||
filter |= (dmgType & DMG_SOUND);
|
|
||||||
filter |= (dmgType & DMG_ENERGYBEAM);
|
|
||||||
filter |= (dmgType & DMG_DROWN);
|
|
||||||
filter |= (dmgType & DMG_POISON);
|
|
||||||
filter |= (dmgType & DMG_RADIATION);
|
|
||||||
filter |= (dmgType & DMG_ACID);
|
|
||||||
filter |= (dmgType & DMG_ACID);
|
|
||||||
filter |= (dmgType & DMG_SLOWFREEZE);
|
|
||||||
|
|
||||||
if (filter == 0i)
|
|
||||||
return (float)iDamage * 100;
|
|
||||||
else
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::ApplyForceCenter(vector vecForce)
|
|
||||||
{
|
|
||||||
if (physics_supported() == TRUE) {
|
|
||||||
physics_addforce(this, vecForce, [0,0,0]);
|
|
||||||
} else {
|
|
||||||
velocity = vecForce;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::ApplyForceOffset(vector vecForce, vector vecOffset)
|
|
||||||
{
|
|
||||||
if (physics_supported() == TRUE) {
|
|
||||||
physics_addforce(this, vecForce, vecOffset);
|
|
||||||
} else {
|
|
||||||
velocity = vecForce;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::ApplyTorqueCenter(vector vecTorque)
|
|
||||||
{
|
|
||||||
if (physics_supported() == TRUE)
|
|
||||||
physics_addtorque(this, vecTorque * m_flInertiaScale);
|
|
||||||
else {
|
|
||||||
avelocity = vecTorque;
|
|
||||||
velocity = vecTorque;
|
|
||||||
velocity[2] = 96;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::TouchThink(void)
|
|
||||||
{
|
|
||||||
if (!m_iEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (physics_supported() == FALSE) {
|
|
||||||
/* let players collide */
|
|
||||||
dimension_solid = 255;
|
|
||||||
dimension_hit = 255;
|
|
||||||
|
|
||||||
tracebox(origin, mins, maxs, origin, FALSE, this);
|
|
||||||
|
|
||||||
/* stuck */
|
|
||||||
if (trace_startsolid) {
|
|
||||||
if (trace_ent.flags & FL_CLIENT) {
|
|
||||||
if (trace_ent.absmin[2] < absmax[2]) {
|
|
||||||
PhysicsEnable();
|
|
||||||
makevectors(vectoangles(origin - trace_ent.origin));
|
|
||||||
ApplyTorqueCenter(v_forward * 240);
|
|
||||||
} else {
|
|
||||||
PhysicsDisable();
|
|
||||||
velocity = [0,0,0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we barely move, disable the physics simulator */
|
|
||||||
if (vlen(velocity) <= 1) {
|
|
||||||
if (m_iEnabled) {
|
|
||||||
PhysicsDisable();
|
|
||||||
velocity = [0,0,0];
|
|
||||||
avelocity = [0,0,0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (physics_supported() == FALSE) {
|
|
||||||
vector wantangle;
|
|
||||||
vector newangle;
|
|
||||||
wantangle[0] = (int)((angles[0] + 45) / 90) * 90;
|
|
||||||
wantangle[1] = angles[1];
|
|
||||||
wantangle[2] = (int)((angles[2] + 45) / 90) * 90;
|
|
||||||
|
|
||||||
makevectors(angles);
|
|
||||||
angles = v_forward;
|
|
||||||
makevectors(wantangle);
|
|
||||||
newangle[0] = Math_Lerp(angles[0], v_forward[0], frametime * 5.0f);
|
|
||||||
newangle[1] = Math_Lerp(angles[1], v_forward[1], frametime * 5.0f);
|
|
||||||
newangle[2] = Math_Lerp(angles[2], v_forward[2], frametime * 5.0f);
|
|
||||||
angles = vectoangles(newangle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (physics_supported() == FALSE) {
|
|
||||||
/* don't let players collide */
|
|
||||||
dimension_solid = 1;
|
|
||||||
dimension_hit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* continue testing next frame */
|
|
||||||
nextthink = time;
|
|
||||||
effects &= ~EF_NOSHADOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::touch(void)
|
|
||||||
{
|
|
||||||
if (trace_ent.flags & FL_CLIENT) {
|
|
||||||
if (trace_ent.absmin[2] > absmax[2]) {
|
|
||||||
velocity = [0,0,0];
|
|
||||||
PhysicsDisable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicsEnable();
|
|
||||||
makevectors(vectoangles(origin - other.origin));
|
|
||||||
ApplyForceOffset(v_forward * 100, origin - other.origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::Pain(void)
|
|
||||||
{
|
|
||||||
float force;
|
|
||||||
|
|
||||||
if (m_iFlags & BPHY_NODMGPUSH)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PhysicsEnable();
|
|
||||||
|
|
||||||
makevectors(vectoangles(origin - trace_endpos));
|
|
||||||
force = CalculateImpactDamage(g_dmg_iDamage, g_dmg_iFlags);
|
|
||||||
|
|
||||||
if (force > 0.0f)
|
|
||||||
ApplyForceOffset(v_forward * force, origin - trace_endpos);
|
|
||||||
|
|
||||||
/* if we don't have prop data, don't consider death */
|
|
||||||
if (HasPropData() == false)
|
|
||||||
health = 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::Death(void)
|
|
||||||
{
|
|
||||||
Pain();
|
|
||||||
super::Death();
|
|
||||||
|
|
||||||
if (takedamage != DAMAGE_YES) {
|
|
||||||
takedamage = (DAMAGE_YES);
|
|
||||||
}
|
|
||||||
health = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::Respawn(void)
|
|
||||||
{
|
|
||||||
SetMovetype(MOVETYPE_PHYSICS);
|
|
||||||
SetSolid(SOLID_PHYSICS_BOX + m_iShape);
|
|
||||||
SetModel(GetSpawnModel());
|
|
||||||
geomtype = GEOMTYPE_TRIMESH;
|
|
||||||
takedamage = DAMAGE_YES;
|
|
||||||
|
|
||||||
#ifndef ODE_MODE
|
|
||||||
PhysicsDisable();
|
|
||||||
SetFriction(4.0f);
|
|
||||||
SetBounceFactor(0.05f);
|
|
||||||
SetMass(1.0f);
|
|
||||||
#else
|
|
||||||
PhysicsDisable();
|
|
||||||
SetMass(1.0f);
|
|
||||||
SetFriction(1.0f);
|
|
||||||
SetBounceFactor(0.1f);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetOrigin(GetSpawnOrigin());
|
|
||||||
|
|
||||||
if (physics_supported() == FALSE) {
|
|
||||||
/* don't let players collide */
|
|
||||||
dimension_solid = 1;
|
|
||||||
dimension_hit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
think = TouchThink;
|
|
||||||
nextthink = time + 0.1f;
|
|
||||||
|
|
||||||
effects &= ~EF_NOSHADOW;
|
|
||||||
|
|
||||||
if (HasPropData()) {
|
|
||||||
health = GetPropData(PROPINFO_HEALTH);
|
|
||||||
} else {
|
|
||||||
health = 100000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::SpawnKey(string strKey, string strValue)
|
|
||||||
{
|
|
||||||
switch (strKey) {
|
|
||||||
case "physmodel":
|
|
||||||
m_iShape = stoi(strValue);
|
|
||||||
if (m_iShape > PHYSM_CYLINDER)
|
|
||||||
m_iShape = 0;
|
|
||||||
break;
|
|
||||||
case "massscale":
|
|
||||||
mass = stof(strValue);
|
|
||||||
break;
|
|
||||||
case "inertiascale":
|
|
||||||
m_flInertiaScale = stof(strValue);
|
|
||||||
break;
|
|
||||||
case "physdamagescale":
|
|
||||||
break;
|
|
||||||
case "material":
|
|
||||||
m_iMaterial = stof(strValue);
|
|
||||||
break;
|
|
||||||
case "nodamageforces":
|
|
||||||
if (strValue == "1")
|
|
||||||
m_iFlags |= BPHY_NODMGPUSH;
|
|
||||||
break;
|
|
||||||
case "Damagetype":
|
|
||||||
if (strValue == "1")
|
|
||||||
m_iFlags |= BPHY_SHARP;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
super::SpawnKey(strKey, strValue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NSPhysicsEntity::NSPhysicsEntity(void)
|
|
||||||
{
|
|
||||||
mass = 1.0f;
|
|
||||||
m_flInertiaScale = 1.0f;
|
|
||||||
super::NSSurfacePropEntity();
|
|
||||||
|
|
||||||
cvar_set("physics_ode_iterationsperframe", "1");
|
|
||||||
cvar_set("physics_ode_movelimit", "0.1");
|
|
||||||
}
|
|
|
@ -16,48 +16,10 @@
|
||||||
|
|
||||||
#include "../shared/baseentity.h"
|
#include "../shared/baseentity.h"
|
||||||
#include "NSOutput.h"
|
#include "NSOutput.h"
|
||||||
#include "NSPhysicsEntity.h"
|
|
||||||
|
|
||||||
void FX_Spark(vector, vector);
|
void FX_Spark(vector, vector);
|
||||||
void FX_BreakModel(int, vector, vector, vector, float);
|
void FX_BreakModel(int, vector, vector, vector, float);
|
||||||
|
|
||||||
/* This is required because people who use Hammer do awful things
|
|
||||||
to get their models to update. We get a multitude of juicy
|
|
||||||
hacks and symbols that Half-Life's engine strips and now we have to
|
|
||||||
replicate this behaviour. Be thankful this is not done in-engine for
|
|
||||||
every game/mod ever.
|
|
||||||
*/
|
|
||||||
string Util_FixModel(string mdl)
|
|
||||||
{
|
|
||||||
if (!mdl) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
int c = tokenizebyseparator(mdl, "/", "\\ ", "!");
|
|
||||||
string newpath = "";
|
|
||||||
|
|
||||||
for (int i = 0; i < c; i++) {
|
|
||||||
newpath = sprintf("%s/%s", newpath, argv(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Kill the first / */
|
|
||||||
newpath = substring(newpath, 1, strlen(newpath)-1);
|
|
||||||
|
|
||||||
/* Now we need to fix \/ because I hate people */
|
|
||||||
c = tokenizebyseparator(newpath, "\\/");
|
|
||||||
mdl = "";
|
|
||||||
for (int i = 0; i < c; i++) {
|
|
||||||
mdl = sprintf("%s/%s", mdl, argv(i));
|
|
||||||
}
|
|
||||||
/* Kill the first / again */
|
|
||||||
mdl = substring(mdl, 1, strlen(mdl)-1);
|
|
||||||
|
|
||||||
if (substring(mdl, 0, 1) == "/")
|
|
||||||
mdl = substring(mdl, 1, -1);
|
|
||||||
|
|
||||||
return mdl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Backwards compat */
|
/* Backwards compat */
|
||||||
class CBaseMonster:NSMonster
|
class CBaseMonster:NSMonster
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,7 @@ shared/NSTrigger.qc
|
||||||
shared/NSEntity.qc
|
shared/NSEntity.qc
|
||||||
shared/NSRenderableEntity.qc
|
shared/NSRenderableEntity.qc
|
||||||
shared/NSSurfacePropEntity.qc
|
shared/NSSurfacePropEntity.qc
|
||||||
|
shared/NSPhysicsEntity.qc
|
||||||
shared/NSBrushTrigger.qc
|
shared/NSBrushTrigger.qc
|
||||||
shared/NSPointTrigger.qc
|
shared/NSPointTrigger.qc
|
||||||
shared/NSVehicle.qc
|
shared/NSVehicle.qc
|
||||||
|
@ -28,6 +29,7 @@ shared/func_tankmortar.qc
|
||||||
shared/trigger_camera.qc
|
shared/trigger_camera.qc
|
||||||
shared/trigger_gravity.qc
|
shared/trigger_gravity.qc
|
||||||
shared/info_particle_system.qc
|
shared/info_particle_system.qc
|
||||||
|
shared/prop_physics_multiplayer.qc
|
||||||
shared/prop_vehicle_driveable.qc
|
shared/prop_vehicle_driveable.qc
|
||||||
shared/prop_rope.qc
|
shared/prop_rope.qc
|
||||||
shared/worldspawn.qc
|
shared/worldspawn.qc
|
||||||
|
|
|
@ -26,6 +26,11 @@ class NSEntity:NSTrigger
|
||||||
vector m_vecMins;
|
vector m_vecMins;
|
||||||
vector m_vecMaxs;
|
vector m_vecMaxs;
|
||||||
|
|
||||||
|
/* important spawn values */
|
||||||
|
vector m_oldOrigin;
|
||||||
|
vector m_oldAngle;
|
||||||
|
string m_oldModel;
|
||||||
|
|
||||||
/* keep track of these variables */
|
/* keep track of these variables */
|
||||||
PREDICTED_VECTOR_N(origin);
|
PREDICTED_VECTOR_N(origin);
|
||||||
PREDICTED_VECTOR_N(angles);
|
PREDICTED_VECTOR_N(angles);
|
||||||
|
@ -61,9 +66,6 @@ class NSEntity:NSTrigger
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
/* respawn */
|
/* respawn */
|
||||||
float m_oldSolid;
|
float m_oldSolid;
|
||||||
vector m_oldOrigin;
|
|
||||||
vector m_oldAngle;
|
|
||||||
string m_oldModel;
|
|
||||||
|
|
||||||
string m_parent;
|
string m_parent;
|
||||||
string m_parent_attachment;
|
string m_parent_attachment;
|
||||||
|
@ -82,10 +84,6 @@ class NSEntity:NSTrigger
|
||||||
/* some ents need this */
|
/* some ents need this */
|
||||||
nonvirtual void(void) RestoreAngles;
|
nonvirtual void(void) RestoreAngles;
|
||||||
nonvirtual void(void) ClearAngles;
|
nonvirtual void(void) ClearAngles;
|
||||||
|
|
||||||
nonvirtual vector(void) GetSpawnOrigin;
|
|
||||||
nonvirtual vector(void) GetSpawnAngles;
|
|
||||||
nonvirtual string(void) GetSpawnModel;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* sets */
|
/* sets */
|
||||||
|
@ -106,6 +104,10 @@ class NSEntity:NSTrigger
|
||||||
virtual void(float) AddFlags;
|
virtual void(float) AddFlags;
|
||||||
virtual void(float) RemoveFlags;
|
virtual void(float) RemoveFlags;
|
||||||
/* gets */
|
/* gets */
|
||||||
|
nonvirtual vector(void) GetSpawnOrigin;
|
||||||
|
nonvirtual vector(void) GetSpawnAngles;
|
||||||
|
nonvirtual string(void) GetSpawnModel;
|
||||||
|
|
||||||
virtual float(void) GetScale;
|
virtual float(void) GetScale;
|
||||||
virtual entity(void) GetOwner;
|
virtual entity(void) GetOwner;
|
||||||
virtual vector(void) GetVelocity;
|
virtual vector(void) GetVelocity;
|
||||||
|
|
|
@ -773,7 +773,6 @@ NSEntity::GetFlags(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SERVER
|
|
||||||
vector
|
vector
|
||||||
NSEntity::GetSpawnOrigin(void)
|
NSEntity::GetSpawnOrigin(void)
|
||||||
{
|
{
|
||||||
|
@ -790,6 +789,7 @@ NSEntity::GetSpawnModel(void)
|
||||||
return m_oldModel;
|
return m_oldModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
void
|
void
|
||||||
NSEntity::Respawn(void)
|
NSEntity::Respawn(void)
|
||||||
{
|
{
|
||||||
|
@ -1026,10 +1026,7 @@ NSEntity::NSEntity(void)
|
||||||
|
|
||||||
super::NSTrigger();
|
super::NSTrigger();
|
||||||
|
|
||||||
m_oldAngle = angles;
|
|
||||||
m_oldOrigin = origin;
|
|
||||||
m_oldSolid = solid;
|
m_oldSolid = solid;
|
||||||
m_oldModel = Util_FixModel(model);
|
|
||||||
blocked = BlockedHandler;
|
blocked = BlockedHandler;
|
||||||
touch = TouchHandler;
|
touch = TouchHandler;
|
||||||
|
|
||||||
|
@ -1044,4 +1041,8 @@ NSEntity::NSEntity(void)
|
||||||
#else
|
#else
|
||||||
isCSQC = 1;
|
isCSQC = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_oldAngle = angles;
|
||||||
|
m_oldOrigin = origin;
|
||||||
|
m_oldModel = Util_FixModel(model);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,35 @@ enumflags
|
||||||
BPHY_SHARP
|
BPHY_SHARP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enumflags
|
||||||
|
{
|
||||||
|
PHYENT_CHANGED_ORIGIN_X,
|
||||||
|
PHYENT_CHANGED_ORIGIN_Y,
|
||||||
|
PHYENT_CHANGED_ORIGIN_Z,
|
||||||
|
PHYENT_CHANGED_ANGLES_X,
|
||||||
|
PHYENT_CHANGED_ANGLES_Y,
|
||||||
|
PHYENT_CHANGED_ANGLES_Z,
|
||||||
|
PHYENT_CHANGED_MODELINDEX,
|
||||||
|
PHYENT_CHANGED_SIZE,
|
||||||
|
PHYENT_CHANGED_FLAGS,
|
||||||
|
PHYENT_CHANGED_SOLID,
|
||||||
|
PHYENT_CHANGED_FRAME,
|
||||||
|
PHYENT_CHANGED_SKIN,
|
||||||
|
PHYENT_CHANGED_MOVETYPE,
|
||||||
|
PHYENT_CHANGED_EFFECTS,
|
||||||
|
PHYENT_CHANGED_BODY,
|
||||||
|
PHYENT_CHANGED_SCALE,
|
||||||
|
PHYENT_CHANGED_VELOCITY,
|
||||||
|
#ifdef GS_RENDERFX
|
||||||
|
PHYENT_CHANGED_RENDERCOLOR,
|
||||||
|
PHYENT_CHANGED_RENDERAMT,
|
||||||
|
PHYENT_CHANGED_RENDERMODE,
|
||||||
|
#else
|
||||||
|
PHYENT_CHANGED_ALPHA,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
class NSPhysicsEntity:NSSurfacePropEntity
|
class NSPhysicsEntity:NSSurfacePropEntity
|
||||||
{
|
{
|
||||||
int m_iEnabled;
|
int m_iEnabled;
|
||||||
|
@ -41,10 +70,17 @@ class NSPhysicsEntity:NSSurfacePropEntity
|
||||||
|
|
||||||
/* overrides */
|
/* overrides */
|
||||||
virtual void(void) Respawn;
|
virtual void(void) Respawn;
|
||||||
virtual void(void) touch;
|
|
||||||
virtual void(void) TouchThink;
|
virtual void(void) TouchThink;
|
||||||
|
#ifdef SERVER
|
||||||
|
PREDICTED_VECTOR(m_vecNetAngles);
|
||||||
|
|
||||||
virtual void(void) Pain;
|
virtual void(void) Pain;
|
||||||
virtual void(void) Death;
|
virtual void(void) Death;
|
||||||
|
virtual void(void) EvaluateEntity;
|
||||||
|
virtual float(entity, float) SendEntity;
|
||||||
|
#else
|
||||||
|
virtual void(float, float) ReceiveEntity;
|
||||||
|
#endif
|
||||||
virtual void(string, string) SpawnKey;
|
virtual void(string, string) SpawnKey;
|
||||||
|
|
||||||
virtual void(float) SetMass;
|
virtual void(float) SetMass;
|
739
src/gs-entbase/shared/NSPhysicsEntity.qc
Normal file
739
src/gs-entbase/shared/NSPhysicsEntity.qc
Normal file
|
@ -0,0 +1,739 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ODE_MODE 1
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
bool physics_supported(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* all the documented phys vars...*/
|
||||||
|
.float geomtype;
|
||||||
|
.float friction;
|
||||||
|
.float erp;
|
||||||
|
.float jointtype;
|
||||||
|
.float mass;
|
||||||
|
.float bouncefactor;
|
||||||
|
.float bouncestop;
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::EvaluateEntity(void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
origin[0] = rint(origin[0]);
|
||||||
|
origin[1] = rint(origin[1]);
|
||||||
|
origin[2] = rint(origin[2]);
|
||||||
|
angles[0] = rint(angles[0]);
|
||||||
|
angles[1] = rint(angles[1]);
|
||||||
|
angles[2] = rint(angles[2]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (origin_x != origin_net_x) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_ORIGIN_X);
|
||||||
|
}
|
||||||
|
if (origin_y != origin_net_y) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_ORIGIN_Y);
|
||||||
|
}
|
||||||
|
if (origin_z != origin_net_z) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_ORIGIN_Z);
|
||||||
|
}
|
||||||
|
if (angles_x != angles_net_x) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_ANGLES_X);
|
||||||
|
}
|
||||||
|
if (angles_y != angles_net_y) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_ANGLES_Y);
|
||||||
|
}
|
||||||
|
if (angles_z != angles_net_z) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_ANGLES_Z);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(modelindex)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_MODELINDEX);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(solid)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_SOLID);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(movetype)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_MOVETYPE);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(size)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_SIZE);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(frame)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_FRAME);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(skin)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_SKIN);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(effects)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_EFFECTS);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(m_iBody)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_BODY);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(scale)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_SCALE);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(velocity)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_VELOCITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAVE_STATE(origin);
|
||||||
|
SAVE_STATE(angles);
|
||||||
|
SAVE_STATE(modelindex);
|
||||||
|
SAVE_STATE(solid);
|
||||||
|
SAVE_STATE(movetype);
|
||||||
|
SAVE_STATE(size);
|
||||||
|
SAVE_STATE(frame);
|
||||||
|
SAVE_STATE(skin);
|
||||||
|
SAVE_STATE(effects);
|
||||||
|
SAVE_STATE(m_iBody);
|
||||||
|
SAVE_STATE(scale);
|
||||||
|
SAVE_STATE(velocity);
|
||||||
|
|
||||||
|
#ifdef GS_RENDERFX
|
||||||
|
if (ATTR_CHANGED(m_iRenderMode)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_RENDERMODE);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(m_iRenderFX)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_RENDERMODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ATTR_CHANGED(m_vecRenderColor)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_RENDERCOLOR);
|
||||||
|
}
|
||||||
|
if (ATTR_CHANGED(m_flRenderAmt)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_RENDERAMT);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (ATTR_CHANGED(alpha)) {
|
||||||
|
SetSendFlags(PHYENT_CHANGED_ALPHA);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::SendEntity(entity ePEnt, float fChanged)
|
||||||
|
{
|
||||||
|
if (!modelindex)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
if (clienttype(ePEnt) != CLIENTTYPE_REAL)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
WriteByte(MSG_ENTITY, ENT_PHYSICS);
|
||||||
|
|
||||||
|
/* newly popped into the PVS, sadly this is the only hacky way to check
|
||||||
|
* for this right now. convince the engine maintainer to make this more sensible */
|
||||||
|
if (fChanged == 0xFFFFFF) {
|
||||||
|
/* check for defaults. if these are predictable fields, don't even bother
|
||||||
|
* networking them! you're just wasting bandwidth. */
|
||||||
|
if (frame == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_FRAME;
|
||||||
|
if (skin == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_SKIN;
|
||||||
|
if (effects == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_EFFECTS;
|
||||||
|
if (m_iBody == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_BODY;
|
||||||
|
if (scale == 0.0 || scale == 1.0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_SCALE;
|
||||||
|
if (origin[0] == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_ORIGIN_X;
|
||||||
|
if (origin[1] == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_ORIGIN_Y;
|
||||||
|
if (origin[2] == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_ORIGIN_Z;
|
||||||
|
if (angles[0] == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_ANGLES_X;
|
||||||
|
if (angles[1] == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_ANGLES_Y;
|
||||||
|
if (angles[2] == 0)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_ANGLES_Z;
|
||||||
|
if (velocity == [0,0,0])
|
||||||
|
fChanged &= ~PHYENT_CHANGED_VELOCITY;
|
||||||
|
if (mins == [0,0,0] && maxs == [0,0,0])
|
||||||
|
fChanged &= ~PHYENT_CHANGED_SIZE;
|
||||||
|
if (solid == SOLID_NOT)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_SOLID;
|
||||||
|
if (movetype == MOVETYPE_NONE)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_MOVETYPE;
|
||||||
|
#ifdef GS_RENDERFX
|
||||||
|
if (m_iRenderMode == RM_NORMAL)
|
||||||
|
fChanged &= ~PHYENT_CHANGED_RENDERMODE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* broadcast how much data is expected to be read */
|
||||||
|
WriteFloat(MSG_ENTITY, fChanged);
|
||||||
|
|
||||||
|
/* really trying to get our moneys worth with 23 bits of mantissa */
|
||||||
|
if (fChanged & PHYENT_CHANGED_ORIGIN_X) {
|
||||||
|
WriteCoord(MSG_ENTITY, origin[0]);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_ORIGIN_Y) {
|
||||||
|
WriteCoord(MSG_ENTITY, origin[1]);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_ORIGIN_Z) {
|
||||||
|
WriteCoord(MSG_ENTITY, origin[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fChanged & PHYENT_CHANGED_ANGLES_X) {
|
||||||
|
WriteShort(MSG_ENTITY, angles[0] * 32767 / 360);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_ANGLES_Y) {
|
||||||
|
WriteShort(MSG_ENTITY, angles[1] * 32767 / 360);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_ANGLES_Z) {
|
||||||
|
WriteShort(MSG_ENTITY, angles[2] * 32767 / 360);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_MODELINDEX) {
|
||||||
|
WriteShort(MSG_ENTITY, modelindex);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_SOLID) {
|
||||||
|
WriteByte(MSG_ENTITY, solid);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_MOVETYPE) {
|
||||||
|
WriteByte(MSG_ENTITY, movetype);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_SIZE) {
|
||||||
|
WriteCoord(MSG_ENTITY, mins[0]);
|
||||||
|
WriteCoord(MSG_ENTITY, mins[1]);
|
||||||
|
WriteCoord(MSG_ENTITY, mins[2]);
|
||||||
|
WriteCoord(MSG_ENTITY, maxs[0]);
|
||||||
|
WriteCoord(MSG_ENTITY, maxs[1]);
|
||||||
|
WriteCoord(MSG_ENTITY, maxs[2]);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_FRAME) {
|
||||||
|
WriteByte(MSG_ENTITY, frame);
|
||||||
|
WriteByte(MSG_ENTITY, frame1time);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_SKIN) {
|
||||||
|
WriteByte(MSG_ENTITY, skin + 128);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_EFFECTS) {
|
||||||
|
WriteFloat(MSG_ENTITY, effects);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_BODY) {
|
||||||
|
WriteByte(MSG_ENTITY, m_iBody);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_SCALE) {
|
||||||
|
WriteFloat(MSG_ENTITY, scale);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_VELOCITY) {
|
||||||
|
WriteFloat(MSG_ENTITY, velocity[0]);
|
||||||
|
WriteFloat(MSG_ENTITY, velocity[1]);
|
||||||
|
WriteFloat(MSG_ENTITY, velocity[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GS_RENDERFX
|
||||||
|
if (fChanged & PHYENT_CHANGED_RENDERMODE) {
|
||||||
|
WriteByte(MSG_ENTITY, m_iRenderMode);
|
||||||
|
WriteByte(MSG_ENTITY, m_iRenderFX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fChanged & PHYENT_CHANGED_RENDERCOLOR) {
|
||||||
|
WriteFloat(MSG_ENTITY, m_vecRenderColor[0]);
|
||||||
|
WriteFloat(MSG_ENTITY, m_vecRenderColor[1]);
|
||||||
|
WriteFloat(MSG_ENTITY, m_vecRenderColor[2]);
|
||||||
|
WriteFloat(MSG_ENTITY, glowmod[0]);
|
||||||
|
WriteFloat(MSG_ENTITY, glowmod[1]);
|
||||||
|
WriteFloat(MSG_ENTITY, glowmod[2]);
|
||||||
|
}
|
||||||
|
if (fChanged & PHYENT_CHANGED_RENDERAMT) {
|
||||||
|
WriteFloat(MSG_ENTITY, m_flRenderAmt);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (fChanged & PHYENT_CHANGED_ALPHA) {
|
||||||
|
WriteFloat(MSG_ENTITY, alpha);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
NSPhysicsEntity::ReceiveEntity
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::ReceiveEntity(float flNew, float flChanged)
|
||||||
|
{
|
||||||
|
if (flChanged & PHYENT_CHANGED_ORIGIN_X) {
|
||||||
|
origin[0] = readcoord();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_ORIGIN_Y) {
|
||||||
|
origin[1] = readcoord();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_ORIGIN_Z) {
|
||||||
|
origin[2] = readcoord();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_ANGLES_X) {
|
||||||
|
angles[0] = readshort() / (32767 / 360);
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_ANGLES_Y) {
|
||||||
|
angles[1] = readshort() / (32767 / 360);
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_ANGLES_Z) {
|
||||||
|
angles[2] = readshort() / (32767 / 360);
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_MODELINDEX) {
|
||||||
|
setmodelindex(this, readshort());
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_SOLID) {
|
||||||
|
solid = readbyte();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_MOVETYPE) {
|
||||||
|
movetype = readbyte();
|
||||||
|
|
||||||
|
if (movetype == MOVETYPE_PHYSICS) {
|
||||||
|
movetype = MOVETYPE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_SIZE) {
|
||||||
|
mins[0] = readcoord();
|
||||||
|
mins[1] = readcoord();
|
||||||
|
mins[2] = readcoord();
|
||||||
|
maxs[0] = readcoord();
|
||||||
|
maxs[1] = readcoord();
|
||||||
|
maxs[2] = readcoord();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_FRAME) {
|
||||||
|
frame = readbyte();
|
||||||
|
frame1time =
|
||||||
|
frame2time = readbyte();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_SKIN) {
|
||||||
|
skin = readbyte() - 128;
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_EFFECTS) {
|
||||||
|
effects = readfloat();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_BODY) {
|
||||||
|
m_iBody = readbyte();
|
||||||
|
setcustomskin(this, "", sprintf("geomset 0 %i\ngeomset 1 %i\n", m_iBody, m_iBody));
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_SCALE) {
|
||||||
|
scale = readfloat();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_VELOCITY) {
|
||||||
|
velocity[0] = readfloat();
|
||||||
|
velocity[1] = readfloat();
|
||||||
|
velocity[2] = readfloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GS_RENDERFX
|
||||||
|
if (flChanged & PHYENT_CHANGED_RENDERMODE) {
|
||||||
|
m_iRenderMode = readbyte();
|
||||||
|
m_iRenderFX = readbyte();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_RENDERCOLOR) {
|
||||||
|
m_vecRenderColor[0] = readfloat();
|
||||||
|
m_vecRenderColor[1] = readfloat();
|
||||||
|
m_vecRenderColor[2] = readfloat();
|
||||||
|
glowmod[0] = readfloat();
|
||||||
|
glowmod[1] = readfloat();
|
||||||
|
glowmod[2] = readfloat();
|
||||||
|
}
|
||||||
|
if (flChanged & PHYENT_CHANGED_RENDERAMT) {
|
||||||
|
m_flRenderAmt = readfloat();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (flChanged & PHYENT_CHANGED_ALPHA) {
|
||||||
|
alpha = readfloat();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (modelindex) {
|
||||||
|
drawmask = MASK_ENGINE;
|
||||||
|
} else {
|
||||||
|
drawmask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale == 0.0)
|
||||||
|
scale = 1.0f;
|
||||||
|
|
||||||
|
if (flChanged & PHYENT_CHANGED_SIZE)
|
||||||
|
setsize(this, mins * scale, maxs * scale);
|
||||||
|
|
||||||
|
setorigin(this, origin);
|
||||||
|
}
|
||||||
|
#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
|
||||||
|
NSPhysicsEntity::SetFriction(float val)
|
||||||
|
{
|
||||||
|
friction = val;
|
||||||
|
}
|
||||||
|
float
|
||||||
|
NSPhysicsEntity::GetFriction(void)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
NSPhysicsEntity::CalculateImpactDamage(int iDamage, int dmgType)
|
||||||
|
{
|
||||||
|
int filter = 0i;
|
||||||
|
|
||||||
|
/* if we're any of these dmg types, we don't transfer any kinetic energy */
|
||||||
|
filter |= (dmgType & DMG_BURN);
|
||||||
|
filter |= (dmgType & DMG_ELECTRO);
|
||||||
|
filter |= (dmgType & DMG_SOUND);
|
||||||
|
filter |= (dmgType & DMG_ENERGYBEAM);
|
||||||
|
filter |= (dmgType & DMG_DROWN);
|
||||||
|
filter |= (dmgType & DMG_POISON);
|
||||||
|
filter |= (dmgType & DMG_RADIATION);
|
||||||
|
filter |= (dmgType & DMG_ACID);
|
||||||
|
filter |= (dmgType & DMG_ACID);
|
||||||
|
filter |= (dmgType & DMG_SLOWFREEZE);
|
||||||
|
|
||||||
|
if (filter == 0i)
|
||||||
|
return (float)iDamage * 100;
|
||||||
|
else
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::ApplyForceCenter(vector vecForce)
|
||||||
|
{
|
||||||
|
if (physics_supported() == TRUE) {
|
||||||
|
physics_addforce(this, vecForce, [0,0,0]);
|
||||||
|
} 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);
|
||||||
|
} 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
|
||||||
|
NSPhysicsEntity::TouchThink(void)
|
||||||
|
{
|
||||||
|
if (!m_iEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physics_supported() == FALSE) {
|
||||||
|
/* let players collide */
|
||||||
|
dimension_solid = 255;
|
||||||
|
dimension_hit = 255;
|
||||||
|
|
||||||
|
tracebox(origin, mins, maxs, origin, FALSE, this);
|
||||||
|
|
||||||
|
/* stuck */
|
||||||
|
if (trace_startsolid) {
|
||||||
|
if (trace_ent.flags & FL_CLIENT) {
|
||||||
|
if (trace_ent.absmin[2] < absmax[2]) {
|
||||||
|
PhysicsEnable();
|
||||||
|
makevectors(vectoangles(origin - trace_ent.origin));
|
||||||
|
ApplyTorqueCenter(v_forward * 240);
|
||||||
|
} else {
|
||||||
|
PhysicsDisable();
|
||||||
|
velocity = [0,0,0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we barely move, disable the physics simulator */
|
||||||
|
if (vlen(velocity) <= 1) {
|
||||||
|
if (m_iEnabled) {
|
||||||
|
PhysicsDisable();
|
||||||
|
velocity = [0,0,0];
|
||||||
|
avelocity = [0,0,0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physics_supported() == FALSE) {
|
||||||
|
vector wantangle;
|
||||||
|
vector newangle;
|
||||||
|
wantangle[0] = (int)((angles[0] + 45) / 90) * 90;
|
||||||
|
wantangle[1] = angles[1];
|
||||||
|
wantangle[2] = (int)((angles[2] + 45) / 90) * 90;
|
||||||
|
|
||||||
|
makevectors(angles);
|
||||||
|
angles = v_forward;
|
||||||
|
makevectors(wantangle);
|
||||||
|
newangle[0] = Math_Lerp(angles[0], v_forward[0], frametime * 5.0f);
|
||||||
|
newangle[1] = Math_Lerp(angles[1], v_forward[1], frametime * 5.0f);
|
||||||
|
newangle[2] = Math_Lerp(angles[2], v_forward[2], frametime * 5.0f);
|
||||||
|
angles = vectoangles(newangle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physics_supported() == FALSE) {
|
||||||
|
/* don't let players collide */
|
||||||
|
dimension_solid = 1;
|
||||||
|
dimension_hit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* continue testing next frame */
|
||||||
|
nextthink = time;
|
||||||
|
effects &= ~EF_NOSHADOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::Pain(void)
|
||||||
|
{
|
||||||
|
float force;
|
||||||
|
|
||||||
|
if (m_iFlags & BPHY_NODMGPUSH)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PhysicsEnable();
|
||||||
|
|
||||||
|
makevectors(vectoangles(origin - trace_endpos));
|
||||||
|
force = CalculateImpactDamage(g_dmg_iDamage, g_dmg_iFlags);
|
||||||
|
|
||||||
|
if (force > 0.0f)
|
||||||
|
ApplyForceOffset(v_forward * force, origin - trace_endpos);
|
||||||
|
|
||||||
|
/* if we don't have prop data, don't consider death */
|
||||||
|
if (HasPropData() == false)
|
||||||
|
health = 10000;
|
||||||
|
|
||||||
|
/* make sure touch think is called */
|
||||||
|
nextthink = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::Death(void)
|
||||||
|
{
|
||||||
|
Pain();
|
||||||
|
super::Death();
|
||||||
|
|
||||||
|
if (takedamage != DAMAGE_YES) {
|
||||||
|
takedamage = (DAMAGE_YES);
|
||||||
|
}
|
||||||
|
health = 1000;
|
||||||
|
|
||||||
|
/* make sure touch think is called */
|
||||||
|
nextthink = time;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::Respawn(void)
|
||||||
|
{
|
||||||
|
SetMovetype(MOVETYPE_PHYSICS);
|
||||||
|
SetSolid(SOLID_PHYSICS_BOX + m_iShape);
|
||||||
|
SetModel(GetSpawnModel());
|
||||||
|
geomtype = GEOMTYPE_TRIMESH;
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
SetTakedamage(DAMAGE_YES);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ODE_MODE
|
||||||
|
PhysicsDisable();
|
||||||
|
SetFriction(4.0f);
|
||||||
|
SetBounceFactor(0.05f);
|
||||||
|
SetMass(1.0f);
|
||||||
|
#else
|
||||||
|
PhysicsDisable();
|
||||||
|
SetMass(1.0f);
|
||||||
|
SetFriction(1.0f);
|
||||||
|
SetBounceFactor(0.1f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SetOrigin(GetSpawnOrigin());
|
||||||
|
|
||||||
|
if (physics_supported() == FALSE) {
|
||||||
|
/* don't let players collide */
|
||||||
|
dimension_solid = 1;
|
||||||
|
dimension_hit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
think = TouchThink;
|
||||||
|
nextthink = time + 0.1f;
|
||||||
|
|
||||||
|
effects &= ~EF_NOSHADOW;
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
if (HasPropData()) {
|
||||||
|
health = GetPropData(PROPINFO_HEALTH);
|
||||||
|
} else {
|
||||||
|
health = 100000;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::SpawnKey(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "physmodel":
|
||||||
|
m_iShape = stoi(strValue);
|
||||||
|
if (m_iShape > PHYSM_CYLINDER)
|
||||||
|
m_iShape = 0;
|
||||||
|
break;
|
||||||
|
case "massscale":
|
||||||
|
mass = stof(strValue);
|
||||||
|
break;
|
||||||
|
case "inertiascale":
|
||||||
|
m_flInertiaScale = stof(strValue);
|
||||||
|
break;
|
||||||
|
case "physdamagescale":
|
||||||
|
break;
|
||||||
|
case "material":
|
||||||
|
m_iMaterial = stof(strValue);
|
||||||
|
break;
|
||||||
|
case "nodamageforces":
|
||||||
|
if (strValue == "1")
|
||||||
|
m_iFlags |= BPHY_NODMGPUSH;
|
||||||
|
break;
|
||||||
|
case "Damagetype":
|
||||||
|
if (strValue == "1")
|
||||||
|
m_iFlags |= BPHY_SHARP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super::SpawnKey(strKey, strValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::NSPhysicsEntity(void)
|
||||||
|
{
|
||||||
|
mass = 1.0f;
|
||||||
|
m_flInertiaScale = 1.0f;
|
||||||
|
super::NSSurfacePropEntity();
|
||||||
|
|
||||||
|
cvar_set("physics_ode_iterationsperframe", "1");
|
||||||
|
cvar_set("physics_ode_movelimit", "0.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
void
|
||||||
|
NSPhysicsEntity_ReadEntity(bool new)
|
||||||
|
{
|
||||||
|
float fl;
|
||||||
|
NSPhysicsEntity rend = (NSPhysicsEntity)self;
|
||||||
|
if (new) {
|
||||||
|
spawnfunc_NSPhysicsEntity();
|
||||||
|
}
|
||||||
|
fl = readfloat();
|
||||||
|
rend.ReceiveEntity(new, fl);
|
||||||
|
|
||||||
|
//print(sprintf("physics ent update: %d %x %d %v\n", self.entnum, fl, self.origin, vlen(self.velocity)));
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -181,9 +181,6 @@ NSRenderableEntity::SendEntity(entity ePEnt, float fChanged)
|
||||||
WriteCoord(MSG_ENTITY, origin[2]);
|
WriteCoord(MSG_ENTITY, origin[2]);
|
||||||
}
|
}
|
||||||
if (fChanged & BASEFL_CHANGED_ANGLES) {
|
if (fChanged & BASEFL_CHANGED_ANGLES) {
|
||||||
/* fix angles and try to avoid a net update next frame */
|
|
||||||
angles = Math_FixDeltaVector(angles);
|
|
||||||
angles_net = angles;
|
|
||||||
WriteShort(MSG_ENTITY, angles[0] * 32767 / 360);
|
WriteShort(MSG_ENTITY, angles[0] * 32767 / 360);
|
||||||
WriteShort(MSG_ENTITY, angles[1] * 32767 / 360);
|
WriteShort(MSG_ENTITY, angles[1] * 32767 / 360);
|
||||||
WriteShort(MSG_ENTITY, angles[2] * 32767 / 360);
|
WriteShort(MSG_ENTITY, angles[2] * 32767 / 360);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "NSEntity.h"
|
#include "NSEntity.h"
|
||||||
#include "NSRenderableEntity.h"
|
#include "NSRenderableEntity.h"
|
||||||
#include "NSSurfacePropEntity.h"
|
#include "NSSurfacePropEntity.h"
|
||||||
|
#include "NSPhysicsEntity.h"
|
||||||
#include "NSBrushTrigger.h"
|
#include "NSBrushTrigger.h"
|
||||||
#include "NSPointTrigger.h"
|
#include "NSPointTrigger.h"
|
||||||
#include "NSMonster.h"
|
#include "NSMonster.h"
|
||||||
|
|
158
src/gs-entbase/shared/prop_physics_multiplayer.qc
Normal file
158
src/gs-entbase/shared/prop_physics_multiplayer.qc
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
|
||||||
|
*
|
||||||
|
* 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 prop_physics_multiplayer (0 0 0.8) (-16 -16 -16) (16 16 16) PRPPHYS_ASLEEP
|
||||||
|
Physics prop that is optimised for netplay.
|
||||||
|
It either pushes the player away, or gets pushed away by the player.
|
||||||
|
The simulation can take place on either client or server.
|
||||||
|
|
||||||
|
-------- KEYS --------
|
||||||
|
"targetname" : Name
|
||||||
|
"physicsmode" : Which type of push/simulation model to use. See notes.
|
||||||
|
|
||||||
|
-------- NOTES --------
|
||||||
|
'physicsmode' can be one of three things:
|
||||||
|
1 - push player away
|
||||||
|
2 - get pushed (server-side)
|
||||||
|
3 - get pushed (client-side)
|
||||||
|
|
||||||
|
-------- TRIVIA --------
|
||||||
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PHYSICS_STATIC
|
||||||
|
#define PRPPHYS_ASLEEP 1
|
||||||
|
|
||||||
|
class prop_physics_multiplayer:NSPhysicsEntity
|
||||||
|
{
|
||||||
|
int m_iPhysicsMode;
|
||||||
|
|
||||||
|
void(void) prop_physics_multiplayer;
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
virtual void(void) Init;
|
||||||
|
#endif
|
||||||
|
virtual void(void) Respawn;
|
||||||
|
virtual void(string, string) SpawnKey;
|
||||||
|
virtual void(entity) Touch;
|
||||||
|
virtual void(void) TouchThink;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::TouchThink(void)
|
||||||
|
{
|
||||||
|
PhysicsEnable();
|
||||||
|
super::TouchThink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::Touch(entity eToucher)
|
||||||
|
{
|
||||||
|
/* we want to push our toucher away */
|
||||||
|
if (eToucher && eToucher.flags & FL_CLIENT)
|
||||||
|
if (m_iPhysicsMode == 1) {
|
||||||
|
makevectors(eToucher.origin - origin);
|
||||||
|
eToucher.velocity = v_forward * 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
super::Touch(eToucher);
|
||||||
|
nextthink = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::Respawn(void)
|
||||||
|
{
|
||||||
|
#ifdef SERVER
|
||||||
|
if (m_iPhysicsMode == 3) {
|
||||||
|
#else
|
||||||
|
if (m_iPhysicsMode != 3) {
|
||||||
|
#endif
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SERVER
|
||||||
|
dimension_solid = 1;
|
||||||
|
dimension_hit = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
super::Respawn();
|
||||||
|
|
||||||
|
if (HasSpawnFlags(PRPPHYS_ASLEEP))
|
||||||
|
PhysicsDisable();
|
||||||
|
else
|
||||||
|
PhysicsEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::SpawnKey(string strKey, string strValue)
|
||||||
|
{
|
||||||
|
switch (strKey) {
|
||||||
|
case "physicsmode":
|
||||||
|
m_iPhysicsMode = stoi(strValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NSPhysicsEntity::SpawnKey(strKey, strValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CLIENT
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::Init(void)
|
||||||
|
{
|
||||||
|
super::Init();
|
||||||
|
|
||||||
|
m_oldAngle = angles;
|
||||||
|
m_oldOrigin = origin;
|
||||||
|
m_oldModel = Util_FixModel(model);
|
||||||
|
|
||||||
|
Respawn();
|
||||||
|
drawmask = MASK_ENGINE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::prop_physics_multiplayer(void)
|
||||||
|
{
|
||||||
|
#ifdef CLIENT
|
||||||
|
Init();
|
||||||
|
#else
|
||||||
|
super::NSPhysicsEntity();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#ifdef SERVER
|
||||||
|
class prop_physics_multiplayer:NSRenderableEntity
|
||||||
|
{
|
||||||
|
void(void) prop_physics_multiplayer;
|
||||||
|
virtual void(void) Respawn;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::Respawn(void)
|
||||||
|
{
|
||||||
|
super::Respawn();
|
||||||
|
SetSolid(SOLID_BBOX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prop_physics_multiplayer::prop_physics_multiplayer(void)
|
||||||
|
{
|
||||||
|
super::NSRenderableEntity();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -244,4 +244,41 @@ readcmd(string foo)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void(string cmd) readcmd = #0:readcmd;
|
void(string cmd) readcmd = #0:readcmd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This is required because people who use Hammer do awful things
|
||||||
|
to get their models to update. We get a multitude of juicy
|
||||||
|
hacks and symbols that Half-Life's engine strips and now we have to
|
||||||
|
replicate this behaviour. Be thankful this is not done in-engine for
|
||||||
|
every game/mod ever.
|
||||||
|
*/
|
||||||
|
string Util_FixModel(string mdl)
|
||||||
|
{
|
||||||
|
if (!mdl) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int c = tokenizebyseparator(mdl, "/", "\\ ", "!");
|
||||||
|
string newpath = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < c; i++) {
|
||||||
|
newpath = sprintf("%s/%s", newpath, argv(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kill the first / */
|
||||||
|
newpath = substring(newpath, 1, strlen(newpath)-1);
|
||||||
|
|
||||||
|
/* Now we need to fix \/ because I hate people */
|
||||||
|
c = tokenizebyseparator(newpath, "\\/");
|
||||||
|
mdl = "";
|
||||||
|
for (int i = 0; i < c; i++) {
|
||||||
|
mdl = sprintf("%s/%s", mdl, argv(i));
|
||||||
|
}
|
||||||
|
/* Kill the first / again */
|
||||||
|
mdl = substring(mdl, 1, strlen(mdl)-1);
|
||||||
|
|
||||||
|
if (substring(mdl, 0, 1) == "/")
|
||||||
|
mdl = substring(mdl, 1, -1);
|
||||||
|
|
||||||
|
return mdl;
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ enum
|
||||||
ENT_NONE,
|
ENT_NONE,
|
||||||
ENT_ENTITY,
|
ENT_ENTITY,
|
||||||
ENT_ENTITYRENDERABLE,
|
ENT_ENTITYRENDERABLE,
|
||||||
|
ENT_PHYSICS,
|
||||||
ENT_MONSTER,
|
ENT_MONSTER,
|
||||||
ENT_TALKMONSTER,
|
ENT_TALKMONSTER,
|
||||||
ENT_PLAYER,
|
ENT_PLAYER,
|
||||||
|
|
Loading…
Reference in a new issue