Kod php:
/*
* v1.2.0 (17mar2008)
* -now hook traceline forward to get the exact (at least more accurate) bullet trace
*
* v1.1.2 (13mar2008)
* -removed famas multi-tracers
*
* v1.1.1 (23jan2008)
* -fixed error when silenced m4 made burst tracers
*
* v1.1
* -changed message_begin with EngFunc_MessageBegin to avoid changing floats into integers
* -made some strings as const
* -replaced 'if statments' with 'switch statements' in PlaybackEvent forward
* -tmp is now considered as a silent weapon (can be disabled by commenting #define TMP_IS_A_SILENCED_WEAPON)
* -added command 'say /tracers' so player can switch on/off tracers (can be disabled by commenting #define PER_PLAYER_SETTINGS)
* -cvar amx_trace_hltv, so tracers are sent to HLTV (if #define PER_PLAYER_SETTINGS is commented, tracers are always sent to HLTVs)
* -added public cvar
*
* v1.0 First Release
*/
/************** CUSTOMIZATION AREA ***************/
#define TMP_IS_A_SILENCED_WEAPON
// #define PER_PLAYER_SETTINGS
/*********** END OF CUSTOMIZATION AREA ***********/
#include <amxmodx>
#include <fakemeta>
#include <xs>
#define VERSION "1.2.0"
#define MAX_PLAYERS 32
#define EXTRAOFFSET_WEAPONS 4
#define OFFSET_SILENCER_FIREMODE 74
#define USP_SILENCED (1<<0)
#define M4A1_SILENCED (1<<2)
#define GLOCK_BURSTMODE 2
#define FAMAS_BURSTMODE 16
#define SHOTGUN_SPREAD 0.05240777928304120404
#define BURST_SPREAD 0.01745506492821758577
#define MAX_GUNTYPES_NUM 5
#define MAX_GUNS_NUM 7
#define GET_SILEN_BURST_OFFSET(%1) get_pdata_int(%1, OFFSET_SILENCER_FIREMODE, EXTRAOFFSET_WEAPONS)
enum TracerType {
Tracer_Normal = 0,
Tracer_Burst,
Tracer_Shotgun
}
enum PcvarsNum {
HandGuns = 0,
ShotGuns,
SmgGuns,
RiffleGuns,
SnipeGuns
}
new g_iForwardId
new g_iMaxClients
new const g_szGunsEvents[MAX_GUNTYPES_NUM][MAX_GUNS_NUM][] = {
{ "events/usp.sc" , "events/fiveseven.sc" , "events/deagle.sc" , "events/p228.sc" ,
"events/glock18.sc", "events/elite_left.sc", "events/elite_right.sc" },
{ "events/m3.sc" , "events/xm1014.sc" ,"","","","",""},
{ "events/mac10.sc", "events/ump45.sc", "events/p90.sc", "events/mp5n.sc", "events/tmp.sc" ,"",""},
{ "events/m249.sc", "events/m4a1.sc", "events/ak47.sc", "events/sg552.sc",
"events/aug.sc", "events/galil.sc", "events/famas.sc" },
{ "events/awp.sc", "events/g3sg1.sc", "events/scout.sc", "events/sg550.sc" ,"","",""}
}
new g_guns_eventids_bitsum[MAX_GUNTYPES_NUM]
#if defined PER_PLAYER_SETTINGS
new bool:g_bSeeTracers[MAX_PLAYERS+1] = {true, ...}
new g_pcvarTraceHltv
#endif
new Float:g_fLastTrace[MAX_PLAYERS+1]
new g_pcvar[PcvarsNum], g_pcvarTraceEnabled, g_pcvarTraceHideSilen
public plugin_precache() {
g_iForwardId = register_forward(FM_PrecacheEvent, "Forward_PrecacheEvent", 1)
}
public Forward_PrecacheEvent(type, const name[])
{
for(new a; a < MAX_GUNTYPES_NUM; ++a)
{
for(new i; i < MAX_GUNS_NUM; ++i)
{
if(equal(g_szGunsEvents[a][i], name))
{
g_guns_eventids_bitsum[a] |= (1<<get_orig_retval())
return FMRES_HANDLED
}
}
}
return FMRES_IGNORED
}
public plugin_init()
{
register_plugin("Advanced Weapon Tracers", VERSION, "ConnorMcLeod")
unregister_forward(FM_PrecacheEvent, g_iForwardId, 1)
register_forward(FM_PlaybackEvent, "Forward_PlaybackEvent")
register_forward(FM_TraceLine, "Forward_TraceLine_Post", 1)
register_cvar("awt_version", VERSION, FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY)
g_pcvarTraceEnabled = register_cvar("amx_tracers", "1")
g_pcvar[HandGuns] = register_cvar("amx_trace_handguns", "1")
g_pcvar[ShotGuns] = register_cvar("amx_trace_shotguns", "1")
g_pcvar[SmgGuns] = register_cvar("amx_trace_smgguns", "1")
g_pcvar[RiffleGuns] = register_cvar("amx_trace_riffleguns", "1")
g_pcvar[SnipeGuns] = register_cvar("amx_trace_snipeguns", "1")
g_pcvarTraceHideSilen = register_cvar("amx_trace_hide_silen", "1")
#if defined PER_PLAYER_SETTINGS
g_pcvarTraceHltv = register_cvar("amx_trace_hltv", "1")
register_clcmd("say /tracers", "clcmdSwitch")
#endif
g_iMaxClients = global_get(glb_maxClients)
}
#if defined PER_PLAYER_SETTINGS
public client_putinserver(id)
{
g_bSeeTracers[id] = true
set_task(35.0, "task_announce", id)
}
public client_disconnect(id)
{
g_bSeeTracers[id] = false
}
public clcmdSwitch(id)
{
g_bSeeTracers[id] = !g_bSeeTracers[id]
client_print(id, print_chat, "** [Advanced Weapon Tracers] Tracers are now %s", g_bSeeTracers[id] ? "ON" : "OFF")
return PLUGIN_HANDLED
}
public task_announce(id)
{
client_print(id, print_chat, "** [Advanced Weapon Tracers] You can [en/dis]able tracers by typing /tracers in chat")
}
#endif
public Forward_PlaybackEvent(flags, invoker, eventid)
{
if( !get_pcvar_num(g_pcvarTraceEnabled) )
return FMRES_IGNORED
if( !(1 <= invoker <= g_iMaxClients) )
return FMRES_IGNORED
for(new a; a < MAX_GUNTYPES_NUM; a++)
{
if( !(g_guns_eventids_bitsum[a] & (1<<eventid)) || !get_pcvar_num(g_pcvar[PcvarsNum:a]) )
continue
switch(a)
{
case 0:
{
static update_the_compiler
switch( get_user_weapon(invoker, update_the_compiler, update_the_compiler) )
{
case CSW_USP:
{
if( get_pcvar_num(g_pcvarTraceHideSilen) &&
get_weapon_silen(invoker, CSW_USP) )
{
return FMRES_IGNORED
}
else
{
make_tracer(invoker, Tracer_Normal)
}
}
case CSW_GLOCK18:
{
if( get_glock_busrt(invoker) )
{
make_tracer(invoker, Tracer_Burst)
}
else
{
make_tracer(invoker, Tracer_Normal)
}
}
default:
{
make_tracer(invoker, Tracer_Normal)
}
}
}
case 1:
{
make_tracer(invoker, Tracer_Shotgun)
}
case 3:
{
static heaven_knows
switch( get_user_weapon(invoker, heaven_knows, heaven_knows) )
{
case CSW_M4A1:
{
if( get_pcvar_num(g_pcvarTraceHideSilen) && get_weapon_silen(invoker, CSW_M4A1) )
{
return FMRES_IGNORED
}
else
{
make_tracer(invoker, Tracer_Normal)
}
}
#if defined TMP_IS_A_SILENCED_WEAPON
case CSW_TMP:
{
if( get_pcvar_num(g_pcvarTraceHideSilen) )
{
return FMRES_IGNORED
}
else
{
make_tracer(invoker, Tracer_Normal)
}
}
#endif
default:
{
make_tracer(invoker, Tracer_Normal)
}
}
}
default :
{
make_tracer(invoker, Tracer_Normal)
}
}
return FMRES_HANDLED
}
return FMRES_IGNORED
}
public Forward_TraceLine_Post(const Float:v1, const Float:v2, fNoMonsters, id, ptr)
{
if( id && ( pev(id, pev_flags) & (FL_CLIENT | FL_FAKECLIENT) ) )
{
get_tr2(ptr, TR_vecEndPos, g_fLastTrace[id])
}
return FMRES_IGNORED
}
make_tracer(id, TracerType:type=Tracer_Normal)
{
static Float:start[3], Float:dest[3]
pev(id, pev_origin, start)
pev(id, pev_view_ofs, dest)
xs_vec_add(start, dest, start)
xs_vec_copy(g_fLastTrace[id], dest)
switch( type )
{
case Tracer_Normal:
{
do_trace(start, dest)
}
case Tracer_Shotgun:
{
static Float:tempdest[3], Float:temp
do_trace(start, dest)
xs_vec_sub(dest, start, tempdest)
temp = SHOTGUN_SPREAD * xs_vec_len(tempdest)
for(new i; i < 3; ++i)
{
xs_vec_copy(dest, tempdest)
tempdest[i] += temp
do_trace(start, tempdest)
xs_vec_copy(dest, tempdest)
tempdest[i] -= temp
do_trace(start, tempdest)
}
}
case Tracer_Burst:
{
static Float:tempdest[3], Float:temp
do_trace(start, dest)
xs_vec_sub(dest, start, tempdest)
temp = BURST_SPREAD * xs_vec_len(tempdest)
xs_vec_copy(dest, tempdest)
tempdest[0] += temp
tempdest[1] += temp
tempdest[2] += temp
do_trace(start, tempdest)
xs_vec_copy(dest, tempdest)
tempdest[0] -= temp
tempdest[1] -= temp
tempdest[2] -= temp
do_trace(start, tempdest)
}
}
}
do_trace(Float:origin[], Float:dest[])
{
#if !defined PER_PLAYER_SETTINGS
engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, origin, 0)
ewrite_byte(TE_TRACER)
engfunc(EngFunc_WriteCoord, origin[0])
engfunc(EngFunc_WriteCoord, origin[1])
engfunc(EngFunc_WriteCoord, origin[2])
engfunc(EngFunc_WriteCoord, dest[0])
engfunc(EngFunc_WriteCoord, dest[1])
engfunc(EngFunc_WriteCoord, dest[2])
emessage_end()
#else
static player
for(player=1; player<=g_iMaxClients; player++)
{
if(!g_bSeeTracers[player])
continue
if((pev(player, pev_flags) & FL_PROXY) && get_pcvar_num(g_pcvarTraceHltv))
{
engfunc(EngFunc_MessageBegin, MSG_SPEC, SVC_TEMPENTITY, origin, 0)
ewrite_byte(TE_TRACER)
engfunc(EngFunc_WriteCoord, origin[0])
engfunc(EngFunc_WriteCoord, origin[1])
engfunc(EngFunc_WriteCoord, origin[2])
engfunc(EngFunc_WriteCoord, dest[0])
engfunc(EngFunc_WriteCoord, dest[1])
engfunc(EngFunc_WriteCoord, dest[2])
emessage_end()
continue
}
engfunc(EngFunc_MessageBegin, MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, origin, player)
ewrite_byte(TE_TRACER)
engfunc(EngFunc_WriteCoord, origin[0])
engfunc(EngFunc_WriteCoord, origin[1])
engfunc(EngFunc_WriteCoord, origin[2])
engfunc(EngFunc_WriteCoord, dest[0])
engfunc(EngFunc_WriteCoord, dest[1])
engfunc(EngFunc_WriteCoord, dest[2])
emessage_end()
}
#endif
}
get_glock_busrt(id)
{
static ent
static const szWeaponGlock18[] = "weapon_glock18"
ent = fm_find_ent_by_owner(g_iMaxClients, szWeaponGlock18, id)
return (GET_SILEN_BURST_OFFSET(ent) == GLOCK_BURSTMODE)
}
get_weapon_silen(id, weaponid)
{
static ent
switch( weaponid )
{
case CSW_USP:
{
static const szWeaponUsp[] = "weapon_usp"
ent = fm_find_ent_by_owner(g_iMaxClients, szWeaponUsp, id)
if(GET_SILEN_BURST_OFFSET(ent) & USP_SILENCED)
return 1
}
case CSW_M4A1:
{
static const szWeaponM4a1[] = "weapon_m4a1"
ent = fm_find_ent_by_owner(g_iMaxClients, szWeaponM4a1, id)
if(GET_SILEN_BURST_OFFSET(ent) & M4A1_SILENCED)
return 1
}
}
return 0
}
fm_find_ent_by_owner(index, const classname[], owner) {
static ent ; ent = index
static const szClassname[] = "classname"
while((ent = engfunc(EngFunc_FindEntityByString, ent, szClassname, classname)) && pev(ent, pev_owner) != owner) {}
return ent
}