Paranoia2/dlls/func_physbox.cpp

576 lines
14 KiB
C++

/*********************************************************
* Closed mod Physical entity: Original code of Nucleo *
**********************************************************/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "saverestore.h"
#include "func_break.h"
#include "decals.h"
#include "explode.h"
extern DLL_GLOBAL Vector g_vecAttackDir;
#define M_PI 3.141592653589793238462643 //NCL: Correct It!
// NCL: Based On "func_breakable"
class CPhy : public CBreakable
{
public:
void Spawn ( void );
void Precache( void );
void EXPORT PushableThink( void );
void Touch ( CBaseEntity *pOther );
void Move( CBaseEntity *pMover, int push );
void KeyValue( KeyValueData *pkvd );
void Solid( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT StopSound( void );
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_CONTINUOUS_USE; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
void SetModelCollisionBox( void );
void TestBeam( Vector org, Vector end, Vector color, int life, int width );
inline float MaxSpeed( void ) { return m_maxSpeed; }
// NCL: Если стоит флаг Breakable
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
static TYPEDESCRIPTION m_SaveData[];
int m_lastSound;
float m_maxSpeed;
float m_soundTime;
};
TYPEDESCRIPTION CPhy::m_SaveData[] =
{
DEFINE_FIELD( CPhy, m_maxSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CPhy, m_soundTime, FIELD_TIME ),
};
IMPLEMENT_SAVERESTORE( CPhy, CBreakable );
// NCL: Temporary name
LINK_ENTITY_TO_CLASS( func_physbox, CPhy );
void CPhy :: Spawn( void )
{
// NCL: Brushes only
Vector vecMins = pev->mins;
Vector vecMaxs = pev->maxs;
CBreakable::Spawn();
pev->movetype = MOVETYPE_BOUNCE;//MOVETYPE_PUSHSTEP;
pev->solid = SOLID_SLIDEBOX;
// NCL: UNDONE! If developer sets path to the model file
SET_MODEL( ENT(pev), STRING(pev->model) );
// NCL: Model needs collision! I Can do it, but i'm lazy... =)
if ( pev->friction > 399 )
pev->friction = 399;
m_maxSpeed = 400 - pev->friction;
SetBits( pev->flags, FL_FLOAT );
pev->friction = 0.5;
pev->gravity = 1;
pev->origin.z += 1; // NCL: Pick up it to fix collision bug
UTIL_SetOrigin( this, pev->origin );
SetThink(&CPhy:: PushableThink );
pev->nextthink = 0.1;
// Multiply by area of the box's cross-section (assume 1000 units^3 standard volume)
pev->skin = ( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005;
m_soundTime = 0;
}
void CPhy::SetModelCollisionBox(void)
{
}
void CPhy :: Precache( void )
{
//PRECACHE_MODEL(pev->model); // Temporary unused.
CBreakable::Precache( );
}
void CPhy :: KeyValue( KeyValueData *pkvd )
{
// NCL: UnDone! Physics needs more parameters!
if ( FStrEq(pkvd->szKeyName, "size") ) // NCL: Id developer sets size manually
{
int bbox = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
SetModelCollisionBox();
}
else if ( FStrEq(pkvd->szKeyName, "skin") ) // NCL: Brushes needs a skinning?
{
pev->skin = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBreakable::KeyValue( pkvd );
}
void CPhy :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !pActivator || !pActivator->IsPlayer() )
{
this->CBreakable::Use( pActivator, pCaller, useType, value );
return;
}
if ( pActivator->pev->velocity != g_vecZero )
Move( pActivator, 0 );
}
/*
===================
AngleBetweenVectors
===================
*/
float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 )
{
float angle;
float l1 = v1.Length();
float l2 = v2.Length();
if ( !l1 || !l2 )
return 0.0f;
angle = acos( DotProduct( v1, v2 ) / (l1*l2) );
angle = ( angle * 180.0f ) / M_PI;
return angle;
}
void NormalizeAngles( float *angles )
{
int i;
// NCL: Normalize angles. It needs to update.
for ( i = 0; i < 3; i++ )
{
if ( angles[i] > 180.0 )
{
angles[i] -= 360.0;
}
else if ( angles[i] < -180.0 )
{
angles[i] += 360.0;
}
}
}
void CPhy :: PushableThink( void )
{
// pev->velocity = pev->velocity * 0.8;
// pev->avelocity = pev->avelocity * 0.8;
// ALERT( at_debug, "Angles yaw: %3.2f\n", pev->angles.y );
/* if( pev->angles.x >= 360 )
pev->angles.x -= 360;
if( pev->angles.x >= -360 )
pev->angles.x += 360;*/
//if( pev->flags & FL_ONGROUND )
//{
// pev->avelocity = pev->avelocity;// * 5.5;
//}
// SetNextThink( 0.1 );
pev->nextthink = 0.1;
}
void CPhy :: Touch( CBaseEntity *pOther )
{
Vector savedangles = Vector( 0, 0, 0 );
int negate = 0;
TraceResult tr;
// look down directly to know the surface we're lying.
UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,64), ignore_monsters, edict(), &tr );
pev->velocity = pev->velocity * 0.8;
// pev->avelocity = pev->avelocity * 0.5;
if( !(pev->flags & FL_ONGROUND) )
{
//pev->avelocity.x = RANDOM_FLOAT( -400, 400 );// NCL: Enable it to fun =)
//NCL: no sound, temporary.
if (pev->frags == 0)
{
// You can place sounds here...
}
}
else
/******
This code is nice, but has a bug:
The angles of the entity it's normalized, but if you touch or move the entity, and if it have another initial
angle, the entity will move too quickly in the reverse angle.
Look that:
1- We have a stand barrel.
------
||||||
| |
| |
| |
------
2- and you hit the barrel and the barrel fall of and it's lie on the ground
-----------
| ||
| ||
-----------
3- Well, do a simple touch to the barrel...
-----------
|| |
|| |
-----------
If you have a barrel, don't make any diference, but if you have a more complex object (a monitor i suposed),
you will see the bug.
It's too hard to explain, you need see it...
******/
{
for( int i = 0; i<3; i++ )
{
if( pev->angles.x < 0 )
negate = 1;
if( fabs(pev->angles.x) < 45 )
savedangles.x = 0;
else if( fabs(pev->angles.x) >= 45 && fabs(pev->angles.x) <= 135 )
savedangles.x = 90;
else if( fabs(pev->angles.x) > 135 && fabs(pev->angles.x) <= 180 )
savedangles.x = 180;
}
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795 //NCL: Correct It!
#endif
#define ang2rad (2 * M_PI / 360)
if ( tr.flFraction < 1.0 )
{
Vector forward, right, angdir, angdiry;
Vector Angles = pev->angles;
NormalizeAngles( Angles );
UTIL_MakeVectorsPrivate( Angles, forward, right, NULL );
angdir = forward;
Vector left = -right;
angdiry = left;
pev->angles.x = -UTIL_VecToAngles( angdir - DotProduct(angdir, tr.vecPlaneNormal) * tr.vecPlaneNormal).x;
pev->angles.y = UTIL_VecToAngles( angdir - DotProduct(angdir, tr.vecPlaneNormal) * tr.vecPlaneNormal).y;
pev->angles.z = UTIL_VecToAngles( angdiry - DotProduct(angdiry, tr.vecPlaneNormal) * tr.vecPlaneNormal).x;
pev->angles.z = UTIL_VecToAngles( angdiry - DotProduct(angdiry, tr.vecPlaneNormal) * right ).x;
}
#undef ang2rad
if( negate )
pev->angles.x -= savedangles.x;
else
pev->angles.x += savedangles.x;
}
if ( FClassnameIs( pOther->pev, "worldspawn" ) )
return;
Move( pOther, 1 );
}
void CPhy :: Move( CBaseEntity *pOther, int push )
{
entvars_t* pevToucher = pOther->pev;
int playerTouch = 0;
// Is entity standing on this pushable ?
if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev )
{
// Only push if floating
if ( pev->waterlevel > 0 && pev->watertype > CONTENT_FLYFIELD)
pev->velocity.z += pevToucher->velocity.z * 0.1;
return;
}
if ( pOther->IsPlayer() )
{
if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull)
return;
playerTouch = 1;
}
float factor;
if ( playerTouch )
{
if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water
{
if ( pev->waterlevel < 1 || pev->watertype <= CONTENT_FLYFIELD)
// {
// pOther->TakeDamage(pev, pev, 30, DMG_PARALYZE | DMG_NEVERGIB);
return;
// }
else
// {
factor = 0.1;
// }
}
else
factor = 1;
}
else
factor = 0.25;
if (!push)
factor = factor*0.1;
pev->velocity.x += pevToucher->velocity.x * factor;
pev->velocity.y += pevToucher->velocity.y * factor;
float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y );
if ( push && (length > MaxSpeed()) )
{
pev->velocity.x = (pev->velocity.x * MaxSpeed() / length );
pev->velocity.y = (pev->velocity.y * MaxSpeed() / length );
}
if ( playerTouch )
{
pevToucher->velocity.x = pev->velocity.x;
pevToucher->velocity.y = pev->velocity.y;
if ( (gpGlobals->time - m_soundTime) > 0.7 )
{
m_soundTime = gpGlobals->time;
if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) )
{
/******
Sys:
A big hack...
When you move the entity, it will make a sound.
There are 6 materials type:
-No defined (no material) The entity doesn't make any sound.
-Metal (metal rough sound)
-Plaster (a plastic tube sound)
-Glass (UNDONE: glass move sound??)
-Cement (concrete sound)
-Wood (wood sound)
*******/
if (pev->frags == 0)
{
//no sound
}
if (pev->frags == 1) //metal
{
}
if (pev->frags == 2) //plaster
{
}
if (pev->frags == 3) { }//glass
if (pev->frags == 4) //cemento
{
}
if (pev->frags == 5) //wood
{
}
// SetThink( StopSound );
// pev->nextthink = 0.1;
}
}
}
}
#if 0
void CPhy::StopSound( void )
{
Vector dist = pev->oldorigin - pev->origin;
if ( dist.Length() <= 0 )
STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] );
}
#endif
void CPhy :: TestBeam( Vector org, Vector end, Vector color, int life, int width )
{
extern short g_sModelIndexLaser;
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_BEAMPOINTS );
WRITE_COORD( org.x );
WRITE_COORD( org.y );
WRITE_COORD( org.z );
WRITE_COORD( end.x );
WRITE_COORD( end.y );
WRITE_COORD( end.z );
WRITE_SHORT( g_sModelIndexLaser );
WRITE_BYTE( 0 ); // framerate
WRITE_BYTE( 0 ); // framerate
WRITE_BYTE( life ); // life
WRITE_BYTE( width ); // width
WRITE_BYTE( 0 ); // noise
WRITE_BYTE( color.x ); // r, g, b
WRITE_BYTE( color.y ); // r, g, b
WRITE_BYTE( color.z ); // r, g, b
WRITE_BYTE( 160 ); // brightness
WRITE_BYTE( 0 ); // speed
MESSAGE_END();
}
int CPhy :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
Vector vecDir, r, anorm, rforward, rup, rright;
float a;
float force = flDamage * 10;
TraceResult trace = UTIL_GetGlobalTrace( );
UTIL_MakeVectors( pev->angles );
// grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit).
vecDir = r = Vector( 0, 0, 0 );
if (!FNullEnt( pevInflictor ))
{
if ( FClassnameIs( pevInflictor, "projectile" ) )
pevInflictor = VARS( pevInflictor->owner );
CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor );
if (pInflictor)
{
vecDir = g_vecAttackDir = ( trace.vecEndPos - pInflictor->Center() ).Normalize();
r = ( trace.vecEndPos - Center() ).Normalize();
}
}
anorm = UTIL_VecToAngles( r );
NormalizeAngles( r );
anorm.x = -anorm.x;
UTIL_MakeVectorsPrivate( anorm, rforward, rright, rup );
if (pev->frags == 1) //metal
{
//if ( bitsDamageType & (DMG_BULLET | DMG_CLUB) )
if ( ( bitsDamageType & DMG_BULLET)|| ( bitsDamageType & DMG_CLUB) )
{
UTIL_Ricochet( trace.vecEndPos, 0.5 );
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "fisica/metal/b_impact1.wav", 0.9, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "fisica/metal/b_impact2.wav", 0.9, ATTN_NORM); break;
case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "fisica/metal/b_impact3.wav", 0.9, ATTN_NORM); break;
}
//int color, int count, int speed, int velocityRange//PARAMs
// StreakSplash( trace.vecEndPos, trace.vecPlaneNormal, 6, 20, 50, 400 );//REFERENCE
// if (RANDOM_LONG( 0, 99 ) < 40)
// UTIL_Sparks( trace.vecEndPos, trace.vecPlaneNormal, 0, 5, 500, 500 );//chispas
// UTIL_Sparks( trace.vecEndPos, trace.vecPlaneNormal, 9, 5, 5, 100 );//puntos
// UTIL_Sparks( trace.vecEndPos, trace.vecPlaneNormal, 0, 5, 500, 20 );//chispas
}
}
if (pev->frags == 3) //glass
UTIL_Ricochet( trace.vecEndPos, 0.5 );
if (pev->frags == 4) //cement
UTIL_Sparks( trace.vecEndPos );
if (pev->frags == 5) //wood
{
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "debris/wood1.wav", 0.9, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "debris/wood2.wav", 0.9, ATTN_NORM); break;
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "debris/wood3.wav", 0.9, ATTN_NORM); break;
}
}
// if ( bitsDamageType & DMG_BULLET )
/*******
Sys: What the ....
If the material is "plaster" let's do more movement.
*******/
//if (pev->frags == 2) //plastico
//{
force *= 0.8;
pev->avelocity.z = cos( AngleBetweenVectors( vecDir, rup ) ) * force * 1;
//}
//else// Isn't plaster
//{
// if ( ( bitsDamageType & DMG_BULLET)|| ( bitsDamageType & DMG_CLUB) )
// force *= 0.5;
//}
pev->flags &= ~FL_ONGROUND;
//pev->origin.z += 1;
pev->avelocity.x = cos( AngleBetweenVectors( vecDir, rup ) ) * 100;
pev->avelocity.y = cos( AngleBetweenVectors( vecDir, -rright ) ) * 200;
// pev->avelocity.z = cos( AngleBetweenVectors( vecDir, -rup ) ) * 200;
// pev->avelocity.z = cos( AngleBetweenVectors( vecDir, rup ) ) * force * 2;//fooz
// pev->avelocity.z = sin( AngleBetweenVectors( vecDir, rup ) ) * force * 2;//fooz
ALERT( at_console, "X : %3.1f %3.1f° Y: %3.1f %3.1f°\n", pev->avelocity.x, AngleBetweenVectors( vecDir, rup ), pev->avelocity.y, AngleBetweenVectors( vecDir, -rright ) );
pev->velocity = pev->velocity /*+ gpGlobals->v_up * force * RANDOM_FLOAT( 0, 0.5 )*/ + vecDir * force * RANDOM_FLOAT( 0.5, 1.0 );
pev->velocity = pev->velocity + gpGlobals->v_up * force * RANDOM_FLOAT( 0, 0.5 ) + vecDir * force * RANDOM_FLOAT( 0.5, 1.0 );
//if ( pev->spawnflags & SF_PUSH_BREAKABLE )
// return CBreakable::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
return 1;
}