Some Beginner-Problems with Entities etc.

G

Gc-Design

Guest
Hi there!

I'm a rather beginner in Source Modding and just at "my first steps" in the SDK. Now I've got some problems and it would be great if someone could help me at least with to of them.

The 1. one:
I began with the "my first Model Entity" Example and then customized it a bit to have a combine console (combine_interface), which theoratically should give, you for a start, just a weapon (here the "AR2"), when you use it (press the use button like at a health charger).

Now here's what I've made:
Code:
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ========
//
// Purpose: Terminal Screen from where the player can buys equipment.
//
//
//=============================================================================

#include "cbase.h"

class CPropTerminal: public CBaseAnimating
{
public:
    DECLARE_CLASS( CPropTerminal, CBaseAnimating );
    DECLARE_DATADESC();

    void Spawn( void );
    void Precache( void );

    void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );

    // Input functions
    void InputToggle( inputdata_t &inputData );

private:

    bool    m_bActive;
    float    m_flNextChangeTime;
};

LINK_ENTITY_TO_CLASS( prop_terminal, CPropTerminal );

// Start of our data description for the class
BEGIN_DATADESC( CPropTerminal )
    
    // Save/restore our active state
    DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ),
    DEFINE_FIELD( m_flNextChangeTime, FIELD_TIME ),

    // Links our input name from Hammer to our input member function
    DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),

END_DATADESC()

// Name of our entity's model
#define    ENTITY_MODEL    "models/props_combine/combine_interface002.mdl"

//-----------------------------------------------------------------------------
// Purpose: Precache assets used by the entity
//-----------------------------------------------------------------------------
void CPropTerminal::Precache( void )
{
    PrecacheModel( ENTITY_MODEL );
}

//-----------------------------------------------------------------------------
// Purpose: Sets up the entity's initial state
//-----------------------------------------------------------------------------
void CPropTerminal::Spawn( void )
{
    Precache();

    SetModel( ENTITY_MODEL );
    SetSolid( SOLID_VPHYSICS );
    //UTIL_SetSize( this, -Vector(20,20,20), Vector(20,20,20) );

    m_bActive = false;
}

//-----------------------------------------------------------------------------
// Purpose: Toggle the movement of the entity
//-----------------------------------------------------------------------------
void CPropTerminal::InputToggle( inputdata_t &inputData )
{
    // Toggle our active state
    if ( !m_bActive )
    {
        m_bActive = true;
    }
    else
    {
        m_bActive = false;
    }
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : *pActivator -
//            *pCaller -
//            useType -
//            value -
//-----------------------------------------------------------------------------
void CPropTerminal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
    CBasePlayer *pPlayer = ToBasePlayer( pActivator );
    if ( pPlayer )
    {
        /*
        if ( HasSpawnFlags( SF_PHYSPROP_ENABLE_PICKUP_OUTPUT ) )
        {
            m_OnPlayerUse.FireOutput( this, this );
        }

        pPlayer->PickupObject( this );
        */
        pPlayer->GiveNamedItem( "weapon_ar2" );
    }
}

Now my actual problem is that when I try to use it just in a test map, nothing happens. As it's now you could use it the same way as a prop_static... :|
There are also no warnings or errors when I compile it.



Now to my 2nd Problem:
I tried to make also a freezer - weapon (like in 17 other mods lol) and took the weapon_pistol.cpp from the game_shared/hl2mp folder (after I figured out that only this file is used in both dll's and not the one from dll/hl2) and copied it. Renamed it to weapon_freezer.cpp and added it to the resourceses of both dll's.
Then I began to modify it and also changed "PrimaryFire" completly - similar to the code of weapon_physcannon - so it searches for a physics-entity in front of the gun which get's freezed then.

Here's the code:
Code:
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================//

#include "cbase.h"
#include "npcevent.h"
#include "in_buttons.h"

#ifdef CLIENT_DLL
	#include "c_hl2mp_player.h"
#else
	#include "hl2mp_player.h"
#endif

#include "weapon_hl2mpbasehlmpcombatweapon.h"

#define	PISTOL_FASTEST_REFIRE_TIME		0.1f
#define	PISTOL_FASTEST_DRY_REFIRE_TIME	0.2f

#define	PISTOL_ACCURACY_SHOT_PENALTY_TIME		0.2f	// Applied amount of time each shot adds to the time we must recover from
#define	PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME	1.5f	// Maximum penalty to deal out

#ifdef CLIENT_DLL
#define CWeaponFreezer C_WeaponFreezer
#endif


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// this will hit skip the pass entity, but not anything it owns 
// (lets player grab own grenades)
class CTraceFilterNoOwnerTest : public CTraceFilterSimple
{
public:
	DECLARE_CLASS( CTraceFilterNoOwnerTest, CTraceFilterSimple );
	
	CTraceFilterNoOwnerTest( const IHandleEntity *passentity, int collisionGroup )
		: CTraceFilterSimple( NULL, collisionGroup ), m_pPassNotOwner(passentity)
	{
	}
	
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
	{
		if ( pHandleEntity != m_pPassNotOwner )
			return BaseClass::ShouldHitEntity( pHandleEntity, contentsMask );

		return false;
	}

protected:
	const IHandleEntity *m_pPassNotOwner;
};


//-----------------------------------------------------------------------------
// CWeaponFreezer
//-----------------------------------------------------------------------------

class CWeaponFreezer : public CBaseHL2MPCombatWeapon
{
public:
	DECLARE_CLASS( CWeaponFreezer, CBaseHL2MPCombatWeapon );

	CWeaponFreezer(void);

	DECLARE_NETWORKCLASS(); 
	DECLARE_PREDICTABLE();

	void	Precache( void );
	void	ItemPostFrame( void );
	void	ItemPreFrame( void );
	void	ItemBusyFrame( void );
	void	PrimaryAttack( void );
	void	AddViewKick( void );
	void	DryFire( void );

	void	UpdatePenaltyTime( void );

	Activity	GetPrimaryAttackActivity( void );

	virtual bool Reload( void );

	virtual const Vector& GetBulletSpread( void )
	{		
		static Vector cone;

		float ramp = RemapValClamped(	m_flAccuracyPenalty, 
											0.0f, 
											PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME, 
											0.0f, 
											1.0f ); 

			// We lerp from very accurate to inaccurate over time
		VectorLerp( VECTOR_CONE_1DEGREES, VECTOR_CONE_6DEGREES, ramp, cone );

		return cone;
	}
	
	virtual int	GetMinBurst() 
	{ 
		return 1; 
	}

	virtual int	GetMaxBurst() 
	{ 
		return 3; 
	}

	virtual float GetFireRate( void ) 
	{
		return 0.5f; 
	}
	
#ifndef CLIENT_DLL
	DECLARE_ACTTABLE();
#endif

private:
	CNetworkVar( float,	m_flSoonestPrimaryAttack );
	CNetworkVar( float,	m_flLastAttackTime );
	CNetworkVar( float,	m_flAccuracyPenalty );
	CNetworkVar( int,	m_nNumShotsFired );

private:
	CWeaponFreezer( const CWeaponFreezer & );
};

IMPLEMENT_NETWORKCLASS_ALIASED( WeaponFreezer, DT_WeaponFreezer )

BEGIN_NETWORK_TABLE( CWeaponFreezer, DT_WeaponFreezer )
#ifdef CLIENT_DLL
	RecvPropTime( RECVINFO( m_flSoonestPrimaryAttack ) ),
	RecvPropTime( RECVINFO( m_flLastAttackTime ) ),
	RecvPropFloat( RECVINFO( m_flAccuracyPenalty ) ),
	RecvPropInt( RECVINFO( m_nNumShotsFired ) ),
#else
	SendPropTime( SENDINFO( m_flSoonestPrimaryAttack ) ),
	SendPropTime( SENDINFO( m_flLastAttackTime ) ),
	SendPropFloat( SENDINFO( m_flAccuracyPenalty ) ),
	SendPropInt( SENDINFO( m_nNumShotsFired ) ),
#endif
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CWeaponFreezer )
END_PREDICTION_DATA()

LINK_ENTITY_TO_CLASS( weapon_freezer, CWeaponFreezer );
PRECACHE_WEAPON_REGISTER( weapon_freezer );

#ifndef CLIENT_DLL
acttable_t CWeaponFreezer::m_acttable[] = 
{
	{ ACT_HL2MP_IDLE,					ACT_HL2MP_IDLE_PISTOL,					false },
	{ ACT_HL2MP_RUN,					ACT_HL2MP_RUN_PISTOL,					false },
	{ ACT_HL2MP_IDLE_CROUCH,			ACT_HL2MP_IDLE_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_WALK_CROUCH,			ACT_HL2MP_WALK_CROUCH_PISTOL,			false },
	{ ACT_HL2MP_GESTURE_RANGE_ATTACK,	ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,	false },
	{ ACT_HL2MP_GESTURE_RELOAD,			ACT_HL2MP_GESTURE_RELOAD_PISTOL,		false },
	{ ACT_HL2MP_JUMP,					ACT_HL2MP_JUMP_PISTOL,					false },
	{ ACT_RANGE_ATTACK1,				ACT_RANGE_ATTACK_PISTOL,				false },
};


IMPLEMENT_ACTTABLE( CWeaponFreezer );

#endif

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeaponFreezer::CWeaponFreezer( void )
{
	m_flSoonestPrimaryAttack = gpGlobals->curtime;
	m_flAccuracyPenalty = 0.0f;

	m_fMinRange1		= 24;
	m_fMaxRange1		= 1500;
	m_fMinRange2		= 24;
	m_fMaxRange2		= 200;

	m_bFiresUnderwater	= true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponFreezer::Precache( void )
{
	BaseClass::Precache();
}


//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponFreezer::DryFire( void )
{
	WeaponSound( EMPTY );
	SendWeaponAnim( ACT_VM_DRYFIRE );
	
	m_flSoonestPrimaryAttack	= gpGlobals->curtime + PISTOL_FASTEST_DRY_REFIRE_TIME;
	m_flNextPrimaryAttack		= gpGlobals->curtime + SequenceDuration();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponFreezer::PrimaryAttack( void )
{
    CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );

	if ( !pPlayer )
		return;
	
	Vector forward;
	pPlayer->EyeVectors( &forward );

	// Setup our positions
	Vector	start = pPlayer->Weapon_ShootPosition();
	//float	testLength = TraceLength() * 4.0f;
	float	testLength = 10.0f * 4.0f;
	Vector	end = start + forward * testLength;

    // Try to find an object by looking straight ahead
	trace_t tr;
	CTraceFilterNoOwnerTest filter( pPlayer, COLLISION_GROUP_NONE );
	UTIL_TraceLine( start, end, MASK_SHOT|CONTENTS_GRATE, &filter, &tr );
	
	// Try again with a hull trace
	if ( ( tr.fraction == 1.0 ) || ( tr.m_pEnt == NULL ) || ( tr.m_pEnt->IsWorld() ) )
	{
		UTIL_TraceHull( start, end, -Vector(4,4,4), Vector(4,4,4), MASK_SHOT|CONTENTS_GRATE, &filter, &tr );
	}

    if ( !tr.m_pEnt )
	    return;

	IPhysicsObject *pObj = tr.m_pEnt->VPhysicsGetObject();
	if ( !pObj )
		return;
    
	{
		pObj->EnableMotion( false );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponFreezer::UpdatePenaltyTime( void )
{
	CBasePlayer *pOwner = ToBasePlayer( GetOwner() );

	if ( pOwner == NULL )
		return;

	// Check our penalty time decay
	if ( ( ( pOwner->m_nButtons & IN_ATTACK ) == false ) && ( m_flSoonestPrimaryAttack < gpGlobals->curtime ) )
	{
		m_flAccuracyPenalty -= gpGlobals->frametime;
		m_flAccuracyPenalty = clamp( m_flAccuracyPenalty, 0.0f, PISTOL_ACCURACY_MAXIMUM_PENALTY_TIME );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponFreezer::ItemPreFrame( void )
{
	UpdatePenaltyTime();

	BaseClass::ItemPreFrame();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponFreezer::ItemBusyFrame( void )
{
	UpdatePenaltyTime();

	BaseClass::ItemBusyFrame();
}

//-----------------------------------------------------------------------------
// Purpose: Allows firing as fast as button is pressed
//-----------------------------------------------------------------------------
void CWeaponFreezer::ItemPostFrame( void )
{
	BaseClass::ItemPostFrame();

	if ( m_bInReload )
		return;
	
	CBasePlayer *pOwner = ToBasePlayer( GetOwner() );

	if ( pOwner == NULL )
		return;
	
	if ( pOwner->m_nButtons & IN_ATTACK2 )
	{
		m_flLastAttackTime = gpGlobals->curtime + PISTOL_FASTEST_REFIRE_TIME;
		m_flSoonestPrimaryAttack = gpGlobals->curtime + PISTOL_FASTEST_REFIRE_TIME;
		m_flNextPrimaryAttack = gpGlobals->curtime + PISTOL_FASTEST_REFIRE_TIME;
	}

	//Allow a refire as fast as the player can click
	if ( ( ( pOwner->m_nButtons & IN_ATTACK ) == false ) && ( m_flSoonestPrimaryAttack < gpGlobals->curtime ) )
	{
		m_flNextPrimaryAttack = gpGlobals->curtime - 0.1f;
	}
	else if ( ( pOwner->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack < gpGlobals->curtime ) && ( m_iClip1 <= 0 ) )
	{
		DryFire();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : int
//-----------------------------------------------------------------------------
Activity CWeaponFreezer::GetPrimaryAttackActivity( void )
{
	if ( m_nNumShotsFired < 1 )
		return ACT_VM_PRIMARYATTACK;

	if ( m_nNumShotsFired < 2 )
		return ACT_VM_RECOIL1;

	if ( m_nNumShotsFired < 3 )
		return ACT_VM_RECOIL2;

	return ACT_VM_RECOIL3;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CWeaponFreezer::Reload( void )
{
	bool fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
	if ( fRet )
	{
		WeaponSound( RELOAD );
		m_flAccuracyPenalty = 0.0f;
	}
	return fRet;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponFreezer::AddViewKick( void )
{
	CBasePlayer *pPlayer  = ToBasePlayer( GetOwner() );
	
	if ( pPlayer == NULL )
		return;

	int iSeed = CBaseEntity::GetPredictionRandomSeed() & 255;
	RandomSeed( iSeed );
	
	QAngle	viewPunch;

	viewPunch.x = random->RandomFloat( 0.25f, 0.5f );
	viewPunch.y = random->RandomFloat( -.6f, .6f );
	viewPunch.z = 0.0f;

	//Add it to the view punch
	pPlayer->ViewPunch( viewPunch );
}

BTW: I also added CTraceFilterNoOwnerTest from weapon_physcannon.cpp - I am not sure if it's really needed but I just took it one by one to prevent errors right now.

So when I try to compile it now it says when compiling it for client.dll that 'IsWorld' is no Element of 'C_BaseEntity'.
How can this be? - Cause when I try to compile it for server.dll I don't experience any problems!



Thx VERY much for any help!
 
For your first problem try putting a breakpoint in the Use function to see if it is called at all. If it is called and you are not given the weapon then you need to look at the code inside that function to make sure you didnt overlook something.

For the second one, if one dll compiles fine but not the other for the same file it means that its a shared file and you probably need to use an #if #endif directive to make sure that the code is only executed for either the server or the client.

Ex.

Code:
#ifdef CLIENT_DLL
  //client specific function definitions or implementation
#else
  //server specific....
#endif
 
thx!
Now my experience to the first problem:
After I had some experiments I found out that the function works at all but it doesn'T get triggered by "using" it in game itself!
But when I enter "ent_fire ent_terminal" into the console it works perfectly! (if it also worked like this when I went to the console straight and pressed "E"....)

So what can it be anymore?


And to the second thing:
I haven't found something "usable" yet but I got to look though it again

Thanks very much anyways!!!
I really appreciate this!
 
I can't tell you definitively what to do but what I would do if i were you would be to look at other entities that have a "use" function. Func_Button seems the obvious choice. Make sure you are extending the right class of entity (use the same one as func_button) or even just extend func_button and redefine the method for usage.

Since the SDK is so poorly documented usually the only way to find what you want is to look around for something similar and rip it off, you'll learn more as you go along so that you can actually come up with your own stuff (thats whats happening with me)
 
hmm
I have already looked into buttons.cpp but when I spectate it, it seems as it on the one hand uses it completely own methods (button_use, button_touch, etc.) and on the other hand there is also an "Use" Function implented at CRotButton (or similar - at all ints also in the buttons.cpp file)
 
Back
Top