Wallhang / Wallclimb
Posted: Mon Sep 28, 2026 12:55 pm
This code allows a player to climb/crawl through walls. Also when the player stop while climbing, he will be stuck to the wall and will not fall.
Code: Select all
//Two global variables. First tells us if the player is above ground and stuck to the wall.
//Second finds the origin of the player when he is near a wall.
new g_bfStuckToWall;
new Float:g_flWallOrigin[33];
#define stickPlayer(%1) g_bfStuckToWall |= (1 << (%1 & 31))
#define unstickPlayer(%1) g_bfStuckToWall &= ~(1 << (%1 & 31))
#define isStuck(%1) g_bfStuckToWall & (1 << (%1 & 31)) Code: Select all
//Register touch to find if player is touching a wall.
//Register prethink to create wallclimb when conditions are proper.
register_touch("worldspawn","player","Touch_Climb");
register_touch("func_brush","player","Touch_Climb");
register_touch("func_breakable","player","Touch_Climb");
register_forward(FM_PlayerPreThink, "Forward_PlayerPreThink", 0); Code: Select all
public Touch_Climb(Ent,id)
{
//If player is touching a wall then we find it's origin
pev(id,pev_origin,g_flWallOrigin[id]);
return PLUGIN_HANDLED;
} Code: Select all
public Forward_PlayerPreThink(id)
{
//If player is dead then ignore.
if(!is_user_alive(id))
return;
static iButton[33], iCrawlSpeed;
//Get button that player is using as well as the speed he is supposed to move on the wall.
//I left iCrawlSpeed as a get_pcvar_num so you can register a cvar for that.
iButton[id] = get_user_button(id);
iCrawlSpeed = get_pcvar_num(YOU_CVAR);
if(iButton[id] & IN_USE)
{
//Here we have three matrices holding the origin of the player, previous origin and velocity.
static Float:fOrigin[33][3];
static Float:fOriginOld[33][3];
static Float:fVelocity[33][3];
//Get user origin.
pev(id,pev_origin,fOrigin[id]);
//If he is far from the wall then return.
if(get_distance_f(fOrigin[id],g_flWallOrigin[id]) > 10.0)
return;
//If holding iButton and moving forward
if(iButton[id] & IN_FORWARD)
{
//Check if player is stuck to wall.
switch(isStuck(id)){
//If not them make him move.
case 0:{
velocity_by_aim(id,iCrawlSpeed,fVelocity[id]);
set_pev(id,pev_velocity,fVelocity[id]);
}
//If yes then unstuck him.
default:{
unstickPlayer(id);
}
}
}
//If holding iButton and moving back
else if(iButton[id] & IN_BACK)
{
switch(isStuck(id)){
case 0:{
velocity_by_aim(id,-iCrawlSpeed,fVelocity[id]);
set_pev(id,pev_velocity,fVelocity[id]);
}
default:{
unstickPlayer(id);
}
}
}
else if(iButton[id])
{
//If Player is holding iButton but not moving, then g_bStuckToWall = true
//and previous origin will now always be equal to current.
switch(isStuck(id)){
case 0:{
fOriginOld[id] = fOrigin[id];
stickPlayer(id);
}
}
//Set his velocity to zero.
velocity_by_aim(id,0,fVelocity[id]);
set_pev(id,pev_velocity,fVelocity[id]);
//if the diference between previous and current origins are small, then set
//set player's new origin as previous
if(get_distance_f(fOrigin[id],fOriginOld[id]) <= 10){
set_pev(id,pev_origin,fOriginOld[id]);
}
}
}
}