AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Code Snippets/Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=83)
-   -   Blocking weapon fire, including client-side sounds/animations (https://forums.alliedmods.net/showthread.php?t=41265)

KCE 07-12-2006 05:30

Blocking weapon fire, including client-side sounds/animations
 
Blocking weapon fire, including client-side sounds/animations

So you want to block weapon fire, including client-side sounds/animations?...you've come to the right thread :)

This tutorial is meant for intermediate - advanced users

Introduction
  • I've been using this method in my metamod MLMod plugin for NS, for a while now, which is similar to the metamod Spawn Chat protection plugin by Jussi Kivilinna. I have not tested this is any other mod except NS, but it should work the same...:?:
  • With the addition of UpdateClientData forward in the latest Amx Mod X, it is now possible to block weapon fire through fakemeta, including client-side sounds/animations.
  • There are two methods to blocking weapon fire:
    1. Make the engine think the player has no weapon - for blocking weapon fire whenever you want to
    2. Set the time until next attack (used in the Spawn Chat protection plugin) - for blocking weapon fire for a specific amount of time
  • Info on the UpdateClientData function...
    • It appears to be called every frame and also before PreThink.
    • Setting player properties like EV_ or pev_ do not work (I've tested with removing buttons from EV_INT_buttons and does not block it).
    • It cannot block reload animations. Doing either of the methods above during a reload will not block the animation. However, weapon reload can be blocked (the anim and actual reload) by removing the buttons.
  • Also, you MUST STILL remove the IN_ATTACK button mask to keep the weapon from using ammo and doing damage, etc. Like I said, you cannot do this in UpdateClientData, so it must be done in PreThink or CmdStart like before. However, I'm not sure if CmdStart is called every frame? I recommend PreThink because it is called specifically before Think and PostThink and every frame.

Now for the good part...

Registering forwards and hooks
  1. Import the additional includes that you will need.
    Code:
    #include <fakemeta> #include <engine>
  2. In plugin_init(), register FM_PlayerPreThink or use the default engine client_preThink. If registering through fakemeta, it does not matter if it is post or not. The engine forward is not post meaning it is called before the original is called.
    Code:
    public client_PreThink(id) { }
    or
    Code:
    register_forward(FM_PlayerPreThink, "PlayerPreThink")
  3. And also in plugin_init(), register FM_UpdateClientData. It is important that it is hooked AFTER the original is called so your modifications are not changed. This is indicated by passing 1 as the third argument telling Amx Mod X that you want your function to get called after the original has been called.
    Code:
    register_forward(FM_UpdateClientData, "UpdateClientData_Post", 1)
  4. In client_preThink, if you're using the default engine forward, if using fakemeta method then whatever it is you named it. In my example it was named PlayerPreThink
    Code:
    //engine method public client_PreThink( id ) {     //Do whatever checks you need to do and whatnot...         if( !is_user_alive(id) )         return PLUGIN_CONTINUE;         //Remove the attack button from their button mask         entity_set_int( id, EV_INT_button, entity_get_int(id,EV_INT_button) & ~IN_ATTACK );     return PLUGIN_CONTINUE; }
    or
    Code:
    //fakemeta method public PlayerPreThink( id ) {     //Do whatever checks you need to do and whatnot...         if( !is_user_alive(id) )         return FMRES_IGNORED;         //Remove the attack button from their button mask         set_pev( id, pev_button, pev(id,pev_button) & ~IN_ATTACK );     return FMRES_HANDLED; }
  5. In UpdateClientData_Post, there are 3 arguments sent:
    1. 1st argument is id (int) - player ID
    2. 2nd argument is sendweapons (int) - indication if client-side weapons are being used (cl_lw); not really important, can be ignored
    3. 3rd argument is cd_handle (clientdata type) - contains all the player info to be modified, which is accessed through get_cd, and set_cd
    Code:
    public UpdateClientData_Post( id, sendweapons, cd_handle ) { }

Method 1 - Make the engine think the player has no weapon:
  • We do this by modifying CD_ID, which is the weapon id, and setting it to 0 thus making the engine think the player has no weapon and so no animation/sound can be played.
    Code:
    //Remember the 3 arguments sent: //id - player id //sendweapons - indication if client-side weapons are being used (cl_lw) //cd_handle - client data which is accessed through get_cd, and set_cd public UpdateClientData_Post( id, sendweapons, cd_handle ) {     //No sense in doing this for dead people?     //Add your additional checks and whatnot...     if ( !is_user_alive(id) )         return FMRES_IGNORED;     //We want to use the cd_handle passed to us     //unless you want this for all the players     //in which you would specify 0 instead         set_cd(cd_handle, CD_ID, 0);                //And finally return...         return FMRES_HANDLED; }

Method 2 - Modify the time until the next attack:
  • We do this by modifying CD_flNextAttack, which is the specific time when the player can attack again. This cannot only be used to block attacks but to also modify ROF! (which I'll discuss elsewhere).
  • Actually CD_flNextAttack has a value greater than zero ONLY when a player is reloading which is why it acts the way it does. So basically setting this value makes the engine think the player is in reload, however the reload animations are not played. Another way this could be used is possibly to make the player fire before the reload is done?
    Code:
    //Again the 3 arguments sent: //id - player id //sendweapons - indication if client-side weapons are being used (cl_lw) //cd_handle - client data which is accessed through get_cd, and set_cd public UpdateClientData_Post( id, sendweapons, cd_handle ) {     //No sense in doing this for dead people?     //Add your additional checks and whatnot...     if ( !is_user_alive(id) )         return FMRES_IGNORED;     //We want to use the cd_handle passed to us     //unless you want this for all the players     //in which you would specify 0 instead         //We get the current half-life time and set the next attack to a fraction of a sec later...     //This must be modified every time or else it won't block the attack     set_cd(cd_handle, CD_flNextAttack, halflife_time() + 0.001 );               //And finally return...         return FMRES_HANDLED; }
  • A snippet from the Spawn Chat protection plugin and how it uses this function. My comments start with four slashes ////.
    Code:

    void CPlayer::UpdateClientData_Post(int sendweapons, struct clientdata_s *cd)
    {
            //Fix clientside weapon animations
            if(sendweapons && m_ProtectionActive)
            {
                    ////The first part of the if statement let's the player attack the next frame
                    ////The second part of the if statement blocks the player's attack until a certain time
           
                    ////If attack time is before the current time (meanning player can fire) then
                    if (cd->m_flNextAttack < gpGlobals->time)                       
                           
                            ////m_StartOfProtection is the time when the blocking of the player's attack started
                            ////scp_off_delay.get() is how long to keep blocking the time
                            ////m_StartOfProtection + scp_off_delay.get() is the time when the player can attack again
                            ////(m_StartOfProtection + scp_off_delay.get()) - (gpGlobals->time + 0.001f)
                            ////Think of it as:
                            ////<time when the player can attack again> - <time now, basically> = now or next frame player can attack
                            ////Pretty much, the player can attack the moment they want to and it won't be blocked
                            ////The 0.001 is so player can fire a fraction of a second earlier to fix some weapon glitches or because it is checked by > instead of equal
                            cd->m_flNextAttack = (m_StartOfProtection + scp_off_delay.get()) - (gpGlobals->time + 0.001f);
                   
                    ////else if attack time is after the current time (meanning player can't fire) then
                    else
                   
                            ////Similar to above except in calculations...
                            ////m_StartOfProtection is the time when the blocking of the player's attack started
                            ////scp_off_delay.get() is how long to keep blocking the time
                            ////m_StartOfProtection + scp_off_delay.get() is the time when the player can attack again
                            ////(m_StartOfProtection + scp_off_delay.get()) - 0.001f
                            ////Think of it as:
                            ////<time when the player can attack again> - <fraction of a second> = specific time when player can attack
                            ////The 0.001 is so player can fire a fraction of a second earlier to fix some weapon glitches or because it is checked by > instead of equal
                            cd->m_flNextAttack = (m_StartOfProtection + scp_off_delay.get()) - 0.001f;
                   
                    SetMetaResult(MRES_HANDLED);
                    return;
            }
           
            SetMetaResult(MRES_IGNORED);
            return;
    }


Custom Weapon ROF (Rate-of-fire)
  • I did this part on-the-fly...anyways there are, of course, many ways to do this. This is just one way; there may be others methods that could be better suited for your situation; just take a look at the above snippet from the Spawn Chat protection plugin.
  • Also the subtraction of the 0.001 is not neccessary but feel free to do it if needed. I believe it is done because it is checked with greater than (>) so the delay is slightly longer but only by a very miniscule amount.
  • Create some variables to store some info:
    Code:
    new g_NextAttack[33];   //stores players' next attack times new g_BlockAnim[33];    //stores players' variable for whether to block animation in UpdateClientData_Post new CVAR_rof;         //"pointer" to CVAR containing the rof; could also be define
  • Using Method #1:
    • In UpdateClientData_Post is where we initially decide whether the attack needs to be blocked
      Code:
      //Remember the 3 arguments sent: //id - player id //sendweapons - indication if client-side weapons are being used (cl_lw) //cd_handle - client data which is accessed through get_cd, and set_cd public UpdateClientData_Post( id, sendweapons, cd_handle ) {     //Do whatever checks you need to do and whatnot...     //Make sure player is holding the weapon you want to block     //Make sure player is alive     //etc.         //First check the ROF         //Store the variables         new Float:global_Time;     global_get(glb_time, global_Time);     new Float:ROF = get_pcvar_float(CVAR_rof);         //If current time hasn't yet reached the next allowed attack time, keep blocking the attack     //else let it go and reset the g_BlockAnim variable         if( global_Time < g_NextAttack[id] )     {         //Keep blocking attack         //Now you could just block if the player is pressing the button but just to be safe block it regardless                 //Set player variable to block in PlayerPreThink also                 g_BlockAnim[id] = 1;                 //We want to use the cd_handle passed to us         //unless you want this for all the players         //in which you would specify 0 instead                    set_cd(cd_handle, CD_ID, 0);            }     else     {         //Allow attack                 //Reset player variable to block in PlayerPreThink                 g_BlockAnim[id] = 0;                 //Set next attack time at which player is allowed to attack                 g_NextAttack[id] = global_Time + ROF;           }         return FMRES_HANDLED; }
  • Using Method #2:
    • In UpdateClientData_Post is where we initially decide whether the attack needs to be blocked
      Code:
      //Remember the 3 arguments sent: //id - player id //sendweapons - indication if client-side weapons are being used (cl_lw) //cd_handle - client data which is accessed through get_cd, and set_cd public UpdateClientData_Post( id, sendweapons, cd_handle ) {     //Do whatever checks you need to do and whatnot...     //Make sure player is holding the weapon you want to block     //Make sure player is alive     //etc.         //First check the ROF         //Store the variables         new Float:global_Time;     global_get(glb_time, global_Time);     new Float:ROF = get_pcvar_float(CVAR_rof);         //If current time hasn't yet reached the next allowed attack time, keep blocking the attack     //else let it go and reset the g_BlockAnim variable         if( global_Time < g_NextAttack[id] )     {         //Keep blocking attack         //Now you could just block if the player is pressing the button but just to be safe block it regardless                 //Set player variable to block in PlayerPreThink also                 g_BlockAnim[id] = 1;         //We want to use the cd_handle passed to us         //unless you want this for all the players         //in which you would specify 0 instead                    //If current time is equal or greater than (>=) g_NextAttack, the attack will be blocked         //else it will not                 set_cd(cd_handle, CD_flNextAttack, g_NextAttack[id]);     }     else     {         //Allow attack                 //Reset player variable to block in PlayerPreThink                 g_BlockAnim[id] = 0;                 //Set next attack time at which player is allowed to attack                 g_NextAttack[id] = global_Time + ROF;           }     return FMRES_HANDLED; }
  • In PlayerPreThink we check the g_BlockAnim variable
    Code:
    //fakemeta method public PlayerPreThink( id ) {     //Do whatever checks you need to do and whatnot...     //Make sure player is holding the weapon you want to block     //Make sure player is alive     //etc.         if( g_BlockAnim[id] )     {         //Remove the attack button from their button mask                 set_pev( id, pev_button, pev(id,pev_button) & ~IN_ATTACK );                 //Reset the variable         //It will be set again in UpdateClientData_Post before it comes here so it is set every frame                 g_BlockAnim[id] = 0;     }     // else allow attack         return FMRES_HANDLED; }

Quick Reference:
  • From fakemeta_const.inc & fakemeta.inc:
  • ClientData enum
    Code:

    enum ClientData
    {
            CD_Origin,                        // float array[3]
            CD_Velocity,                // float array[3]
            CD_ViewModel,                // int
            CD_PunchAngle,                // float array[3]
            CD_Flags,                        // int
            CD_WaterLevel,                // int
            CD_WaterType,                // int
            CD_ViewOfs,                        // float array[3]
            CD_Health,                        // float
            CD_bInDuck,                        // int
            CD_Weapons,                        // int
            CD_flTimeStepSound,        // int
            CD_flDuckTime,                // int
            CD_flSwimTime,                // int
            CD_WaterJumpTime,        // int
            CD_MaxSpeed,                // float
            CD_FOV,                                // float
            CD_WeaponAnim,                // int
            CD_ID,                                // int
            CD_AmmoShells,                // int
            CD_AmmoNails,                // int
            CD_AmmoCells,                // int
            CD_AmmoRockets,                // int
            CD_flNextAttack,        // float
            CD_tfState,                        // int
            CD_PushMsec,                // int
            CD_DeadFlag,                // int
            CD_PhysInfo,                // string[256]
            CD_iUser1,                        // int
            CD_iUser2,                        // int
            CD_iUser3,                        // int
            CD_iUser4,                        // int
            CD_fUser1,                        // float
            CD_fUser2,                        // float
            CD_fUser3,                        // float
            CD_fUser4,                        // float
            CD_vUser1,                        // float array[3]
            CD_vUser2,                        // float array[3]
            CD_vUser3,                        // float array[3]
            CD_vUser4                        // float array[3]
    };

  • ClientData functions
    Code:

    // These functions are used with the clientdata data structure (FM_UpdateClientData)
    // Get: 0 extra params - Return integer; 1 extra param - by ref float or vector; 2 extra params - string and length
    // Set: Use anything
    // Use 0 for cd_handle to specify the global clientdata handle
    native get_cd(cd_handle, ClientData:member, {Float,_}:...);
    native set_cd(cd_handle, ClientData:member, {Float,_}:...);

  • Forward Function Constants
    Code:

    enum {
            FM_PrecacheModel = 1,                // done
            FM_PrecacheSound,                // done
            FM_SetModel,                        // done
            FM_ModelIndex,                        // done
            FM_ModelFrames,                        // done
            FM_SetSize,                        // done
            FM_ChangeLevel,                        // done
            FM_VecToYaw,                        // done
            FM_VecToAngles,                        // done
            FM_MoveToOrigin,                // done
            FM_ChangeYaw,                        // done
            FM_ChangePitch,                        // done
            FM_FindEntityByString,                // done
            FM_GetEntityIllum,                // done
            FM_FindEntityInSphere,                // done
            FM_FindClientInPVS,                // done
            FM_EntitiesInPVS,                // done
            FM_MakeVectors,                        // done
            FM_AngleVectors,                // done
            FM_CreateEntity,                // done
            FM_RemoveEntity,                // done
            FM_CreateNamedEntity,                // done
            FM_MakeStatic,                        // done
            FM_EntIsOnFloor,                // done
            FM_DropToFloor,                        // done
            FM_WalkMove,                        // int  )                (edict_t *ent, float yaw, float dist, int iMode); -- does't work as of 0.20 RC2
            FM_SetOrigin,                        // done
            FM_EmitSound,                        // done
            FM_EmitAmbientSound,                // done
            FM_TraceLine,                        // void )                (const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -- does't work as of 0.20 RC2
            FM_TraceToss,                        // void )                (edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr); -- does't work as of 0.20 RC2
            FM_TraceMonsterHull,                // int  )                (edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -- does't work as of 0.20 RC2
            FM_TraceHull,                        // void )                (const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr);  -- does't work as of 0.20 RC2
            FM_TraceModel,                        // void )                (const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr);  -- does't work as of 0.20 RC2
            FM_TraceTexture,                // const char *)        (edict_t *pTextureEntity, const float *v1, const float *v2 ); -- does't work as of 0.20 RC2
            FM_TraceSphere,                        // void )                (const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr);  -- does't work as of 0.20 RC2
            FM_GetAimVector,                // done
            FM_ParticleEffect,                // done
            FM_LightStyle,                        // done
            FM_DecalIndex,                        // done
            FM_PointContents,                // done
            FM_MessageBegin,                // done
            FM_MessageEnd,                        // done
            FM_WriteByte,                        // done
            FM_WriteChar,                        // done
            FM_WriteShort,                        // done
            FM_WriteLong,                        // done
            FM_WriteAngle,                        // done
            FM_WriteCoord,                        // done
            FM_WriteString,                        // done
            FM_WriteEntity,                        // done
            FM_CVarGetFloat,                // done
            FM_CVarGetString,                // done
            FM_CVarSetFloat,                // done
            FM_CVarSetString,                // done
            FM_FreeEntPrivateData,                // done
            FM_SzFromIndex,                        // done
            FM_AllocString,                        // done
            FM_RegUserMsg,                        // done
            FM_AnimationAutomove,                // done
            FM_GetBonePosition,                // void )        (const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles );  -- does't work as of 0.20 RC2
            FM_GetAttachment,                // void        )        (const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles );  -- does't work as of 0.20 RC2
            FM_SetView,                        // done
            FM_Time,                        // done
            FM_CrosshairAngle,                // done
            FM_FadeClientVolume,                // done
            FM_SetClientMaxspeed,                // done
            FM_CreateFakeClient,                // done
            FM_RunPlayerMove,                // void )        (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ); -- does't work as of 0.20 RC2
            FM_NumberOfEntities,                // done
            FM_StaticDecal,                        // done
            FM_PrecacheGeneric,                // done
            FM_BuildSoundMsg,                // void )        (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);  -- does't work as of 0.20 RC2
            FM_GetPhysicsKeyValue,                // done
            FM_SetPhysicsKeyValue,                // done
            FM_GetPhysicsInfoString,        // done
            FM_PrecacheEvent,                // done
            FM_PlaybackEvent,                // done
            FM_CheckVisibility,                //)                (
            FM_GetCurrentPlayer,                // done
            FM_CanSkipPlayer,                // done
            FM_SetGroupMask,                // done
            FM_Voice_GetClientListening,        // done
            FM_Voice_SetClientListening,        // done
            FM_InfoKeyValue,                // done
            FM_SetKeyValue,                        // done
            FM_SetClientKeyValue,                // done
            FM_GetPlayerAuthId,                // done
            FM_GetPlayerWONId,                // done
            FM_IsMapValid,                        // done


            FM_Spawn,                        // done
            FM_Think,                        // done
            FM_Use,                                // done
            FM_Touch,                        // done
            FM_Blocked,                        // done
            FM_KeyValue,                        // void )        ( edict_t *pentKeyvalue, KeyValueData *pkvd ); -- does't work as of 0.20 RC2
            FM_SetAbsBox,                        // done
            FM_ClientConnect,                // done
           
            FM_ClientDisconnect,                // done
            FM_ClientKill,                        // done
            FM_ClientPutInServer,                // done
            FM_ClientCommand,                // done

            FM_ServerDeactivate,                // done

            FM_PlayerPreThink,                // done
            FM_PlayerPostThink,                // done

            FM_StartFrame,                        // done
            FM_ParmsNewLevel,                // done
            FM_ParmsChangeLevel,                // done

            // Returns string describing current .dll.  E.g., TeamFotrress 2, Half-Life
            FM_GetGameDescription,                // done

            // Spectator funcs
            FM_SpectatorConnect,                // done
            FM_SpectatorDisconnect,                // done
            FM_SpectatorThink,                // done

            // Notify game .dll that engine is going to shut down.  Allows mod authors to set a breakpoint.
            FM_Sys_Error,                        // done

            FM_PM_FindTextureType,                // done
            FM_RegisterEncoders,                // done

            // Enumerates player hulls.  Returns 0 if the hull number doesn't exist, 1 otherwise

            // Create baselines for certain "unplaced" items.
            FM_CreateInstancedBaseline,        // done
            FM_AllowLagCompensation,        // done
            FM_AlertMessage,                // done                (at_type, message[])

            // NEW_DLL_FUNCTIONS:
            FM_OnFreeEntPrivateData,
            FM_GameShutdown,
            FM_ShouldCollide
    };


Miscellaneous:
  • The method I use above is my own personal tried and true method I've been using. Feel free to look into other methods of blocking attack and manipulating weapon sequences:
    • FM_AddToFullPack
    • FM_CmdStart

Any Karma donations are welcomed! :up:

v3x 07-12-2006 12:00

Re: Blocking weapon fire, including client-side sounds/animations
 
Interesting :]

Cheap_Suit 07-12-2006 15:04

Re: Blocking weapon fire, including client-side sounds/animations
 
pimpin...

Thank you! And great job on your ml plugin too!

DevconeS 07-12-2006 20:28

Re: Blocking weapon fire, including client-side sounds/animations
 
Quote:

Originally Posted by KCE
Code:
//fakemeta method public PlayerPreThink( id ) {     //Do whatever checks you need to do and whatnot...         if( !is_user_alive(id) )         return FMRES_IGNORED;         //Remove the attack button from their button mask         set_pev( id, pev_button, pev(id,pev_button) & ~IN_ATTACK );     return FMRES_HANDLED; }

Blocking buttons like IN_ATTACK in PreThink isn't very good. It just works for the knife and not that good.

I recommend the use of FM_CmdStart because it causes a better result than in PretThink and you're able to block all the weapon attacks. :)
Code:
// Put this in plugin init (yes it's for hooking the forward) register_forward(FM_CmdStart,"fwd_CmdStart") // Put this somewhere in the code ;) public fwd_CmdStart(id, uc_handle, seed) {     if(!is_user_alive(id)) return FMRES_IGNORED         new buttons = get_uc(uc_handle,UC_Buttons)     if(buttons & IN_ATTACK) {         buttons &= ~IN_ATTACK         set_uc(uc_handle,UC_Buttons,buttons)     }     return FMRES_HANDLED }

KCE 07-12-2006 20:40

Re: Blocking weapon fire, including client-side sounds/animations
 
Quote:

Originally Posted by DevconeS
Blocking buttons like IN_ATTACK in PreThink isn't very good. It just works for the knife and not that good.

I recommend the use of FM_CmdStart because it causes a better result than in PretThink and you're able to block all the weapon attacks. :)
Code:
// Put this in plugin init (yes it's for hooking the forward) register_forward(FM_CmdStart,"fwd_CmdStart") // Put this somewhere in the code ;) public fwd_CmdStart(id, uc_handle, seed) {     if(!is_user_alive(id)) return FMRES_IGNORED         new buttons = get_uc(uc_handle,UC_Buttons)     if(buttons & IN_ATTACK) {         buttons &= ~IN_ATTACK         set_uc(uc_handle,UC_Buttons,buttons)     }     return FMRES_HANDLED }

So far preThink is the tried and true method. There's never one solution to a problem :wink:

EDIT: Ok, I've just tried it and it seems to work the same way as preThink? Nothing different...:?:

Orangutanz 07-12-2006 20:52

Re: Blocking weapon fire, including client-side sounds/animations
 
Its more resourceful DevconeS way, since you are getting the change state of the buttons instantly as it happens, whereas prethink you don't.

DevconeS 07-12-2006 21:02

Re: Blocking weapon fire, including client-side sounds/animations
 
Quote:

Originally Posted by KCE
So far preThink is the tried and true method. There's never one solution to a problem :wink:

EDIT: Ok, I've just tried it and it seems to work the same way as preThink? Nothing different...:?:

Blocking the knife sounds seems to be working fine, but you see how it trys to animate for a little moment.
Yes I've tested this on CS. :P

KCE 07-12-2006 21:09

Re: Blocking weapon fire, including client-side sounds/animations
 
Quote:

Originally Posted by DevconeS
Blocking the knife sounds seems to be working fine, but you see how it trys to animate for a little moment.
Yes I've tested this on CS. :P

I guess either way is okay since UpdateClientData blocks the animation & sound anyways :P

I think the preThink method might be better since it only passes one argument, being slightly more efficient? Not really sure entirely...Most people find preThink also convenient for doing other specific stuff.

DevconeS 07-12-2006 22:03

Re: Blocking weapon fire, including client-side sounds/animations
 
You're free to do the way you prefer. :wink:
Mainly I don't like PreThink forward at all and in the CmdStart forward it also blocks the sounds (at least in the cs knife :)) so I don't have to do another function for blocking knife sounds. Before I blocked them by hooking the EmitSound forward. :P

Cheap_Suit 07-12-2006 22:34

Re: Blocking weapon fire, including client-side sounds/animations
 
Function renaming solved the problem, sorry.


All times are GMT -4. The time now is 18:03.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.