Have fun.
Please let me know about any problems or errors. Especially the pdata offsets on linux.
Code:
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <xs>
#define m_pPlayer 41 // CBasePlayerItem, Linux +4
#define m_flNextAttack 83 // CBasePlayer, Linux +5
#define P_MODEL "models/p_knife.mdl"
#define V_MODEL "models/v_amok_kukri.mdl"
new bool:gKnife[33],
gKnifeEntity,
gMaxPlayers,
gPModel,
gVModel,
pCvar_PriDelay,
pCvar_PriDamage,
pCvar_PriFreq,
pCvar_PriRange,
pCvar_SecDelay,
pCvar_SecDamage,
pCvar_SecFreq,
pCvar_SecRange;
new const Float:PrimaryDamage[] = {
15.0, /* Generic */
60.0, /* Head */
15.0, /* Chest */
18.75, /* Stomach */
15.0, /* Left Arm */
15.0, /* Right Arm */
11.25, /* Left Leg */
11.25 /* Right Leg */
};
new const Float:SecondaryDamage[] = {
65.0, /* Generic */
260.0, /* Head */
65.0, /* Chest */
81.25, /* Stomach */
65.0, /* Left Arm */
65.0, /* Right Arm */
48.75, /* Left Leg */
48.75 /* Right Leg */
};
new const gSoundBHitFlesh[][] = {
"player/bhit_flesh-1.wav",
"player/bhit_flesh-2.wav",
"player/bhit_flesh-3.wav"
};
new const gSoundKnifeHit[][] = {
"weapons/knife_hit1.wav",
"weapons/knife_hit2.wav",
"weapons/knife_hit3.wav",
"weapons/knife_hit4.wav"
};
new const gSoundKnifeSlash[][] = {
"weapons/knife_slash1.wav",
"weapons/knife_slash2.wav"
};
#define ATTACK_PRIMARY 1
#define ATTACK_SECONDARY 2
public plugin_init() {
register_plugin("Delay Knife Attack", "1.0", "[ --{-@ ]");
register_concmd("amok","cmd_buy");
RegisterHam(Ham_Killed, "player", "fwd_Killed");
RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_knife", "fwd_Weapon_PrimaryAttack_Pre");
RegisterHam(Ham_Weapon_SecondaryAttack, "weapon_knife", "fwd_Weapon_SecondaryAttack_Pre");
RegisterHam(Ham_TraceAttack, "player", "fwd_TraceAttack_Pre");
RegisterHam(Ham_Item_Deploy, "weapon_knife", "fwd_ItemDeploy_Post", 1);
register_forward(FM_EmitSound, "fwd_EmitSound");
if ( ( gKnifeEntity = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "weapon_knife")) ) )
set_pdata_int(gKnifeEntity, m_pPlayer, 0, 4); // Just so Ham won't deny us.
pCvar_PriDelay = register_cvar("knife_delay_pri", "0.5");
pCvar_PriDamage = register_cvar("knife_damage_pri", "1.2");
pCvar_PriFreq = register_cvar("knife_frequency_pri", "1.0");
pCvar_PriRange = register_cvar("knife_range_pri", "48");
pCvar_SecDelay = register_cvar("knife_delay_sec", "0.8");
pCvar_SecDamage = register_cvar("knife_damage_sec", "1.2");
pCvar_SecFreq = register_cvar("knife_frequency_sec", "1.2");
pCvar_SecRange = register_cvar("knife_range_sec", "32");
gMaxPlayers = get_maxplayers();
}
public fwd_EmitSound(id, channel, const sound[], Float:vol, Float:attn, flags, pitch) {
if ( is_user_connected(id) && gKnife[id] && ( channel == CHAN_WEAPON || channel == CHAN_ITEM ) && equal(sound, "weapons/knife_", 14) && ! equal(sound[14], "deploy", 6) )
return FMRES_SUPERCEDE;
return FMRES_IGNORED;
}
public plugin_precache() {
precache_model(P_MODEL);
precache_model(V_MODEL);
gPModel = engfunc(EngFunc_AllocString, P_MODEL);
gVModel = engfunc(EngFunc_AllocString, V_MODEL);
for ( new i = 0 ; i < sizeof gSoundBHitFlesh ; i++ )
precache_sound(gSoundBHitFlesh[i]);
for ( new i = 0 ; i < sizeof gSoundKnifeHit ; i++ )
precache_sound(gSoundKnifeHit[i]);
for ( new i = 0 ; i < sizeof gSoundKnifeSlash ; i++ )
precache_sound(gSoundKnifeSlash[i]);
}
public client_disconnect(id) {
gKnife[id] = false;
remove_task(id);
}
public cmd_buy(id)
gKnife[id] = true;
public fwd_ItemDeploy_Post(ent) {
new id = get_pdata_cbase(ent, m_pPlayer, 4);
if ( is_user_alive(id) && gKnife[id] ) {
set_pev_string(id, pev_weaponmodel2, gPModel);
set_pev_string(id, pev_viewmodel2, gVModel);
}
}
public fwd_TraceAttack_Pre(victim, attacker, Float:damage, Float:direction[3], tracehandle, damagebits) {
if ( 1 <= attacker <= gMaxPlayers && gKnife[attacker] )
return HAM_SUPERCEDE;
return HAM_IGNORED;
}
public fwd_Weapon_PrimaryAttack_Pre(ent)
ProcessAttack(ent, ATTACK_PRIMARY);
public fwd_Weapon_SecondaryAttack_Pre(ent)
ProcessAttack(ent, ATTACK_SECONDARY);
ProcessAttack(ent, AttackType) {
new id = get_pdata_cbase(ent, m_pPlayer, 4);
if ( ! gKnife[id] )
return;
new TaskData[2];
TaskData[0] = id;
TaskData[1] = AttackType;
set_pdata_float(id, m_flNextAttack, AttackType == ATTACK_PRIMARY ? get_pcvar_float(pCvar_PriFreq) : get_pcvar_float(pCvar_SecFreq), 5);
set_task(AttackType == ATTACK_PRIMARY ? get_pcvar_float(pCvar_PriDelay) : get_pcvar_float(pCvar_SecDelay), "task_DelayAttack", id, TaskData, 2);
}
public task_DelayAttack(TaskData[]) {
new id = TaskData[0];
new AttackType = TaskData[1];
new Float:viewofs[3];
new Float:start[3];
new Float:end[3];
new Float:AimVec[3];
pev(id, pev_origin, start);
pev(id, pev_view_ofs, viewofs);
xs_vec_add(start, viewofs, start);
velocity_by_aim(id, 1, AimVec);
xs_vec_mul_scalar(AimVec, AttackType == ATTACK_PRIMARY ? get_pcvar_float(pCvar_PriRange) : get_pcvar_float(pCvar_SecRange), end);
xs_vec_add(start, end, end);
new hTrace, Float:trFraction, bool:trHull;
engfunc(EngFunc_TraceLine, start, end, DONT_IGNORE_MONSTERS, id, hTrace);
get_tr2(hTrace, TR_flFraction, trFraction);
if ( trFraction >= 1.00 ) {
engfunc(EngFunc_TraceHull, start, end, DONT_IGNORE_MONSTERS, HULL_HEAD, id, hTrace);
get_tr2(hTrace, TR_flFraction, trFraction);
trHull = true;
}
if ( trFraction >= 1.00 )
emit_sound(id, CHAN_WEAPON, gSoundKnifeSlash[random(sizeof gSoundKnifeSlash)], VOL_NORM, ATTN_NORM, 0, 94);
else {
new trPlayer = get_tr2(hTrace, TR_pHit);
if ( 1 <= trPlayer <= gMaxPlayers ) {
emit_sound(trPlayer, CHAN_VOICE, gSoundBHitFlesh[random(sizeof gSoundBHitFlesh)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
new hTraceAttack = create_tr2();
if ( trHull )
engfunc(EngFunc_TraceHull, start, end, DONT_IGNORE_MONSTERS, HULL_HEAD, id, hTraceAttack);
else
engfunc(EngFunc_TraceLine, start, end, DONT_IGNORE_MONSTERS, id, hTraceAttack);
ExecuteHam(Ham_TraceAttack, trPlayer, id, AttackType == ATTACK_PRIMARY ? PrimaryDamage[0] : SecondaryDamage[0], AimVec, hTraceAttack, DMG_BULLET|DMG_NEVERGIB);
free_tr2(hTraceAttack);
if ( AttackType == ATTACK_PRIMARY ) {
emit_sound(id, CHAN_WEAPON, gSoundKnifeHit[random(sizeof gSoundKnifeHit)], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
ExecuteHam(Ham_TakeDamage, trPlayer, gKnifeEntity, id, PrimaryDamage[get_tr2(hTrace, TR_iHitgroup)] * get_pcvar_float(pCvar_PriDamage), DMG_BULLET|DMG_NEVERGIB);
}
else {
emit_sound(id, CHAN_WEAPON, "weapons/knife_stab.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
ExecuteHam(Ham_TakeDamage, trPlayer, gKnifeEntity, id, ( SecondaryDamage[get_tr2(hTrace, TR_iHitgroup)] * get_pcvar_float(pCvar_SecDamage) * ( ( IsBackstab(id, trPlayer) ) ? 3.0 : 1.0 ) ), DMG_BULLET|DMG_NEVERGIB);
}
}
else
emit_sound(id, CHAN_ITEM, "weapons/knife_hitwall1.wav", VOL_NORM, ATTN_NORM, 0, random_num(98, 101));
}
free_tr2(hTrace);
}
bool:IsBackstab(const attacker, const victim) {
new Float: vec1[3];
new Float: vec2[3];
velocity_by_aim(attacker, 1, vec1);
new Float:invlen = xs_rsqrt(vec1[0] * vec1[0] + vec1[1] * vec1[1]);
vec1[0] *= invlen;
vec1[1] *= invlen;
pev(victim, pev_angles, vec2);
angle_vector(vec2, ANGLEVECTOR_FORWARD, vec2);
return vec1[0] * vec2[0] + vec1[1] * vec2[1] > 0.8 ? true : false;
}
public fwd_Killed(victim, attacker, shouldgib)
remove_task(victim);