You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
7.9 KiB
276 lines
7.9 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: The various ammo types for HL2 |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "props.h" |
|
#include "items.h" |
|
#include "item_dynamic_resupply.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
const char *pszItemCrateModelName[] = |
|
{ |
|
"models/items/item_item_crate.mdl", |
|
"models/items/item_beacon_crate.mdl", |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// A breakable crate that drops items |
|
//----------------------------------------------------------------------------- |
|
class CItem_ItemCrate : public CPhysicsProp |
|
{ |
|
public: |
|
DECLARE_CLASS( CItem_ItemCrate, CPhysicsProp ); |
|
DECLARE_DATADESC(); |
|
|
|
void Precache( void ); |
|
void Spawn( void ); |
|
|
|
virtual int ObjectCaps() { return BaseClass::ObjectCaps() | FCAP_WCEDIT_POSITION; }; |
|
|
|
virtual int OnTakeDamage( const CTakeDamageInfo &info ); |
|
|
|
void InputKill( inputdata_t &data ); |
|
|
|
virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ); |
|
virtual void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ); |
|
|
|
protected: |
|
virtual void OnBreak( const Vector &vecVelocity, const AngularImpulse &angVel, CBaseEntity *pBreaker ); |
|
|
|
private: |
|
// Crate types. Add more! |
|
enum CrateType_t |
|
{ |
|
CRATE_SPECIFIC_ITEM = 0, |
|
CRATE_TYPE_COUNT, |
|
}; |
|
|
|
enum CrateAppearance_t |
|
{ |
|
CRATE_APPEARANCE_DEFAULT = 0, |
|
CRATE_APPEARANCE_RADAR_BEACON, |
|
}; |
|
|
|
private: |
|
CrateType_t m_CrateType; |
|
string_t m_strItemClass; |
|
int m_nItemCount; |
|
string_t m_strAlternateMaster; |
|
CrateAppearance_t m_CrateAppearance; |
|
|
|
COutputEvent m_OnCacheInteraction; |
|
}; |
|
|
|
|
|
LINK_ENTITY_TO_CLASS(item_item_crate, CItem_ItemCrate); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Save/load: |
|
//----------------------------------------------------------------------------- |
|
BEGIN_DATADESC( CItem_ItemCrate ) |
|
|
|
DEFINE_KEYFIELD( m_CrateType, FIELD_INTEGER, "CrateType" ), |
|
DEFINE_KEYFIELD( m_strItemClass, FIELD_STRING, "ItemClass" ), |
|
DEFINE_KEYFIELD( m_nItemCount, FIELD_INTEGER, "ItemCount" ), |
|
DEFINE_KEYFIELD( m_strAlternateMaster, FIELD_STRING, "SpecificResupply" ), |
|
DEFINE_KEYFIELD( m_CrateAppearance, FIELD_INTEGER, "CrateAppearance" ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Kill", InputKill ), |
|
DEFINE_OUTPUT( m_OnCacheInteraction, "OnCacheInteraction" ), |
|
|
|
END_DATADESC() |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CItem_ItemCrate::Precache( void ) |
|
{ |
|
// Set this here to quiet base prop warnings |
|
PrecacheModel( pszItemCrateModelName[m_CrateAppearance] ); |
|
SetModel( pszItemCrateModelName[m_CrateAppearance] ); |
|
|
|
BaseClass::Precache(); |
|
if ( m_CrateType == CRATE_SPECIFIC_ITEM ) |
|
{ |
|
if ( NULL_STRING != m_strItemClass ) |
|
{ |
|
// Don't precache if this is a null string. |
|
UTIL_PrecacheOther( STRING(m_strItemClass) ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CItem_ItemCrate::Spawn( void ) |
|
{ |
|
if ( g_pGameRules->IsAllowedToSpawn( this ) == false ) |
|
{ |
|
UTIL_Remove( this ); |
|
return; |
|
} |
|
|
|
DisableAutoFade(); |
|
SetModelName( AllocPooledString( pszItemCrateModelName[m_CrateAppearance] ) ); |
|
|
|
if ( NULL_STRING == m_strItemClass ) |
|
{ |
|
Warning( "CItem_ItemCrate(%i): CRATE_SPECIFIC_ITEM with NULL ItemClass string (deleted)!!!\n", entindex() ); |
|
UTIL_Remove( this ); |
|
return; |
|
} |
|
|
|
Precache( ); |
|
SetModel( pszItemCrateModelName[m_CrateAppearance] ); |
|
AddEFlags( EFL_NO_ROTORWASH_PUSH ); |
|
BaseClass::Spawn( ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &data - |
|
//----------------------------------------------------------------------------- |
|
void CItem_ItemCrate::InputKill( inputdata_t &data ) |
|
{ |
|
UTIL_Remove( this ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Item crates blow up immediately |
|
//----------------------------------------------------------------------------- |
|
int CItem_ItemCrate::OnTakeDamage( const CTakeDamageInfo &info ) |
|
{ |
|
if ( info.GetDamageType() & DMG_AIRBOAT ) |
|
{ |
|
CTakeDamageInfo dmgInfo = info; |
|
dmgInfo.ScaleDamage( 10.0 ); |
|
return BaseClass::OnTakeDamage( dmgInfo ); |
|
} |
|
|
|
return BaseClass::OnTakeDamage( info ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CItem_ItemCrate::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) |
|
{ |
|
float flDamageScale = 1.0f; |
|
if ( FClassnameIs( pEvent->pEntities[!index], "prop_vehicle_airboat" ) || |
|
FClassnameIs( pEvent->pEntities[!index], "prop_vehicle_jeep" ) ) |
|
{ |
|
flDamageScale = 100.0f; |
|
} |
|
|
|
m_impactEnergyScale *= flDamageScale; |
|
BaseClass::VPhysicsCollision( index, pEvent ); |
|
m_impactEnergyScale /= flDamageScale; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CItem_ItemCrate::OnBreak( const Vector &vecVelocity, const AngularImpulse &angImpulse, CBaseEntity *pBreaker ) |
|
{ |
|
// FIXME: We could simply store the name of an entity to put into the crate |
|
// as a string entered in by worldcraft. Should we? I'd do it for sure |
|
// if it was easy to get a dropdown with all entity types in it. |
|
|
|
m_OnCacheInteraction.FireOutput(pBreaker,this); |
|
|
|
for ( int i = 0; i < m_nItemCount; ++i ) |
|
{ |
|
CBaseEntity *pSpawn = NULL; |
|
switch( m_CrateType ) |
|
{ |
|
case CRATE_SPECIFIC_ITEM: |
|
pSpawn = CreateEntityByName( STRING(m_strItemClass) ); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
|
|
if ( !pSpawn ) |
|
return; |
|
|
|
// Give a little randomness... |
|
Vector vecOrigin; |
|
CollisionProp()->RandomPointInBounds( Vector(0.25, 0.25, 0.25), Vector( 0.75, 0.75, 0.75 ), &vecOrigin ); |
|
pSpawn->SetAbsOrigin( vecOrigin ); |
|
|
|
QAngle vecAngles; |
|
vecAngles.x = random->RandomFloat( -20.0f, 20.0f ); |
|
vecAngles.y = random->RandomFloat( 0.0f, 360.0f ); |
|
vecAngles.z = random->RandomFloat( -20.0f, 20.0f ); |
|
pSpawn->SetAbsAngles( vecAngles ); |
|
|
|
Vector vecActualVelocity; |
|
vecActualVelocity.Random( -10.0f, 10.0f ); |
|
// vecActualVelocity += vecVelocity; |
|
pSpawn->SetAbsVelocity( vecActualVelocity ); |
|
|
|
QAngle angVel; |
|
AngularImpulseToQAngle( angImpulse, angVel ); |
|
pSpawn->SetLocalAngularVelocity( angVel ); |
|
|
|
// If we're creating an item, it can't be picked up until it comes to rest |
|
// But only if it wasn't broken by a vehicle |
|
CItem *pItem = dynamic_cast<CItem*>(pSpawn); |
|
if ( pItem && !pBreaker->GetServerVehicle()) |
|
{ |
|
pItem->ActivateWhenAtRest(); |
|
} |
|
|
|
pSpawn->Spawn(); |
|
|
|
// Avoid missing items drops by a dynamic resupply because they don't think immediately |
|
if ( FClassnameIs( pSpawn, "item_dynamic_resupply" ) ) |
|
{ |
|
if ( m_strAlternateMaster != NULL_STRING ) |
|
{ |
|
DynamicResupply_InitFromAlternateMaster( pSpawn, m_strAlternateMaster ); |
|
} |
|
if ( i == 0 ) |
|
{ |
|
pSpawn->AddSpawnFlags( SF_DYNAMICRESUPPLY_ALWAYS_SPAWN ); |
|
} |
|
pSpawn->SetNextThink( gpGlobals->curtime ); |
|
} |
|
} |
|
} |
|
|
|
void CItem_ItemCrate::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason ) |
|
{ |
|
BaseClass::OnPhysGunPickup( pPhysGunUser, reason ); |
|
|
|
m_OnCacheInteraction.FireOutput( pPhysGunUser, this ); |
|
|
|
if ( reason == PUNTED_BY_CANNON && m_CrateAppearance != CRATE_APPEARANCE_RADAR_BEACON ) |
|
{ |
|
Vector vForward; |
|
AngleVectors( pPhysGunUser->EyeAngles(), &vForward, NULL, NULL ); |
|
Vector vForce = Pickup_PhysGunLaunchVelocity( this, vForward, PHYSGUN_FORCE_PUNTED ); |
|
AngularImpulse angular = AngularImpulse( 0, 0, 0 ); |
|
|
|
IPhysicsObject *pPhysics = VPhysicsGetObject(); |
|
|
|
if ( pPhysics ) |
|
{ |
|
pPhysics->AddVelocity( &vForce, &angular ); |
|
} |
|
|
|
TakeDamage( CTakeDamageInfo( pPhysGunUser, pPhysGunUser, GetHealth(), DMG_GENERIC ) ); |
|
} |
|
}
|
|
|