I was doing some testing cause some people have ask me about this and I found a way without hooking client_prethink. I am also using gravity cause its really smooth and acts more realistic. Would be nice to see this in a module coded like this.
PHP Code:
#include < amxmodx >
#include < fakemeta >
#include < hamsandwich >
#include < fun >
#include < orpheu >
#include < orpheu_stocks >
new OrpheuStruct:g_ppmove;
#define PLUGIN "Parachute"
#define VERSION "1.0"
#define AUTHOR ""
#define PARACHUTE_MODEL "models/parachute.mdl"
#define MAX_PLAYERS 32
#define MarkUserHasParachute(%0) g_bitHasParachute |= (1<<(%0&31))
#define ClearUserHasParachute(%0) g_bitHasParachute &= ~(1<<(%0&31))
#define HasUserParachute(%0) g_bitHasParachute & (1<<(%0&31))
#define MarkUserUsingParachute(%0) g_bitUsingParachute |= (1<<(%0&31))
#define ClearUserUsingParachute(%0) g_bitUsingParachute &= ~(1<<(%0&31))
#define HasUserUsingParachute(%0) g_bitUsingParachute & (1<<(%0&31))
#define MarkUserAliveParachute(%0) g_bitAlive |= (1<<(%0&31))
#define ClearUserAliveParachute(%0) g_bitAlive &= ~(1<<(%0&31))
#define HasUserAliveParachute(%0) g_bitAlive & (1<<(%0&31))
new g_bitAlive
new g_bitUsingParachute
new g_bitHasParachute
new g_iUserParachute[MAX_PLAYERS+1]
new Float:g_flEntityFrame[MAX_PLAYERS+1]
new g_iModelIndex
new g_pCvarFallSpeed
new const PARACHUTE_CLASS[] = "parachute"
enum {
deploy,
idle,
detach
}
public plugin_init() {
register_plugin(_PLUGIN, _VERSION, _AUTHOR)
g_pCvarFallSpeed = register_cvar("parachute_fallspeed", "0.0001")
RegisterHam(Ham_Spawn, "player", "Ham_CBasePlayer_Spawn_Post", 1)
RegisterHam(Ham_Killed, "player", "Ham_CBasePlayer_Killed_Post", 1)
OrpheuRegisterHook( OrpheuGetDLLFunction( "pfnPM_Move", "PM_Move" ), "PM_Move" );
OrpheuRegisterHook( OrpheuGetFunction( "PM_FlyMove" ), "PM_FlyMove" );
OrpheuRegisterHook( OrpheuGetFunction( "PM_PlayStepSound" ), "PM_PlayStepSound" );
}
public plugin_precache() {
g_iModelIndex = precache_model(PARACHUTE_MODEL)
}
public client_putinserver(id) {
if( HasUserParachute(id) ) {
new iEnt = g_iUserParachute[id]
if( iEnt ) {
RemoveUserParachute(id, iEnt)
}
ClearUserHasParachute(id)
}
ClearUserAliveParachute(id)
}
public client_disconnect(id) {
if( HasUserParachute(id) ) {
new iEnt = g_iUserParachute[id]
if( iEnt ) {
RemoveUserParachute(id, iEnt)
}
ClearUserHasParachute(id)
}
ClearUserAliveParachute(id)
}
public Ham_CBasePlayer_Killed_Post( id ) {
if( HasUserParachute(id) ) {
new iEnt = g_iUserParachute[id]
if( iEnt ) {
RemoveUserParachute(id, iEnt)
}
ClearUserHasParachute(id)
}
ClearUserAliveParachute(id)
}
new Float:get_userGravity[ 33 ]
new Float:get_cvar
public Ham_CBasePlayer_Spawn_Post(id) {
if( is_user_alive(id) ) {
get_cvar = get_pcvar_float(g_pCvarFallSpeed)
get_userGravity[ id ] = get_user_gravity(id)
if( HasUserParachute(id) ) {
new iEnt = g_iUserParachute[id]
if( iEnt ) {
RemoveUserParachute(id, iEnt)
}
}
MarkUserHasParachute(id)
MarkUserAliveParachute(id)
}
}
RemoveUserParachute(id, iEnt) {
engfunc(EngFunc_RemoveEntity, iEnt)
g_iUserParachute[id] = 0
set_user_gravity(id, get_userGravity[ id ])
ClearUserUsingParachute(id)
}
CreateParachute(id) {
static iszInfoTarget
if( !iszInfoTarget ) {
iszInfoTarget = engfunc(EngFunc_AllocString, "info_target")
}
new iEnt = engfunc(EngFunc_CreateNamedEntity, iszInfoTarget)
if( iEnt > 0) {
static iszClass = 0
if( !iszClass ) {
iszClass = engfunc(EngFunc_AllocString, PARACHUTE_CLASS)
}
set_pev_string(iEnt, pev_classname, iszClass)
set_pev(iEnt, pev_aiment, id)
set_pev(iEnt, pev_owner, id)
set_pev(iEnt, pev_movetype, MOVETYPE_FOLLOW)
static iszModel = 0
if( !iszModel ) {
iszModel = engfunc(EngFunc_AllocString, PARACHUTE_MODEL)
}
set_pev_string(iEnt, pev_model, iszModel)
set_pev(iEnt, pev_modelindex, g_iModelIndex)
set_pev(iEnt, pev_sequence, deploy)
set_pev(iEnt, pev_gaitsequence, 1)
set_pev(iEnt, pev_frame, 0.0)
set_pev(iEnt, pev_rendermode, pev(id, pev_rendermode));
set_pev(iEnt, pev_renderfx, pev(id, pev_renderfx));
new Float:f_renderamt;
pev(id, pev_renderamt, f_renderamt);
set_pev(iEnt, pev_renderamt, f_renderamt);
g_flEntityFrame[id] = 0.0
g_iUserParachute[id] = iEnt
MarkUserHasParachute(id)
new Float:fVecOrigin[3]
pev(id, pev_origin, fVecOrigin)
return iEnt
}
return 0
}
public OrpheuHookReturn:PM_Move( OrpheuStruct:ppmove, server )
{
g_ppmove = ppmove;
return OrpheuIgnored;
}
public OrpheuHookReturn:PM_PlayStepSound( )
{
new id = OrpheuGetStructMember( g_ppmove, "player_index" ) + 1;
if( ~HasUserParachute(id) && ~HasUserAliveParachute(id)) {
return OrpheuIgnored;
}
new iEnt = g_iUserParachute[id]
if(iEnt > 0 && HasUserUsingParachute(id) ) {
RemoveUserParachute(id, iEnt)
}
return OrpheuIgnored;
}
public OrpheuHookReturn:PM_FlyMove( )
{
new id = OrpheuGetStructMember( g_ppmove, "player_index" ) + 1;
new Float:flFrame
new iEnt = g_iUserParachute[id]
if( pev(id, pev_button) & IN_USE ) {
new Float:fVecVelocity[3], Float:fVelocity_z
pev(id, pev_velocity, fVecVelocity)
fVelocity_z = fVecVelocity[2]
if( fVelocity_z < 0.0 ) {
if(iEnt <= 0) {
iEnt = CreateParachute(id)
}
//fVelocity_z = floatmin(fVelocity_z + 14.0, -get_pcvar_float(g_pCvarFallSpeed))
//fVecVelocity[2] = fVelocity_z
//set_pev(id, pev_velocity, fVecVelocity)
MarkUserUsingParachute(id)
set_user_gravity(id, (get_userGravity[ id ]/4)+get_cvar)
if( pev(iEnt, pev_sequence) == deploy ) {
flFrame = g_flEntityFrame[id]++
if( flFrame > 100.0 ) {
set_pev(iEnt, pev_animtime, 0.0)
set_pev(iEnt, pev_framerate, 0.4)
set_pev(iEnt, pev_sequence, idle)
set_pev(iEnt, pev_gaitsequence, 1)
set_pev(iEnt, pev_frame, 0.0)
g_flEntityFrame[id] = 0.0
}
else {
set_pev(iEnt, pev_frame, flFrame)
}
}
}
else if(iEnt > 0) {
RemoveUserParachute(id, iEnt)
}
}
else if( iEnt > 0 && pev(id, pev_oldbuttons) & IN_USE ) {
RemoveUserParachute(id, iEnt)
}
return OrpheuIgnored;
}