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
It is not possible to directly add more, unless you "sacrifice" some of the existing ones. 16 bits is all you're going to get, and it's impossible to change this limitation, even in delta.lst
. There exist workarounds, although that is out of scope for this guide.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.
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.