PropData: read info from Source Engine .phy files
This commit is contained in:
parent
8cd6d3967d
commit
73bec53034
17 changed files with 421 additions and 78 deletions
|
@ -126,4 +126,15 @@ destruction.
|
||||||
this entity breaks.
|
this entity breaks.
|
||||||
- **breakable_model <string>**: Which models to spawn when it breaks.
|
- **breakable_model <string>**: Which models to spawn when it breaks.
|
||||||
- **breakable_count <int>**: The amount of models it'll spawn upon
|
- **breakable_count <int>**: The amount of models it'll spawn upon
|
||||||
breaking.
|
breaking.
|
||||||
|
- **surfaceprop <string>**: Surfaceprop override for the object.
|
||||||
|
|
||||||
|
## Physics Object Commands {#physcommands}
|
||||||
|
|
||||||
|
These are only relevant for when you want to use a phyics object, or rather an object that's handled by NSPhysicsEntity, such as prop_physics.
|
||||||
|
|
||||||
|
- **mass <float>**: Mass of the object, in kilograms.
|
||||||
|
- **volume <float>**: Volume of the object, in cubic meters.
|
||||||
|
- **inertia <float>**: Inertia multiplier.
|
||||||
|
- **damping <float>**: Linear movement damping multiplier.
|
||||||
|
- **rotdamping <float>**: Angular movement damping multiplier.
|
|
@ -228,6 +228,9 @@ Event_Parse(float type)
|
||||||
case EV_SHAKE:
|
case EV_SHAKE:
|
||||||
EV_Shake();
|
EV_Shake();
|
||||||
break;
|
break;
|
||||||
|
case EV_BREAKMODELDATA:
|
||||||
|
BreakModel_ReceiveClientData();
|
||||||
|
break;
|
||||||
case EV_BREAKMODEL:
|
case EV_BREAKMODEL:
|
||||||
BreakModel_Receive();
|
BreakModel_Receive();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -255,8 +255,8 @@ View_DrawViewModel(void)
|
||||||
if (Client_IsSpectator(cl) || XR_Available(pl) == false) {
|
if (Client_IsSpectator(cl) || XR_Available(pl) == false) {
|
||||||
m_eViewModelL.origin = g_view.GetCameraOrigin();
|
m_eViewModelL.origin = g_view.GetCameraOrigin();
|
||||||
m_eViewModel.origin = g_view.GetCameraOrigin();
|
m_eViewModel.origin = g_view.GetCameraOrigin();
|
||||||
m_eViewModel.angles = g_view.GetCameraAngle();
|
//m_eViewModel.angles = g_view.GetCameraAngle();
|
||||||
m_eViewModelL.angles = g_view.GetCameraAngle();
|
//m_eViewModelL.angles = g_view.GetCameraAngle();
|
||||||
|
|
||||||
/* we only calculate bob on the right model, to avoid double speed bobbing */
|
/* we only calculate bob on the right model, to avoid double speed bobbing */
|
||||||
Viewmodel_CalcBob();
|
Viewmodel_CalcBob();
|
||||||
|
|
|
@ -15,6 +15,7 @@ client/func_dustmotes.qc
|
||||||
client/func_dustcloud.qc
|
client/func_dustcloud.qc
|
||||||
client/func_smokevolume.qc
|
client/func_smokevolume.qc
|
||||||
client/light_environment.qc
|
client/light_environment.qc
|
||||||
|
client/prop_static.qc
|
||||||
client/infodecal.qc
|
client/infodecal.qc
|
||||||
client/sky_camera.qc
|
client/sky_camera.qc
|
||||||
client/info_notnull.qc
|
client/info_notnull.qc
|
||||||
|
|
|
@ -72,7 +72,7 @@ server/phys_keepupright.qc
|
||||||
server/phys_hinge.qc
|
server/phys_hinge.qc
|
||||||
server/phys_slideconstraint.qc
|
server/phys_slideconstraint.qc
|
||||||
//server/phys_constraintsystem.qc
|
//server/phys_constraintsystem.qc
|
||||||
server/prop_static.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
|
||||||
|
|
|
@ -36,7 +36,7 @@ A force-centered explosion, primarily targetted at physics objects and optionall
|
||||||
This entity was introduced in Half-Life 2 (2004).
|
This entity was introduced in Half-Life 2 (2004).
|
||||||
*/
|
*/
|
||||||
class
|
class
|
||||||
env_physexplosion:NSPhysicsConstraint
|
env_physexplosion:NSEntity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void env_physexplosion(void);
|
void env_physexplosion(void);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int g_ent_spawned;
|
static int g_ent_spawned;
|
||||||
|
.bool gotData;
|
||||||
|
|
||||||
/** Called once every single tic on the server. */
|
/** Called once every single tic on the server. */
|
||||||
void
|
void
|
||||||
|
@ -45,6 +46,7 @@ void
|
||||||
ClientConnect(void)
|
ClientConnect(void)
|
||||||
{
|
{
|
||||||
int playercount = 0;
|
int playercount = 0;
|
||||||
|
self.gotData = false;
|
||||||
|
|
||||||
/* don't carry over team settings from a previous session */
|
/* don't carry over team settings from a previous session */
|
||||||
forceinfokey(self, "*team", "0");
|
forceinfokey(self, "*team", "0");
|
||||||
|
@ -268,6 +270,11 @@ SV_RunClientCommand(void)
|
||||||
|
|
||||||
cl.SharedInputFrame();
|
cl.SharedInputFrame();
|
||||||
cl.ServerInputFrame();
|
cl.ServerInputFrame();
|
||||||
|
|
||||||
|
if (self.gotData == false) {
|
||||||
|
BreakModel_SendClientData(self);
|
||||||
|
self.gotData = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Any 'cmd' from the client get sent here and handled.
|
/** Any 'cmd' from the client get sent here and handled.
|
||||||
|
@ -390,18 +397,21 @@ initents(void)
|
||||||
precache_sound("misc/null.wav");
|
precache_sound("misc/null.wav");
|
||||||
precache_sound("common/null.wav");
|
precache_sound("common/null.wav");
|
||||||
|
|
||||||
Sound_Precache("player.gasplight");
|
Sound_Precache("player.GaspLight");
|
||||||
Sound_Precache("player.gaspheavy");
|
Sound_Precache("player.GaspHeavy");
|
||||||
Sound_Precache("player.waterenter");
|
Sound_Precache("player.WaterEnter");
|
||||||
Sound_Precache("player.waterexit");
|
Sound_Precache("player.WaterExit");
|
||||||
|
Sound_Precache("Player.Death");
|
||||||
|
Sound_Precache("Player.Pain");
|
||||||
|
Sound_Precache("Player.Wade");
|
||||||
|
Sound_Precache("Player.Swim");
|
||||||
|
Sound_Precache("Player.DenyWeaonSelection");
|
||||||
|
Sound_Precache("Player.WeaponSelected");
|
||||||
|
|
||||||
Sound_Precache("damage_bullet.hit");
|
Sound_Precache("damage_bullet.hit");
|
||||||
Sound_Precache("player.spraylogo");
|
Sound_Precache("player.spraylogo");
|
||||||
Sound_Precache("step_wade.left");
|
|
||||||
Sound_Precache("step_wade.right");
|
|
||||||
Sound_Precache("step_ladder.left");
|
Sound_Precache("step_ladder.left");
|
||||||
Sound_Precache("step_ladder.right");
|
Sound_Precache("step_ladder.right");
|
||||||
Sound_Precache("step_swim.left");
|
|
||||||
Sound_Precache("step_swim.right");
|
|
||||||
|
|
||||||
if (!g_grMode) {
|
if (!g_grMode) {
|
||||||
Game_InitRules();
|
Game_InitRules();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifdef CLIENT
|
#ifdef CLIENT
|
||||||
class NSDebris:NSRenderableEntity
|
class NSDebris:NSPhysicsEntity
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void NSDebris(void);
|
void NSDebris(void);
|
||||||
|
|
|
@ -25,7 +25,7 @@ _NSPhysics_Log(string msg)
|
||||||
|
|
||||||
|
|
||||||
var float autocvar_phys_pushscale = 1.0f;
|
var float autocvar_phys_pushscale = 1.0f;
|
||||||
var float autocvar_phys_impactforcescale = 1.0f;
|
var float autocvar_phys_impactforcescale = 100.0f;
|
||||||
|
|
||||||
#ifdef CLIENT
|
#ifdef CLIENT
|
||||||
var bool autocvar_r_showPhysicsInfo = false;
|
var bool autocvar_r_showPhysicsInfo = false;
|
||||||
|
@ -91,17 +91,19 @@ private:
|
||||||
int m_iFlags;
|
int m_iFlags;
|
||||||
float m_flInertiaScale;
|
float m_flInertiaScale;
|
||||||
float m_flBuoyancyRatio;
|
float m_flBuoyancyRatio;
|
||||||
|
bool m_bInvincible;
|
||||||
|
float m_flVolume;
|
||||||
|
|
||||||
/* performance sanity checks */
|
/* performance sanity checks */
|
||||||
vector m_vecPrevOrigin;
|
vector m_vecPrevOrigin;
|
||||||
vector m_vecPrevAngles;
|
vector m_vecPrevAngles;
|
||||||
float m_flCheckTime;
|
float m_flCheckTime;
|
||||||
|
PREDICTED_FLOAT(m_flMass)
|
||||||
|
|
||||||
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;
|
string m_strOnDamaged;
|
||||||
#endif
|
#endif
|
||||||
|
@ -127,6 +129,9 @@ public:
|
||||||
virtual void postdraw(void);
|
virtual void postdraw(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
nonvirtual void _UpdateBuoyancy(void);
|
||||||
|
nonvirtual void _UpdateMass(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. */
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
.float max_angular;
|
.float max_angular;
|
||||||
|
|
||||||
|
/* taken from VPhysics-Jolt */
|
||||||
|
const float InchesToMeters = 0.0254f;
|
||||||
|
const float MetersToInches = 1.0f / 0.0254f;
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::NSPhysicsEntity(void)
|
NSPhysicsEntity::NSPhysicsEntity(void)
|
||||||
{
|
{
|
||||||
|
@ -30,17 +35,18 @@ NSPhysicsEntity::NSPhysicsEntity(void)
|
||||||
damp_linear = 1.0f;
|
damp_linear = 1.0f;
|
||||||
damp_angular = 1.0f;
|
damp_angular = 1.0f;
|
||||||
max_angular = -1.0f;
|
max_angular = -1.0f;
|
||||||
|
m_flMass = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
cvar_set("physics_ode_quadtree_depth", "10");
|
cvar_set("physics_ode_quadtree_depth", "5");
|
||||||
cvar_set("physics_ode_contactsurfacelayer", "0");
|
cvar_set("physics_ode_contactsurfacelayer", "0");
|
||||||
cvar_set("physics_ode_worldquickstep", "1");
|
cvar_set("physics_ode_worldquickstep", "1");
|
||||||
cvar_set("physics_ode_worldquickstep_iterations", "20");
|
cvar_set("physics_ode_worldquickstep_iterations", "20");
|
||||||
cvar_set("physics_ode_contact_mu", "-1");
|
cvar_set("physics_ode_contact_mu", "1");
|
||||||
cvar_set("physics_ode_contact_erp", "0.96");
|
cvar_set("physics_ode_contact_erp", "0.96");
|
||||||
cvar_set("physics_ode_contact_cfm", "0.001");
|
cvar_set("physics_ode_contact_cfm", "0.001");
|
||||||
cvar_set("physics_ode_world_damping", "1");
|
cvar_set("physics_ode_world_damping", "1");
|
||||||
cvar_set("physics_ode_world_damping_linear", "-1");
|
cvar_set("physics_ode_world_damping_linear", "-1");
|
||||||
cvar_set("physics_ode_world_damping_linear_threshold", "-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", "-1");
|
||||||
cvar_set("physics_ode_world_damping_angular_threshold", "-1");
|
cvar_set("physics_ode_world_damping_angular_threshold", "-1");
|
||||||
|
@ -179,7 +185,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)
|
EVALUATE_FIELD(m_flMass, RDENT_CHANGED_SOLIDMOVETYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
@ -269,7 +275,7 @@ NSPhysicsEntity::SendEntity(entity ePEnt, float flChanged)
|
||||||
SENDENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
SENDENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
||||||
|
|
||||||
/* physics specific flags */
|
/* physics specific flags */
|
||||||
SENDENTITY_FLOAT(mass, RDENT_CHANGED_SOLIDMOVETYPE)
|
SENDENTITY_FLOAT(m_flMass, RDENT_CHANGED_SOLIDMOVETYPE)
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
@ -333,7 +339,7 @@ NSPhysicsEntity::ReceiveEntity(float flNew, float flChanged)
|
||||||
READENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
READENTITY_ANGLE(m_flBoneControl5, RDENT_CHANGED_CONTROLLER)
|
||||||
|
|
||||||
/* physics specific flags */
|
/* physics specific flags */
|
||||||
READENTITY_FLOAT(mass, RDENT_CHANGED_SOLIDMOVETYPE)
|
READENTITY_FLOAT(m_flMass, RDENT_CHANGED_SOLIDMOVETYPE)
|
||||||
|
|
||||||
if (scale == 0.0)
|
if (scale == 0.0)
|
||||||
scale = 1.0f;
|
scale = 1.0f;
|
||||||
|
@ -344,6 +350,7 @@ NSPhysicsEntity::ReceiveEntity(float flNew, float flChanged)
|
||||||
_UpdateGeomset();
|
_UpdateGeomset();
|
||||||
|
|
||||||
movetype = MOVETYPE_NONE;
|
movetype = MOVETYPE_NONE;
|
||||||
|
_UpdateMass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -355,8 +362,11 @@ NSPhysicsEntity::postdraw(void)
|
||||||
if not (PointMessage_Visible(WorldSpaceCenter(), g_view.GetCameraOrigin(), g_view.GetCameraAngle()))
|
if not (PointMessage_Visible(WorldSpaceCenter(), g_view.GetCameraOrigin(), g_view.GetCameraAngle()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string renderString = sprintf("Mass: %f\nEnergy: %f\nInertia:%d",
|
float massVolume = (size[0] * size[1] * size[2]);
|
||||||
GetMass(), GetEnergy(), GetInertia());
|
massVolume *= 0.0254f; /* from meters to inches */
|
||||||
|
|
||||||
|
string renderString = sprintf("Mass: %.2f kg (%.2f ODE)\nEnergy: %f kj\nInertia:%d\nVolume: %.2f",
|
||||||
|
GetMass(), mass, GetEnergy(), GetInertia(), massVolume);
|
||||||
|
|
||||||
PointMessage_StringAtPos(WorldSpaceCenter(), renderString);
|
PointMessage_StringAtPos(WorldSpaceCenter(), renderString);
|
||||||
}
|
}
|
||||||
|
@ -530,9 +540,10 @@ NSPhysicsEntity::Pain(void)
|
||||||
if (force > 0.0f)
|
if (force > 0.0f)
|
||||||
ApplyForceOffset(forceDir * force, g_dmg_vecLocation);
|
ApplyForceOffset(forceDir * force, g_dmg_vecLocation);
|
||||||
|
|
||||||
/* if we don't have prop data, don't consider death */
|
/* HACK: */
|
||||||
if (HasPropData() == false)
|
if (m_bInvincible) {
|
||||||
health = 10000;
|
health = 10000;
|
||||||
|
}
|
||||||
|
|
||||||
/* make sure touch think is called */
|
/* make sure touch think is called */
|
||||||
nextthink = time;
|
nextthink = time;
|
||||||
|
@ -547,7 +558,11 @@ NSPhysicsEntity::Death(void)
|
||||||
if (takedamage != DAMAGE_YES) {
|
if (takedamage != DAMAGE_YES) {
|
||||||
takedamage = (DAMAGE_YES);
|
takedamage = (DAMAGE_YES);
|
||||||
}
|
}
|
||||||
health = 1000;
|
|
||||||
|
/* HACK: */
|
||||||
|
if (m_bInvincible) {
|
||||||
|
health = 10000;
|
||||||
|
}
|
||||||
|
|
||||||
/* make sure touch think is called */
|
/* make sure touch think is called */
|
||||||
nextthink = time;
|
nextthink = time;
|
||||||
|
@ -567,22 +582,22 @@ NSPhysicsEntity::Respawn(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Sleep();
|
Sleep();
|
||||||
SetMass(10.0f);
|
SetMass(1.0f);
|
||||||
SetFriction(1.0f);
|
SetFriction(1.0f);
|
||||||
SetBuoyancyRatio(1.0f);
|
SetBuoyancyRatio(1.0f);
|
||||||
bouncefactor = 0.9f;
|
bouncefactor = 0.9f;
|
||||||
bouncestop = 0.1f / cvar("sv_gravity");
|
bouncestop = 0.1f / cvar("sv_gravity");
|
||||||
|
|
||||||
//bouncefactor = 0.0f;
|
bouncefactor = 0.0f;
|
||||||
//bouncestop = 0.0f;
|
bouncestop = 0.0f;
|
||||||
|
|
||||||
geomtype = GEOMTYPE_TRIMESH;
|
geomtype = GEOMTYPE_TRIMESH;
|
||||||
friction = 100.0f;
|
friction = 1.0f;
|
||||||
|
|
||||||
SetOrigin(GetSpawnOrigin());
|
SetOrigin(GetSpawnOrigin());
|
||||||
m_flBuoyancyRatio = 1.0f;
|
m_flBuoyancyRatio = 1.0f;
|
||||||
|
|
||||||
SetDamping(0.0f, 0.0f);
|
SetDamping(1.0f, 1.0f);
|
||||||
EnableGravity(true);
|
EnableGravity(true);
|
||||||
|
|
||||||
hitcontentsmaski &= ~CONTENTBITS_FLUID;
|
hitcontentsmaski &= ~CONTENTBITS_FLUID;
|
||||||
|
@ -600,9 +615,25 @@ NSPhysicsEntity::Respawn(void)
|
||||||
|
|
||||||
#ifdef SERVER
|
#ifdef SERVER
|
||||||
if (HasPropData()) {
|
if (HasPropData()) {
|
||||||
health = GetPropData(PROPINFO_HEALTH);
|
SetHealth(GetPropData(PROPINFO_HEALTH));
|
||||||
|
SetMass(GetPropData(PROPINFO_MASS));
|
||||||
|
SetDamping(GetPropData(PROPINFO_DAMPING_LINEAR), GetPropData(PROPINFO_DAMPING_ANGULAR));
|
||||||
|
SetInertia(GetPropData(PROPINFO_INERTIA));
|
||||||
|
SetSurfaceData(GetPropData(PROPINFO_SURFACEPROP));
|
||||||
} else {
|
} else {
|
||||||
health = 100000;
|
health = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no health set, either indistructible or too weak */
|
||||||
|
if (health == 0) {
|
||||||
|
/* it has no breakmodels set, therefore it cannot break. */
|
||||||
|
if (GetPropData(PROPINFO_BREAKMODEL) == __NULL__) {
|
||||||
|
m_bInvincible = true;
|
||||||
|
health = 10000;
|
||||||
|
} else {
|
||||||
|
/* something like glass bottles, maybe. */
|
||||||
|
health = 1.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -666,6 +697,8 @@ NSPhysicsEntity::ApplyForceCenter(vector vecForce)
|
||||||
{
|
{
|
||||||
Wake();
|
Wake();
|
||||||
|
|
||||||
|
vecForce *= MetersToInches;
|
||||||
|
|
||||||
if (physics_supported() == TRUE) {
|
if (physics_supported() == TRUE) {
|
||||||
vector finalForce = vecForce;
|
vector finalForce = vecForce;
|
||||||
physics_addforce(this, finalForce, GetMassCenter());
|
physics_addforce(this, finalForce, GetMassCenter());
|
||||||
|
@ -685,6 +718,8 @@ NSPhysicsEntity::ApplyForceOffset(vector vecForce, vector vecOffset)
|
||||||
{
|
{
|
||||||
Wake();
|
Wake();
|
||||||
|
|
||||||
|
vecForce *= MetersToInches;
|
||||||
|
|
||||||
if (physics_supported() == TRUE) {
|
if (physics_supported() == TRUE) {
|
||||||
vector finalForce = vecForce;
|
vector finalForce = vecForce;
|
||||||
physics_addforce(this, finalForce, vecOffset);
|
physics_addforce(this, finalForce, vecOffset);
|
||||||
|
@ -767,7 +802,7 @@ NSPhysicsEntity::GetEnergy(void)
|
||||||
rotationalEnergy = (0.5f * GetMass() * vlen(GetAngularVelocity()));
|
rotationalEnergy = (0.5f * GetMass() * vlen(GetAngularVelocity()));
|
||||||
rotationalEnergy *= rotationalEnergy;
|
rotationalEnergy *= rotationalEnergy;
|
||||||
|
|
||||||
return linearEnergy + rotationalEnergy;
|
return (linearEnergy + rotationalEnergy) / (InchesToMeters * InchesToMeters);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
@ -791,7 +826,7 @@ NSPhysicsEntity::GetInvMass(void)
|
||||||
float
|
float
|
||||||
NSPhysicsEntity::GetMass(void)
|
NSPhysicsEntity::GetMass(void)
|
||||||
{
|
{
|
||||||
return mass;
|
return m_flMass;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector
|
vector
|
||||||
|
@ -897,10 +932,39 @@ NSPhysicsEntity::SetInertia(float val)
|
||||||
m_flInertiaScale = val;
|
m_flInertiaScale = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::_UpdateMass(void)
|
||||||
|
{
|
||||||
|
/* in ODE, mass is relative. */
|
||||||
|
float massVolume = (size[0] * size[1] * size[2]);
|
||||||
|
massVolume *= 0.0254f; /* from inches to meters */
|
||||||
|
|
||||||
|
mass = 1.0f;
|
||||||
|
//mass = m_flMass / massVolume; /* really ODE's thing is density */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSPhysicsEntity::_UpdateBuoyancy(void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if ( m_flVolume != 0.0f )
|
||||||
|
{
|
||||||
|
float flVolume = max( m_flVolume, 5.0f ) * MeterstoInches * MeterstoInches * MeterstoInches;
|
||||||
|
float flDensity = m_flMass / flVolume;
|
||||||
|
m_flBuoyancyRatio = flDensity / m_flMaterialDensity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_flBuoyancyRatio = 1.0f;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NSPhysicsEntity::SetMass(float val)
|
NSPhysicsEntity::SetMass(float val)
|
||||||
{
|
{
|
||||||
mass = val;
|
m_flMass = val;
|
||||||
|
_UpdateMass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -659,9 +659,6 @@ NSSurfacePropEntity::Death(void)
|
||||||
{
|
{
|
||||||
m_flDeathTime = time;
|
m_flDeathTime = time;
|
||||||
|
|
||||||
print(sprintf("%S", m_strOnBreak));
|
|
||||||
print("\n");
|
|
||||||
|
|
||||||
UseOutput(g_dmg_eAttacker, m_strOnBreak);
|
UseOutput(g_dmg_eAttacker, m_strOnBreak);
|
||||||
|
|
||||||
if (HasPropData() == false)
|
if (HasPropData() == false)
|
||||||
|
@ -672,7 +669,8 @@ NSSurfacePropEntity::Death(void)
|
||||||
} else if (GetPropData(PROPINFO_BREAKMODEL) != __NULL__) {
|
} else if (GetPropData(PROPINFO_BREAKMODEL) != __NULL__) {
|
||||||
string gibeffect = GetPropData(PROPINFO_BREAKMODEL);
|
string gibeffect = GetPropData(PROPINFO_BREAKMODEL);
|
||||||
int breakcount = GetPropData(PROPINFO_BREAKCOUNT);
|
int breakcount = GetPropData(PROPINFO_BREAKCOUNT);
|
||||||
BreakModel_Spawn(absmin, absmax, [0,0,0], 100, breakcount, gibeffect);
|
BreakModel_Entity(this, normalize(GetOrigin() - g_dmg_vecLocation), g_dmg_iDamage);
|
||||||
|
//BreakModel_Spawn(absmin, absmax, [0,0,0], 100, breakcount, gibeffect);
|
||||||
Disappear();
|
Disappear();
|
||||||
} else {
|
} else {
|
||||||
Disappear();
|
Disappear();
|
||||||
|
|
|
@ -377,6 +377,29 @@ string Util_FixModel(string mdl)
|
||||||
return mdl;
|
return mdl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns a string (usually filename) with only the file extension
|
||||||
|
at the end replaced with a given, new extension. */
|
||||||
|
string
|
||||||
|
Util_ChangeExtension(string baseString, string newExtension)
|
||||||
|
{
|
||||||
|
float stringOffset = 0;
|
||||||
|
string tempString = "";
|
||||||
|
float foundOffset = 0;
|
||||||
|
|
||||||
|
while ((tempString = substring(baseString, stringOffset, 1))) {
|
||||||
|
if (tempString == ".")
|
||||||
|
foundOffset = stringOffset;
|
||||||
|
if (tempString == "")
|
||||||
|
break;
|
||||||
|
if not (tempString)
|
||||||
|
break;
|
||||||
|
|
||||||
|
stringOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strcat(substring(baseString, 0, foundOffset), ".", newExtension);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Util_IsSingleplayer(void)
|
Util_IsSingleplayer(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,6 +54,7 @@ enum
|
||||||
EV_SURFIMPACT,
|
EV_SURFIMPACT,
|
||||||
EV_SURFIMPACTID,
|
EV_SURFIMPACTID,
|
||||||
EV_DECALGROUP,
|
EV_DECALGROUP,
|
||||||
|
EV_BREAKMODELDATA,
|
||||||
EV_BREAKMODEL,
|
EV_BREAKMODEL,
|
||||||
EV_BEAMCYLINDER,
|
EV_BEAMCYLINDER,
|
||||||
EV_MUZZLEFLASH,
|
EV_MUZZLEFLASH,
|
||||||
|
|
|
@ -34,6 +34,4 @@ typedef enum
|
||||||
void PMove_StartFrame(void);
|
void PMove_StartFrame(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void PMove_Init(void);
|
void PMove_Init(void);
|
||||||
|
|
||||||
void PMove_Run(void);
|
|
|
@ -132,6 +132,7 @@ var float autocvar_pm_wateraccelerate = PMOVE_WATERACCELERATE;
|
||||||
var float autocvar_pm_accelerate = PMOVE_ACCELERATE;
|
var float autocvar_pm_accelerate = PMOVE_ACCELERATE;
|
||||||
var float autocvar_pm_maxspeed = PMOVE_MAXSPEED;
|
var float autocvar_pm_maxspeed = PMOVE_MAXSPEED;
|
||||||
var float autocvar_g_gravity = PMOVE_GRAVITY;
|
var float autocvar_g_gravity = PMOVE_GRAVITY;
|
||||||
|
var bool autocvar_pm_nospeedcap = false;
|
||||||
|
|
||||||
void
|
void
|
||||||
PMove_Init(void)
|
PMove_Init(void)
|
||||||
|
@ -167,7 +168,7 @@ PMove_StartFrame(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* simple bounds check */
|
/* simple bounds check */
|
||||||
int
|
bool
|
||||||
PMove_IsStuck(entity eTarget, vector vOffset, vector vecMins, vector vecMaxs)
|
PMove_IsStuck(entity eTarget, vector vOffset, vector vecMins, vector vecMaxs)
|
||||||
{
|
{
|
||||||
vector bound;
|
vector bound;
|
||||||
|
@ -180,14 +181,3 @@ PMove_IsStuck(entity eTarget, vector vOffset, vector vecMins, vector vecMaxs)
|
||||||
tracebox(bound, vecMins, vecMaxs, bound, MOVE_NORMAL, eTarget);
|
tracebox(bound, vecMins, vecMaxs, bound, MOVE_NORMAL, eTarget);
|
||||||
return trace_startsolid;
|
return trace_startsolid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* it all starts here, this function is called by both CLIENT and SERVER for
|
|
||||||
obvious prediction purposes. The SERVER will usually do this in the
|
|
||||||
Game_RunClientCommand function and the CLIENT will do so in both the
|
|
||||||
prediction places of Predict_PreFrame and Player_ReceiveEntity */
|
|
||||||
void
|
|
||||||
PMove_Run(void)
|
|
||||||
{
|
|
||||||
player pl = (player)self;
|
|
||||||
pl.Physics_Run();
|
|
||||||
}
|
|
||||||
|
|
|
@ -83,6 +83,12 @@ typedef struct
|
||||||
string breakable_model; /* name of BreakableModels entry in PropData.txt */
|
string breakable_model; /* name of BreakableModels entry in PropData.txt */
|
||||||
int breakable_count;
|
int breakable_count;
|
||||||
float breakable_skin;
|
float breakable_skin;
|
||||||
|
float mass;
|
||||||
|
float damping_linear;
|
||||||
|
float damping_angular;
|
||||||
|
float inertia;
|
||||||
|
float volume;
|
||||||
|
string surfaceprop;
|
||||||
} propdata_t;
|
} propdata_t;
|
||||||
|
|
||||||
/* entity will have to have a .propdata field pointing to a propdata id */
|
/* entity will have to have a .propdata field pointing to a propdata id */
|
||||||
|
@ -113,7 +119,14 @@ typedef enum
|
||||||
PROPINFO_EXPLOSIVE_RADIUS,
|
PROPINFO_EXPLOSIVE_RADIUS,
|
||||||
PROPINFO_BREAKMODEL,
|
PROPINFO_BREAKMODEL,
|
||||||
PROPINFO_BREAKCOUNT,
|
PROPINFO_BREAKCOUNT,
|
||||||
PROPINFO_SKIN
|
PROPINFO_SKIN,
|
||||||
|
/* physics related variables. */
|
||||||
|
PROPINFO_MASS,
|
||||||
|
PROPINFO_DAMPING_LINEAR,
|
||||||
|
PROPINFO_DAMPING_ANGULAR,
|
||||||
|
PROPINFO_INERTIA,
|
||||||
|
PROPINFO_VOLUME,
|
||||||
|
PROPINFO_SURFACEPROP
|
||||||
} propinfo_t;
|
} propinfo_t;
|
||||||
__variant Prop_GetInfo(int, int);
|
__variant Prop_GetInfo(int, int);
|
||||||
|
|
||||||
|
@ -121,20 +134,25 @@ typedef struct
|
||||||
{
|
{
|
||||||
string name;
|
string name;
|
||||||
string data;
|
string data;
|
||||||
|
float modelindex; /* only used for networking */
|
||||||
|
bool physics; /* differentiate between Source and GS */
|
||||||
} breakmodel_t;
|
} breakmodel_t;
|
||||||
|
|
||||||
/* entity will have a .breakmodel field pointing to a breakmodel id */
|
/* entity will have a .breakmodel field pointing to a breakmodel id */
|
||||||
breakmodel_t *g_breakmodel;
|
breakmodel_t *g_breakmodel;
|
||||||
int g_breakmodel_count;
|
int g_breakmodel_count;
|
||||||
|
int g_breakmodel_end;
|
||||||
var hashtable g_hashbreakmodel;
|
var hashtable g_hashbreakmodel;
|
||||||
|
|
||||||
|
|
||||||
#ifdef CLIENT
|
#ifdef CLIENT
|
||||||
void BreakModel_SpawnID(vector smins, vector smaxs, vector dir, float speed, int count, int index);
|
void BreakModel_SpawnID(vector smins, vector smaxs, vector dir, float speed, int count, int index);
|
||||||
void BreakModel_Receive(void);
|
void BreakModel_Receive(void);
|
||||||
|
void BreakModel_ReceiveClientData(void);
|
||||||
#else
|
#else
|
||||||
void BreakModel_Spawn(vector pos, vector dir, vector spread, float speed, int count, string type);
|
void BreakModel_Spawn(vector pos, vector dir, vector spread, float speed, int count, string type);
|
||||||
void BreakModel_Entity(NSSurfacePropEntity target, vector dir, float speed);
|
void BreakModel_Entity(NSSurfacePropEntity target, vector dir, float speed);
|
||||||
|
void BreakModel_SendClientData(entity);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* necessary API functions */
|
/* necessary API functions */
|
||||||
|
|
|
@ -71,6 +71,18 @@ Prop_GetInfo(int i, int type)
|
||||||
return (__variant)g_propdata[i].breakable_count;
|
return (__variant)g_propdata[i].breakable_count;
|
||||||
case PROPINFO_SKIN:
|
case PROPINFO_SKIN:
|
||||||
return (__variant)g_propdata[i].breakable_skin;
|
return (__variant)g_propdata[i].breakable_skin;
|
||||||
|
case PROPINFO_MASS:
|
||||||
|
return (__variant)g_propdata[i].mass;
|
||||||
|
case PROPINFO_DAMPING_LINEAR:
|
||||||
|
return (__variant)g_propdata[i].damping_linear;
|
||||||
|
case PROPINFO_DAMPING_ANGULAR:
|
||||||
|
return (__variant)g_propdata[i].damping_angular;
|
||||||
|
case PROPINFO_INERTIA:
|
||||||
|
return (__variant)g_propdata[i].inertia;
|
||||||
|
case PROPINFO_VOLUME:
|
||||||
|
return (__variant)g_propdata[i].volume;
|
||||||
|
case PROPINFO_SURFACEPROP:
|
||||||
|
return (__variant)g_propdata[i].surfaceprop;
|
||||||
default:
|
default:
|
||||||
return __NULL__;
|
return __NULL__;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +92,9 @@ void
|
||||||
PropData_ParseField(int i, int a)
|
PropData_ParseField(int i, int a)
|
||||||
{
|
{
|
||||||
switch (argv(0)) {
|
switch (argv(0)) {
|
||||||
|
case "name":
|
||||||
|
g_propdata[i].name = argv(1);
|
||||||
|
break;
|
||||||
case "base":
|
case "base":
|
||||||
g_propdata[i].base = argv(1);
|
g_propdata[i].base = argv(1);
|
||||||
break;
|
break;
|
||||||
|
@ -122,6 +137,24 @@ PropData_ParseField(int i, int a)
|
||||||
case "breakable_skin":
|
case "breakable_skin":
|
||||||
g_propdata[i].breakable_skin = stof(argv(1));
|
g_propdata[i].breakable_skin = stof(argv(1));
|
||||||
break;
|
break;
|
||||||
|
case "mass":
|
||||||
|
g_propdata[i].mass = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "damping":
|
||||||
|
g_propdata[i].damping_linear = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "rotdamping":
|
||||||
|
g_propdata[i].damping_angular = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "inertia":
|
||||||
|
g_propdata[i].inertia = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "volume":
|
||||||
|
g_propdata[i].volume = stof(argv(1));
|
||||||
|
break;
|
||||||
|
case "surfaceprop":
|
||||||
|
g_propdata[i].surfaceprop = argv(1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +212,62 @@ PropData_Parse(int i, string line, string type)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* specific to parsing strings from binary .phy files */
|
||||||
|
int
|
||||||
|
PropData_ParsePhyFile(int i, string line, string type)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
string key;
|
||||||
|
static string t_name;
|
||||||
|
static int braced = 0i;
|
||||||
|
|
||||||
|
static string gibModel = "";
|
||||||
|
static string gibFadeTime = "";
|
||||||
|
|
||||||
|
c = tokenize(line);
|
||||||
|
|
||||||
|
for (int x = 0i; x < c; x++) {
|
||||||
|
key = argv(x);
|
||||||
|
|
||||||
|
switch(key) {
|
||||||
|
case "{":
|
||||||
|
braced++;
|
||||||
|
break;
|
||||||
|
case "}":
|
||||||
|
if (braced == 1i && t_name == "break") {
|
||||||
|
int bID = g_breakmodel_count; /* !!! increment after loading phy file! */
|
||||||
|
g_breakmodel[bID].modelindex = getmodelindex(type);
|
||||||
|
g_breakmodel[bID].name = g_propdata[i].name;
|
||||||
|
g_breakmodel[bID].data = sprintf("%s%S %S\n", g_breakmodel[bID].data, gibModel, gibFadeTime);
|
||||||
|
hash_add(g_hashbreakmodel, g_breakmodel[bID].name, (int)bID);
|
||||||
|
g_propdata[i].breakable_model = g_breakmodel[bID].name;
|
||||||
|
g_propdata[i].breakable_count++;
|
||||||
|
gibModel = "";
|
||||||
|
gibFadeTime = 0.0f;
|
||||||
|
}
|
||||||
|
braced--;
|
||||||
|
t_name = "";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (braced == 1i && t_name == "solid") {
|
||||||
|
PropData_ParseField(i, c);
|
||||||
|
} else if (braced == 1i && t_name == "break") {
|
||||||
|
switch (key) {
|
||||||
|
case "model":
|
||||||
|
gibModel = strcat("models/", argv(x+1), ".mdl");
|
||||||
|
break;
|
||||||
|
case "fadetime":
|
||||||
|
gibFadeTime = argv(x+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (braced == 0i) {
|
||||||
|
t_name = strtolower(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/* goes through and looks for a specifically named propdata type inside the scripts dir */
|
/* goes through and looks for a specifically named propdata type inside the scripts dir */
|
||||||
int
|
int
|
||||||
PropData_ForModel(string modelname)
|
PropData_ForModel(string modelname)
|
||||||
|
@ -196,9 +285,9 @@ PropData_ForModel(string modelname)
|
||||||
index = g_propdata_count;
|
index = g_propdata_count;
|
||||||
modelname = strtolower(modelname);
|
modelname = strtolower(modelname);
|
||||||
|
|
||||||
dprint("[PROPDATA] Loading model propdata ");
|
print("[PROPDATA] Loading model propdata ");
|
||||||
dprint(modelname);
|
print(modelname);
|
||||||
dprint("\n");
|
print("\n");
|
||||||
|
|
||||||
/* create the hash-table if it doesn't exist */
|
/* create the hash-table if it doesn't exist */
|
||||||
if (!g_hashpropdata) {
|
if (!g_hashpropdata) {
|
||||||
|
@ -220,7 +309,8 @@ PropData_ForModel(string modelname)
|
||||||
g_propdata = (propdata_t *)memrealloc(g_propdata, sizeof(propdata_t), index, g_propdata_count);
|
g_propdata = (propdata_t *)memrealloc(g_propdata, sizeof(propdata_t), index, g_propdata_count);
|
||||||
#else
|
#else
|
||||||
if (g_propdata_count >= PROPDATA_MAX) {
|
if (g_propdata_count >= PROPDATA_MAX) {
|
||||||
error(sprintf("PropData_ForModel: Reached PROPDATA_MAX (%d)\n", PROPDATA_MAX));
|
printf(sprintf("PropData_ForModel: Reached PROPDATA_MAX (%d)\n", PROPDATA_MAX));
|
||||||
|
return -1i;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -228,9 +318,75 @@ PropData_ForModel(string modelname)
|
||||||
|
|
||||||
fh = fopen(strcat(modelname, ".propdata"), FILE_READ);
|
fh = fopen(strcat(modelname, ".propdata"), FILE_READ);
|
||||||
if (fh < 0) {
|
if (fh < 0) {
|
||||||
g_propdata_count--;
|
/* try the Source Engine version */
|
||||||
NSLog("Can't find propdata for model %s", modelname);
|
fh = fopen(Util_ChangeExtension(modelname, "phy"), FILE_READ);
|
||||||
return -1;
|
|
||||||
|
if (fh < 0) {
|
||||||
|
g_propdata_count--;
|
||||||
|
NSLog("Can't find propdata for model %s", modelname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fileSize;
|
||||||
|
int phyID;
|
||||||
|
int numSolids;
|
||||||
|
int fileSum;
|
||||||
|
int filePos = 0i;
|
||||||
|
int surfaceSize;
|
||||||
|
|
||||||
|
filePos = fread(fh, (void*)&fileSize, 4i); /* header size, sanity check */
|
||||||
|
|
||||||
|
if (fileSize != 16i) {
|
||||||
|
error("Only .phy files from Source are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
filePos = fread(fh, (void*)&phyID, 4i); /* some header id */
|
||||||
|
filePos = fread(fh, (void*)&numSolids, 4i); /* read our number of solids. */
|
||||||
|
filePos = fread(fh, (void*)&fileSum, 4i);
|
||||||
|
|
||||||
|
//print(sprintf("num fileSize: %i\n", fileSize));
|
||||||
|
//print(sprintf("num phyID: %i\n", phyID));
|
||||||
|
//print(sprintf("num numSolids: %i\n", numSolids));
|
||||||
|
//print(sprintf("num fileSum: %i\n", fileSum));
|
||||||
|
|
||||||
|
/* HACK: We won't support ragdolls, for now. */
|
||||||
|
if (numSolids > 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* we skip over all these to get to the bottom of the file */
|
||||||
|
for (int i = 0i; i < numSolids; i++) {
|
||||||
|
filePos = fread(fh, (void*)&surfaceSize, 4);
|
||||||
|
filePos = fseek(fh, filePos + surfaceSize + 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now comes the propdata */
|
||||||
|
while ((line = fgets(fh))) {
|
||||||
|
//printf(line);
|
||||||
|
//print("\n");
|
||||||
|
PropData_ParsePhyFile(index, line, modelname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* push up the breakmodel count by one if we've written into it */
|
||||||
|
{
|
||||||
|
string breakModel = Prop_GetInfo(index, PROPINFO_BREAKMODEL);
|
||||||
|
|
||||||
|
if (breakModel != "") {
|
||||||
|
int bID = (int)hash_get(g_hashbreakmodel, Prop_GetInfo(index, PROPINFO_BREAKMODEL), -1);
|
||||||
|
|
||||||
|
if (bID != -1) {
|
||||||
|
if (g_breakmodel[bID].data) {
|
||||||
|
g_breakmodel[bID].physics = true;
|
||||||
|
g_breakmodel_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//print(sprintf("Added %S at id %i with name %S\n", modelname, index, g_propdata[index].name));
|
||||||
|
hash_add(g_hashpropdata, modelname, (int)index);
|
||||||
|
return index;
|
||||||
|
|
||||||
|
//error(sprintf("phy file (size %i): size: %i id: %i numSolids: %i\n", fsize(fh), fileSize, phyID, numSolids));
|
||||||
}
|
}
|
||||||
while ((line = fgets(fh))) {
|
while ((line = fgets(fh))) {
|
||||||
/* when we found it, quit */
|
/* when we found it, quit */
|
||||||
|
@ -456,8 +612,13 @@ PropData_Init(void)
|
||||||
/* gotta tokenize our inputs again */
|
/* gotta tokenize our inputs again */
|
||||||
x = tokenize(g_breakmodel[i].data);
|
x = tokenize(g_breakmodel[i].data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We're making assumptions here, but most physics props have their
|
||||||
|
breakmodels defined along the model. */
|
||||||
|
g_breakmodel[i].physics = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_breakmodel_end = g_breakmodel_count;
|
||||||
print("PropData initialized.\n");
|
print("PropData initialized.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,6 +652,9 @@ BreakModel_SpawnID(vector smins, vector smaxs, vector dir, float speed, int coun
|
||||||
{
|
{
|
||||||
float x = tokenize(g_breakmodel[index].data);
|
float x = tokenize(g_breakmodel[index].data);
|
||||||
int modelcount = x / 2;
|
int modelcount = x / 2;
|
||||||
|
bool usePhysics = g_breakmodel[index].physics;
|
||||||
|
|
||||||
|
//print(sprintf("breaking into %i models\n", modelcount));
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
vector endpos;
|
vector endpos;
|
||||||
|
@ -498,7 +662,6 @@ BreakModel_SpawnID(vector smins, vector smaxs, vector dir, float speed, int coun
|
||||||
string fullline;
|
string fullline;
|
||||||
float fadetime;
|
float fadetime;
|
||||||
NSDebris gib;
|
NSDebris gib;
|
||||||
int r;
|
|
||||||
int p;
|
int p;
|
||||||
int bodygroup = 0;
|
int bodygroup = 0;
|
||||||
vector rendercolor = [1,1,1];
|
vector rendercolor = [1,1,1];
|
||||||
|
@ -507,12 +670,17 @@ BreakModel_SpawnID(vector smins, vector smaxs, vector dir, float speed, int coun
|
||||||
float renderfx = RFX_NORMAL;
|
float renderfx = RFX_NORMAL;
|
||||||
string impactDecal = __NULL__;
|
string impactDecal = __NULL__;
|
||||||
|
|
||||||
/* pick a model between 0 and num) */
|
|
||||||
r = floor(random(0, modelcount));
|
|
||||||
|
|
||||||
/* two entries, always have to skip by 2 */
|
/* two entries, always have to skip by 2 */
|
||||||
fullline = mname = argv((r * 2));
|
if (modelcount < count) {
|
||||||
fadetime = stof(argv((r * 2) + 1));
|
int r = floor(random(0, modelcount));
|
||||||
|
fullline = mname = argv((r * 2));
|
||||||
|
fadetime = stof(argv((r * 2) + 1));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fullline = mname = argv((i * 2));
|
||||||
|
fadetime = stof(argv((i * 2) + 1));
|
||||||
|
}
|
||||||
|
|
||||||
p = tokenizebyseparator(mname, "#");
|
p = tokenizebyseparator(mname, "#");
|
||||||
|
|
||||||
/* special char # detected to designate model submodel count */
|
/* special char # detected to designate model submodel count */
|
||||||
|
@ -572,16 +740,30 @@ BreakModel_SpawnID(vector smins, vector smaxs, vector dir, float speed, int coun
|
||||||
gib.SetRenderFX(renderfx);
|
gib.SetRenderFX(renderfx);
|
||||||
gib.SetSize([0,0,0], [0,0,0]);
|
gib.SetSize([0,0,0], [0,0,0]);
|
||||||
gib.SetOrigin(endpos);
|
gib.SetOrigin(endpos);
|
||||||
makevectors(dir);
|
|
||||||
gib.velocity = (v_forward * speed) * 0.75;
|
if (usePhysics == false) {
|
||||||
gib.velocity[0] += (random() - 0.5) * (speed * 0.25);
|
makevectors(dir);
|
||||||
gib.velocity[1] += (random() - 0.5) * (speed * 0.25);
|
gib.velocity = (v_forward * speed) * 0.75;
|
||||||
gib.velocity[2] += (random() - 0.5) * (speed * 0.25);
|
gib.velocity[0] += (random() - 0.5) * (speed * 0.25);
|
||||||
gib.SetAngularVelocity(vectoangles(gib.velocity));
|
gib.velocity[1] += (random() - 0.5) * (speed * 0.25);
|
||||||
gib.SetMovetype(MOVETYPE_BOUNCE);
|
gib.velocity[2] += (random() - 0.5) * (speed * 0.25);
|
||||||
gib.SetSolid(SOLID_BBOX);
|
gib.SetAngularVelocity(vectoangles(gib.velocity));
|
||||||
|
gib.SetMovetype(MOVETYPE_BOUNCE);
|
||||||
|
gib.SetSolid(SOLID_BBOX);
|
||||||
|
} else {
|
||||||
|
gib.SetMovetype(MOVETYPE_PHYSICS);
|
||||||
|
gib.SetSolid(SOLID_NOT);
|
||||||
|
gib.mass = 1.0f;
|
||||||
|
gib.friction = 1.0f;
|
||||||
|
gib.bouncefactor = 0.9f;
|
||||||
|
gib.bouncestop = 0.1f / cvar("sv_gravity");
|
||||||
|
gib.geomtype = GEOMTYPE_TRIMESH;
|
||||||
|
gib.ApplyForceOffset(dir * speed, endpos);
|
||||||
|
}
|
||||||
|
|
||||||
gib.ScheduleThink(NSEntity::Destroy, fadetime);
|
gib.ScheduleThink(NSEntity::Destroy, fadetime);
|
||||||
gib.SetImpactDecal(impactDecal);
|
gib.SetImpactDecal(impactDecal);
|
||||||
|
print(sprintf("%S\n", mname));
|
||||||
|
|
||||||
#ifdef CLIENT
|
#ifdef CLIENT
|
||||||
gib.drawmask = MASK_ENGINE;
|
gib.drawmask = MASK_ENGINE;
|
||||||
|
@ -616,10 +798,49 @@ BreakModel_Receive(void)
|
||||||
speed = readfloat();
|
speed = readfloat();
|
||||||
count = readbyte();
|
count = readbyte();
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (index >= g_breakmodel_count) {
|
||||||
|
print(sprintf("^1Unable to spawn breakmodel of id %i. Not cached on client. (Client knows of %i)\n", index, g_breakmodel_count));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//print(sprintf("i: %i max: %i name: %S\n", index, g_breakmodel_count, g_breakmodel[index].name));
|
||||||
|
|
||||||
BreakModel_SpawnID(smins, smaxs, dir, speed, count, index);
|
BreakModel_SpawnID(smins, smaxs, dir, speed, count, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BreakModel_ReceiveClientData(void)
|
||||||
|
{
|
||||||
|
int addToCount = readbyte();
|
||||||
|
|
||||||
|
for (int i = 0; i < addToCount; i++) {
|
||||||
|
string modelName = modelnameforindex(readshort());
|
||||||
|
PropData_ForModel(modelName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
void
|
||||||
|
BreakModel_SendClientData(entity targetEnt)
|
||||||
|
{
|
||||||
|
int extraCount = g_breakmodel_count - g_breakmodel_end;
|
||||||
|
int startOffset = g_breakmodel_end;
|
||||||
|
|
||||||
|
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
||||||
|
WriteByte(MSG_MULTICAST, EV_BREAKMODELDATA);
|
||||||
|
WriteByte(MSG_MULTICAST, g_breakmodel_count - g_breakmodel_end);
|
||||||
|
|
||||||
|
//print(sprintf("%i %i\n", g_breakmodel_end, g_breakmodel_count));
|
||||||
|
|
||||||
|
for (int i = g_breakmodel_end; i < g_breakmodel_count; i++) {
|
||||||
|
WriteShort(MSG_MULTICAST, g_breakmodel[i].modelindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_entity = targetEnt;
|
||||||
|
multicast(g_vec_null, MULTICAST_ONE_R);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BreakModel_Spawn(vector smins, vector smaxs, vector dir, float speed, int count, string type)
|
BreakModel_Spawn(vector smins, vector smaxs, vector dir, float speed, int count, string type)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue