mirror of
https://github.com/nillerusr/source-engine.git
synced 2025-03-13 06:01:53 +00:00
309 lines
7.8 KiB
C++
309 lines
7.8 KiB
C++
#include "cbase.h"
|
|
#include "c_asw_door.h"
|
|
#include <vgui/ISurface.h>
|
|
#include <vgui_controls/Panel.h>
|
|
#include "vgui/IInput.h"
|
|
#include "engine/ivdebugoverlay.h"
|
|
#include "asw_shareddefs.h"
|
|
#include "effect_dispatch_data.h"
|
|
#include "c_te_effect_dispatch.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
IMPLEMENT_CLIENTCLASS_DT( C_ASW_Door, DT_ASW_Door, CASW_Door )
|
|
RecvPropFloat (RECVINFO(m_flTotalSealTime)),
|
|
RecvPropFloat (RECVINFO(m_flCurrentSealTime)),
|
|
RecvPropInt (RECVINFO(m_iDoorStrength)),
|
|
RecvPropInt (RECVINFO(m_iDoorType)),
|
|
RecvPropInt (RECVINFO(m_lifeState)),
|
|
RecvPropInt (RECVINFO(m_iHealth) ),
|
|
RecvPropBool (RECVINFO(m_bAutoOpen)),
|
|
RecvPropBool (RECVINFO(m_bBashable)),
|
|
RecvPropBool (RECVINFO(m_bShootable)),
|
|
RecvPropBool (RECVINFO(m_bCanCloseToWeld)),
|
|
RecvPropBool (RECVINFO(m_bRecommendedSeal)),
|
|
RecvPropBool (RECVINFO(m_bWasWeldedByMarine)),
|
|
RecvPropFloat (RECVINFO(m_fLastMomentFlipDamage)),
|
|
RecvPropVector (RECVINFO(m_vecClosedPosition)),
|
|
RecvPropBool (RECVINFO(m_bSkillMarineHelping)),
|
|
END_RECV_TABLE()
|
|
|
|
bool C_ASW_Door::s_bLoadedSealedIconTexture = false;
|
|
bool C_ASW_Door::s_bLoadedFullySealedIconTexture = false;
|
|
int C_ASW_Door::s_nSealedIconTextureID = -1;
|
|
int C_ASW_Door::s_nFullySealedIconTextureID = -1;
|
|
|
|
// for mousing over door health
|
|
CUtlVector<C_ASW_Door*> g_ClientDoorList;
|
|
|
|
C_ASW_Door::C_ASW_Door()
|
|
{
|
|
m_fLastWeldedTime = 0.0f;
|
|
|
|
Q_snprintf(m_szSealedIconTexture, sizeof(m_szSealedIconTexture), "vgui/swarm/UseIcons/UseIconDoorPartlySealed");
|
|
|
|
g_ClientDoorList.AddToTail(this);
|
|
}
|
|
|
|
C_ASW_Door::~C_ASW_Door()
|
|
{
|
|
g_ClientDoorList.FindAndRemove(this);
|
|
}
|
|
|
|
// returns how sealed this door is, from 0 to 1.0
|
|
float C_ASW_Door::GetSealAmount()
|
|
{
|
|
if (m_flTotalSealTime <= 0)
|
|
return 0;
|
|
|
|
return (m_flCurrentSealTime/m_flTotalSealTime);
|
|
}
|
|
|
|
int C_ASW_Door::GetSealedIconTextureID()
|
|
{
|
|
if (!s_bLoadedSealedIconTexture)
|
|
{
|
|
// load the portrait textures
|
|
s_nSealedIconTextureID = vgui::surface()->CreateNewTextureID();
|
|
vgui::surface()->DrawSetTextureFile( s_nSealedIconTextureID, m_szSealedIconTexture, true, false);
|
|
s_bLoadedSealedIconTexture = true;
|
|
}
|
|
|
|
return s_nSealedIconTextureID;
|
|
}
|
|
|
|
int C_ASW_Door::GetFullySealedIconTextureID()
|
|
{
|
|
if (!s_bLoadedFullySealedIconTexture)
|
|
{
|
|
s_nFullySealedIconTextureID = vgui::surface()->CreateNewTextureID();
|
|
vgui::surface()->DrawSetTextureFile( s_nFullySealedIconTextureID, "vgui/swarm/UseIcons/UseIconDoorFullySealed", true, false);
|
|
s_bLoadedFullySealedIconTexture = true;
|
|
}
|
|
|
|
return s_nFullySealedIconTextureID;
|
|
}
|
|
|
|
const char* C_ASW_Door::GetSealedIconText()
|
|
{
|
|
if ( gpGlobals->curtime > m_fLastWeldedTime + 1.0f )
|
|
{
|
|
if ( m_bWasWeldedByMarine )
|
|
{
|
|
if ( GetSealAmount() >= 1.0f )
|
|
{
|
|
return "#asw_door_fully_reinforced";
|
|
}
|
|
else if ( GetSealAmount() >= 0.5f )
|
|
{
|
|
return "#asw_door_reinforced";
|
|
}
|
|
}
|
|
|
|
return "#asw_door_sealed";
|
|
}
|
|
|
|
if ( m_bUnwelding )
|
|
{
|
|
return "#asw_door_unsealing";
|
|
}
|
|
|
|
if ( GetSealAmount() >= 0.5f )
|
|
{
|
|
return "#asw_door_reinforcing";
|
|
}
|
|
|
|
return "#asw_door_sealing";
|
|
}
|
|
|
|
|
|
bool C_ASW_Door::IsOpen()
|
|
{
|
|
Vector diff = GetAbsOrigin() - m_vecClosedPosition;
|
|
float dist = diff.LengthSqr();
|
|
return (dist > 2); // 2 to allow for network rounding...
|
|
}
|
|
|
|
bool C_ASW_Door::IsMoving()
|
|
{
|
|
Vector vel;
|
|
EstimateAbsVelocity(vel);
|
|
return vel.LengthSqr() > 0;
|
|
}
|
|
|
|
#define DOOR_CORNER_DISTANCE 62.0f
|
|
#define DOOR_HEIGHT 135.0f
|
|
|
|
Vector C_ASW_Door::GetWeldFacingPoint(C_BaseEntity* pOther)
|
|
{
|
|
// work out which side of the door the marine is on
|
|
Vector diff = pOther->GetAbsOrigin() - GetAbsOrigin();
|
|
VectorNormalize(diff);
|
|
QAngle angDoorFacing = GetAbsAngles();
|
|
Vector vecDoorFacing = vec3_origin;
|
|
AngleVectors(angDoorFacing, &vecDoorFacing);
|
|
bool bFrontSide = (DotProduct(vecDoorFacing, diff) > 0);
|
|
|
|
// depending on the side, get one of the corners
|
|
angDoorFacing.y -= bFrontSide ? 81 : 102;
|
|
AngleVectors(angDoorFacing, &vecDoorFacing);
|
|
Vector result = GetAbsOrigin() + vecDoorFacing * DOOR_CORNER_DISTANCE;
|
|
|
|
// correct by height
|
|
result.z += DOOR_HEIGHT * (1.0f - GetSealAmount());
|
|
|
|
return result;
|
|
}
|
|
|
|
Vector C_ASW_Door::GetSparkNormal( C_BaseEntity* pOther )
|
|
{
|
|
// work out which side of the door the marine is on
|
|
Vector diff = pOther->GetAbsOrigin() - GetAbsOrigin();
|
|
VectorNormalize(diff);
|
|
QAngle angDoorFacing = GetAbsAngles();
|
|
Vector vecDoorFacing = vec3_origin;
|
|
AngleVectors(angDoorFacing, &vecDoorFacing);
|
|
bool bFrontSide = (DotProduct(vecDoorFacing, diff) > 0);
|
|
|
|
if (bFrontSide)
|
|
return vecDoorFacing;
|
|
|
|
return -vecDoorFacing;
|
|
}
|
|
|
|
// checks the client door list for a door near this position
|
|
// NOTE: currently only returns damaged doors
|
|
#define ASW_DOOR_NEAR_PADDING 20
|
|
C_ASW_Door* C_ASW_Door::GetDoorNear(Vector vecSrc)
|
|
{
|
|
for (int i=0;i<g_ClientDoorList.Count();i++)
|
|
{
|
|
C_ASW_Door *pEnt = g_ClientDoorList[i];
|
|
int iDoorType;
|
|
if (!pEnt || pEnt->GetHealth() <= 0 || pEnt->GetHealthFraction(iDoorType) >= 1.0f)
|
|
continue;
|
|
|
|
Vector mins, maxs;
|
|
|
|
// get the size of the door
|
|
pEnt->GetRenderBoundsWorldspace(mins,maxs);
|
|
|
|
// pull out all 8 corners of this volume
|
|
Vector worldPos[8];
|
|
Vector screenPos[8];
|
|
worldPos[0] = mins;
|
|
worldPos[1] = mins; worldPos[1].x = maxs.x;
|
|
worldPos[2] = mins; worldPos[2].y = maxs.y;
|
|
worldPos[3] = mins; worldPos[3].z = maxs.z;
|
|
worldPos[4] = mins;
|
|
worldPos[5] = maxs; worldPos[5].x = mins.x;
|
|
worldPos[6] = maxs; worldPos[6].y = mins.y;
|
|
worldPos[7] = maxs; worldPos[7].z = mins.z;
|
|
|
|
// convert them to screen space
|
|
for (int k=0;k<8;k++)
|
|
{
|
|
debugoverlay->ScreenPosition( worldPos[k], screenPos[k] );
|
|
}
|
|
|
|
// find the rectangle bounding all screen space points
|
|
Vector topLeft = screenPos[0];
|
|
Vector bottomRight = screenPos[0];
|
|
for (int k=0;k<8;k++)
|
|
{
|
|
topLeft.x = MIN(screenPos[k].x, topLeft.x);
|
|
topLeft.y = MIN(screenPos[k].y, topLeft.y);
|
|
bottomRight.x = MAX(screenPos[k].x, bottomRight.x);
|
|
bottomRight.y = MAX(screenPos[k].y, bottomRight.y);
|
|
}
|
|
int BracketSize = 5; // todo: set by screen res?
|
|
|
|
// pad it a bit
|
|
topLeft.x -= BracketSize * 2;
|
|
topLeft.y -= BracketSize * 2;
|
|
bottomRight.x += BracketSize * 2;
|
|
bottomRight.y += BracketSize * 2;
|
|
|
|
// check if the cursor is inside this
|
|
int x, y;
|
|
vgui::input()->GetCursorPos( x, y );
|
|
|
|
if (x >= topLeft.x && x <= bottomRight.x &&
|
|
y >= topLeft.y && y <= bottomRight.y)
|
|
{
|
|
return pEnt;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
float C_ASW_Door::GetHealthFraction(int &iDoorType) const
|
|
{
|
|
if ( m_iDoorStrength == 0 ) // indestructable
|
|
{
|
|
iDoorType = 2;
|
|
return 1.0f;
|
|
}
|
|
if ( m_iDoorStrength == ASW_DOOR_NORMAL_HEALTH ) // normal
|
|
{
|
|
iDoorType = 0;
|
|
}
|
|
else
|
|
{
|
|
iDoorType = 1; // reinforced
|
|
}
|
|
|
|
return ( static_cast< float >( MAX( 0, m_iHealth ) ) - MIN( 0.0f, m_fLastMomentFlipDamage ) ) / static_cast< float >( m_iDoorStrength );
|
|
}
|
|
|
|
void C_ASW_Door::OnDataChanged( DataUpdateType_t type )
|
|
{
|
|
BaseClass::OnDataChanged( type );
|
|
|
|
if ( !IsAlive() && VPhysicsGetObject())
|
|
{
|
|
VPhysicsDestroyObject();
|
|
}
|
|
|
|
if ( m_flOldSealTime != m_flCurrentSealTime )
|
|
{
|
|
m_fLastWeldedTime = gpGlobals->curtime;
|
|
m_bUnwelding = ( m_flOldSealTime > m_flCurrentSealTime );
|
|
m_flOldSealTime = m_flCurrentSealTime;
|
|
}
|
|
}
|
|
|
|
void C_ASW_Door::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName )
|
|
{
|
|
Assert( pTrace->m_pEnt );
|
|
|
|
CBaseEntity *pEntity = pTrace->m_pEnt;
|
|
|
|
// Build the impact data
|
|
CEffectData data;
|
|
data.m_vOrigin = pTrace->endpos;
|
|
data.m_vStart = pTrace->startpos;
|
|
data.m_nSurfaceProp = pTrace->surface.surfaceProps;
|
|
if (!m_bShootable)
|
|
data.m_nSurfaceProp = physprops->GetSurfaceIndex("metal");
|
|
data.m_nDamageType = iDamageType;
|
|
data.m_nHitBox = pTrace->hitbox;
|
|
#ifdef CLIENT_DLL
|
|
data.m_hEntity = ClientEntityList().EntIndexToHandle( pEntity->entindex() );
|
|
#else
|
|
data.m_nEntIndex = pEntity->entindex();
|
|
#endif
|
|
|
|
// Send it on its way
|
|
if ( !pCustomImpactName )
|
|
{
|
|
DispatchEffect( "Impact", data );
|
|
}
|
|
else
|
|
{
|
|
DispatchEffect( pCustomImpactName, data );
|
|
}
|
|
}
|