pev->button
.
CBasePlayer::PreThink
, this happens:
int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame
// Debounced button codes for pressed/released
m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed"
m_afButtonReleased = buttonsChanged & (~pev->button); // The ones not down are "released"
You may think of:
pev->button
as the answer to "what buttons are held right now?",m_afButtonPressed
as the answer to "what buttons have just become pressed?" andm_afButtonReleased
as the answer to "what buttons have just become released?"pev->button
, which can be found in in_buttons.h
:
#define IN_ATTACK (1 << 0)
#define IN_JUMP (1 << 1)
#define IN_DUCK (1 << 2)
#define IN_FORWARD (1 << 3)
#define IN_BACK (1 << 4)
#define IN_USE (1 << 5)
#define IN_CANCEL (1 << 6)
#define IN_LEFT (1 << 7)
#define IN_RIGHT (1 << 8)
#define IN_MOVELEFT (1 << 9)
#define IN_MOVERIGHT (1 << 10)
#define IN_ATTACK2 (1 << 11)
#define IN_RUN (1 << 12)
#define IN_RELOAD (1 << 13)
#define IN_ALT1 (1 << 14)
#define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down
So, with all that said, if you want to check if the player is holding a certain key in a given moment, you can do it like so:
// If the player is holding down the reload key
if ( pPlayer->pev->button & IN_RELOAD )
{
// Do stuff here
}
CFuncSlidicle
(slidicle as in, "sliding vehicle") class with a Spawn method:
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
class CFuncSlidicle : public CBaseEntity
{
public:
void Spawn() override;
int ObjectCaps() override { return CBaseEntity::ObjectCaps() | FCAP_IMPULSE_USE; }
void Use( CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value ) override;
void Think() override;
private:
CBasePlayer* driver = nullptr;
};
LINK_ENTITY_TO_CLASS( func_slidicle, CFuncSlidicle );
// This is assumed to be a brush entity, so we set it up like this in Spawn
void CFuncSlidicle::Spawn()
{
pev->movetype = MOVETYPE_PUSHSTEP;
pev->solid = SOLID_BSP;
SET_MODEL( edict(), STRING( pev->model ) );
}
driver
variable which will point to a player that is currently controlling the vehicle, and we'll sample the inputs there.
void CFuncSlidicle::Think()
{
// If we got no driver, then we got nothing
if ( !driver )
{
return;
}
// Movement logic here
pev->nextthink = gpGlobals->time + 0.01f;
}
Let's expand on this comment about movement logic. First, we'll sample the current button states:
const int& buttons = driver->pev->button;
Then, we'll have a vector to store some type of "wish velocity", i.e. where the player wants to go.
// vec3_origin is the same as Vector( 0, 0, 0 )
Vector addVelocity = vec3_origin;
It is (0,0,0) by default, so it can be added upon like so:
if ( buttons & IN_FORWARD )
addVelocity.x += 16.0f; // alternative: define a constant for this speed instead of typing 16 every time
if ( buttons & IN_BACK )
addVelocity.x -= 16.0f;
if ( buttons & IN_MOVELEFT )
addVelocity.y += 16.0f;
if ( buttons & IN_MOVERIGHT )
addVelocity.y -= 16.0f;
// And of course, you gotta finally add it to the entity's velocity:
pev->velocity = pev->velocity + addVelocity;
The final function will be the following:
void CFuncSlidicle::Think()
{
// If we got no driver, then we got nothing
if ( !driver )
{
return;
}
constexpr float VehicleAcceleration = 16.0f;
const int& buttons = driver->pev->button;
Vector addVelocity = vec3_origin;
if ( buttons & IN_FORWARD )
addVelocity.x += VehicleAcceleration;
if ( buttons & IN_BACK )
addVelocity.x -= VehicleAcceleration;
if ( buttons & IN_MOVELEFT )
addVelocity.y += VehicleAcceleration;
if ( buttons & IN_MOVERIGHT )
addVelocity.y -= VehicleAcceleration;
pev->velocity = pev->velocity + addVelocity;
pev->nextthink = gpGlobals->time + 0.01f;
}
void CFuncSlidicle::Use( CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value )
{
if ( !pActivator->IsPlayer() )
{
return;
}
// A potential driver wants to enter this vehicle
if ( !driver )
{
driver = static_cast<CBasePlayer*>(pActivator);
// Hack: lock the player in place
driver->pev->maxspeed = 0.01f;
// Think immediately
pev->nextthink = gpGlobals->time + 0.01f;
return;
}
// The current driver wants to eject
if ( driver && pActivator == driver )
{
driver->pev->maxspeed = 0.0f;
driver = nullptr;
}
}
A couple of things to note here:
pev->maxspeed
to 0.01 practically freezes them. driver->EnableControl( FALSE );
could've been used, but pev->button
would be 0 all the time. Setting pev->movetype
to MOVETYPE_NONE
for the player seems to do nothing.UTIL_MakeVectors
, rotate the vehicle with A and D instead of moving it left-right, and then add the forward vector to the velocity, or subtract if the player's going backwards.if ( buttons & IN_MOVELEFT )
pev->angles.y += 1.0f;
if ( buttons & IN_MOVERIGHT )
pev->angles.y -= 1.0f;
UTIL_MakeVectors( pev->angles );
if ( buttons & IN_FORWARD )
pev->velocity = pev->velocity + gpGlobals->v_forward * VehicleAcceleration;
if ( buttons & IN_BACK )
pev->velocity = pev->velocity - gpGlobals->v_forward * VehicleAcceleration;
Finally, you might also want to set up a save-restore table, so that driver
gets saved and loaded properly.You must log in to post a comment. You can login or register a new account.