Загрузка данных
/*
*
* Corpse Gore by RedSMURF
*
*
* Description:
*
* Cvars:
* corpsegore_enable - Enable or disable the plugin.
* corpsegore_gib_knife - Gib corpses killed with a knife.
* corpsegore_gib_explosive - Gib corpses killed by explosives.
* corpsegore_break_velocity - Velocity applied to flying gibs.
* corpsegore_break_count - Number of gibs spawned.
* corpsegore_break_life - Gib lifetime in seconds.
* corpsegore_blood_color - Blood color (195 - Yellow, 247 - Red).
* corpsegore_blood_scale - Blood effect scale.
*
* Commands:
* None
*
* Changelog:
* v1.0: Initial release.
*
*/
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#define PLUGIN_VERSION "1.1"
#define CORPSEGORE_KEY 981222
#define CORPSEGORE_PENDING pev_iuser1
#define CORPSE_BREAK_FLESH 0x04
#define CORPSE_DMG_EXPLOSIVE ((1 << 6) | (1 << 24))
#define CORPSE_BONES 36
#define CORPSE_PAD 8.0
#define CORPSE_HEIGHT 0.1
new g_cvarEnable, g_cvarGibKnife, g_cvarGibExplosive, g_cvarBreakVelocity, g_cvarBreakCount, g_cvarBreakLife,
g_cvarBloodColor, g_cvarBloodScale,
bool:g_bEnable, bool:g_bGibKnife, bool:g_bGibExplosive, g_iBreakVelocity, g_iBreakCount, g_iBreakLife,
g_iBloodColor, g_iBloodScale
new g_iSprite, g_iSpriteSpray, g_iModelGibs, g_iMaxPlayers
new g_iDecal[2] = {204, 205}
new Float:g_fKnifeHit[33]
new g_szSoundKnife[] = "common/bodysplat.wav"
new g_szCN[] = "corpse_gore"
public plugin_init()
{
register_plugin("Corpse Gore", PLUGIN_VERSION, "RedSMURF")
register_cvar("RedSMURF_CorpseGore", PLUGIN_VERSION, FCVAR_SERVER | FCVAR_SPONLY)
g_cvarEnable = register_cvar("corpsegore_enable", "1")
g_cvarGibKnife = register_cvar("corpsegore_gib_knife", "1")
g_cvarGibExplosive = register_cvar("corpsegore_gib_explosive", "1")
g_cvarBreakVelocity = register_cvar("corpsegore_break_velocity", "12")
g_cvarBreakCount = register_cvar("corpsegore_break_count", "12")
g_cvarBreakLife = register_cvar("corpsegore_break_life", "50")
g_cvarBloodColor = register_cvar("corpsegore_blood_color", "247") // 195 - Yellow, 247 - Red
g_cvarBloodScale = register_cvar("corpsegore_blood_scale", "10")
cvarCache()
hook_cvar_change(g_cvarEnable, "cvarUpdate")
hook_cvar_change(g_cvarGibKnife, "cvarUpdate")
hook_cvar_change(g_cvarGibExplosive, "cvarUpdate")
hook_cvar_change(g_cvarBreakVelocity, "cvarUpdate")
hook_cvar_change(g_cvarBreakCount, "cvarUpdate")
hook_cvar_change(g_cvarBreakLife, "cvarUpdate")
hook_cvar_change(g_cvarBloodColor, "cvarUpdate")
hook_cvar_change(g_cvarBloodScale, "cvarUpdate")
register_message(get_user_msgid("ClCorpse"), "msgClCorpse")
register_forward(FM_EmitSound, "fwdEmitSound")
RegisterHam(Ham_TraceAttack, "info_target", "fwdTraceAttack")
RegisterHam(Ham_TakeDamage, "info_target", "fwdTakeDamage")
register_logevent("eventRoundStart", 2, "1=Round_Start")
g_iMaxPlayers = get_maxplayers()
}
public plugin_precache()
{
g_iSprite = engfunc(EngFunc_PrecacheModel, "sprites/blood.spr")
g_iSpriteSpray = engfunc(EngFunc_PrecacheModel, "sprites/bloodspray.spr")
g_iModelGibs = engfunc(EngFunc_PrecacheModel, "models/hgibs.mdl")
precache_sound(g_szSoundKnife)
}
public cvarUpdate(pCvar, const OldValue[], const NewValue[])
{
cvarCache()
}
public cvarCache()
{
g_bEnable = get_pcvar_num(g_cvarEnable) == 1
g_bGibKnife = get_pcvar_num(g_cvarGibKnife) == 1
g_bGibExplosive = get_pcvar_num(g_cvarGibExplosive) == 1
g_iBreakVelocity = clamp(get_pcvar_num(g_cvarBreakVelocity), 0, 255)
g_iBreakCount = clamp(get_pcvar_num(g_cvarBreakCount), 0, 255)
g_iBreakLife = clamp(get_pcvar_num(g_cvarBreakLife), 0, 255)
g_iBloodColor = clamp(get_pcvar_num(g_cvarBloodColor), 0, 255)
g_iBloodScale = clamp(get_pcvar_num(g_cvarBloodScale), 0, 255)
}
public eventRoundStart()
{
new iEnt = -1
while ( (iEnt = engfunc(EngFunc_FindEntityByString, iEnt, "classname", g_szCN)) )
{
remove_task(iEnt)
corpseGoreKill(iEnt)
}
}
public msgClCorpse()
{
if ( !g_bEnable )
return PLUGIN_CONTINUE
new szModel[32]
get_msg_arg_string(1, szModel, charsmax(szModel))
new Float:fOrigin[3], Float:fAngles[3]
for ( new i; i < 3; i ++ )
{
fOrigin[i] = float(get_msg_arg_int(2 + i)) / 128.0
fAngles[i] = get_msg_arg_float(5 + i)
}
corpseCreate(szModel, fOrigin, fAngles, get_msg_arg_int(9), get_msg_arg_int(10))
return PLUGIN_HANDLED
}
public fwdEmitSound(id, iChannel, const szSample[], Float:fVol, Float:fAttn, iFlags, iPitch)
{
if ( !g_bEnable
|| !(1 <= id <= g_iMaxPlayers)
|| get_gametime() - g_fKnifeHit[id] > 0.1
|| !equal(szSample, "weapons/knife_hitwall1.wav") )
return FMRES_IGNORED
engfunc(EngFunc_EmitSound, id, iChannel, g_szSoundKnife, fVol, fAttn, iFlags, iPitch)
return FMRES_SUPERCEDE
}
public fwdTraceAttack(iEnt, iAttacker, Float:fDamage, Float:fDir[3], iTr, iBits)
{
if ( !g_bEnable || !isCorpseGore(iEnt) || pev(iEnt, CORPSEGORE_PENDING) )
return HAM_IGNORED
if ( g_bGibKnife && is_user_alive(iAttacker) && get_user_weapon(iAttacker) == CSW_KNIFE )
{
g_fKnifeHit[iAttacker] = get_gametime()
corpseGoreGib(iEnt)
return HAM_SUPERCEDE
}
new Float:fEnd[3]
get_tr2(iTr, TR_vecEndPos, fEnd)
corpseGoreBlood(fEnd)
return HAM_SUPERCEDE
}
public fwdTakeDamage(iEnt, iInflictor, iAttacker, Float:fDamage, iBits)
{
if ( !g_bEnable
|| !isCorpseGore(iEnt)
|| !(iBits & CORPSE_DMG_EXPLOSIVE) )
return HAM_IGNORED
if ( g_bGibExplosive )
corpseGoreGib(iEnt)
return HAM_SUPERCEDE
}
public corpseGoreTask(iEnt)
{
if ( !isCorpseGore(iEnt) || !pev(iEnt, CORPSEGORE_PENDING) )
{
remove_task(iEnt)
return
}
if ( !corpseBlocked(iEnt) )
corpseActivate(iEnt)
}
stock corpseCreate(const szModel[], const Float:fOrigin[3], const Float:fAngles[3], iSequence, iBody)
{
new iEnt = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
if ( !pev_valid(iEnt) )
return 0
new szPath[96]
formatex(szPath, charsmax(szPath), "models/player/%s/%s.mdl", szModel, szModel)
set_pev(iEnt, pev_classname, g_szCN)
set_pev(iEnt, pev_impulse, CORPSEGORE_KEY)
set_pev(iEnt, CORPSEGORE_PENDING, 1)
dllfunc(DLLFunc_Spawn, iEnt)
engfunc(EngFunc_SetOrigin, iEnt, fOrigin)
set_pev(iEnt, pev_angles, fAngles)
set_pev(iEnt, pev_solid, SOLID_NOT)
set_pev(iEnt, pev_movetype, MOVETYPE_NONE)
engfunc(EngFunc_SetModel, iEnt, szPath)
set_pev(iEnt, pev_body, iBody)
set_pev(iEnt, pev_sequence, iSequence)
set_pev(iEnt, pev_frame, 255.0)
set_pev(iEnt, pev_framerate, 0.0)
set_pev(iEnt, pev_animtime, get_gametime())
corpseFitBox(iEnt)
if ( corpseBlocked(iEnt) )
set_task(0.1, "corpseGoreTask", iEnt, .flags = "b")
else
corpseActivate(iEnt)
return iEnt
}
stock corpseActivate(iEnt)
{
new Float:fOrigin[3]
pev(iEnt, pev_origin, fOrigin)
set_pev(iEnt, CORPSEGORE_PENDING, 0)
set_pev(iEnt, pev_solid, SOLID_BBOX)
set_pev(iEnt, pev_takedamage, DAMAGE_YES)
engfunc(EngFunc_SetOrigin, iEnt, fOrigin)
remove_task(iEnt)
}
stock bool:corpseBlocked(iEnt)
{
new Float:fMin[3], Float:fMax[3], Float:fPMin[3], Float:fPMax[3]
pev(iEnt, pev_absmin, fMin)
pev(iEnt, pev_absmax, fMax)
for ( new id = 1, bool:bOverlap; id <= g_iMaxPlayers; id ++ )
{
if ( !is_user_alive(id) )
continue
pev(id, pev_absmin, fPMin)
pev(id, pev_absmax, fPMax)
bOverlap = true
for ( new i; i < 3; i ++ )
{
if ( fPMin[i] >= fMax[i] || fPMax[i] <= fMin[i] )
{
bOverlap = false
break
}
}
if ( bOverlap )
return true
}
return false
}
stock corpseFitBox(iEnt)
{
new Float:fOrigin[3], Float:fEnd[3], Float:fBone[3], Float:fAng[3]
pev(iEnt, pev_origin, fOrigin)
fEnd = fOrigin
fEnd[2] -= 64.0
engfunc(EngFunc_TraceLine, fOrigin, fEnd, IGNORE_MONSTERS, iEnt, 0)
get_tr2(0, TR_vecEndPos, fEnd)
new Float:fFloor = fEnd[2] - fOrigin[2]
new Float:fMins[3], Float:fMaxs[3], bool:bFound
for ( new i = 0; i < 2; i ++ )
{
fMins[i] = 9999.0
fMaxs[i] = -9999.0
}
for ( new b; b < CORPSE_BONES; b ++ )
{
engfunc(EngFunc_GetBonePosition, iEnt, b, fBone, fAng)
if ( get_distance_f(fBone, fOrigin) > 100.0 )
continue
for ( new i; i < 2; i ++ )
{
fMins[i] = floatmin(fMins[i], fBone[i] - fOrigin[i])
fMaxs[i] = floatmax(fMaxs[i], fBone[i] - fOrigin[i])
}
bFound = true
}
for ( new i; i < 2; i ++ )
{
if ( bFound )
{
fMins[i] -= CORPSE_PAD
fMaxs[i] += CORPSE_PAD
}
else
{
fMins[i] = -36.0
fMaxs[i] = 36.0
}
}
fMins[2] = fFloor
fMaxs[2] = fFloor + CORPSE_HEIGHT
engfunc(EngFunc_SetSize, iEnt, fMins, fMaxs)
engfunc(EngFunc_SetOrigin, iEnt, fOrigin)
}
stock corpseGoreGib(iEnt)
{
new Float:fMin[3], Float:fMax[3], Float:fPos[3], Float:fSize[3]
pev(iEnt, pev_absmin, fMin)
pev(iEnt, pev_absmax, fMax)
fPos[0] = (fMin[0] + fMax[0]) * 0.5
fPos[1] = (fMin[1] + fMax[1]) * 0.5
fPos[2] = fMin[2] + 8.0
fSize[0] = (fMax[0] - fMin[0]) * 0.25
fSize[1] = (fMax[1] - fMin[1]) * 0.25
fSize[2] = 8.0
message_begin_f(MSG_PVS, SVC_TEMPENTITY, fPos)
write_byte(TE_BREAKMODEL)
write_coord_f(fPos[0])
write_coord_f(fPos[1])
write_coord_f(fPos[2])
write_coord_f(fSize[0])
write_coord_f(fSize[1])
write_coord_f(fSize[2])
write_coord_f(0.0)
write_coord_f(0.0)
write_coord_f(0.0)
write_byte(random_num(g_iBreakVelocity - 2, g_iBreakVelocity + 2))
write_short(g_iModelGibs)
write_byte(random_num(g_iBreakCount - 3, g_iBreakCount + 3))
write_byte(random_num(g_iBreakLife - 15, g_iBreakLife + 15))
write_byte(CORPSE_BREAK_FLESH)
message_end()
corpseGoreBlood(fPos)
corpseGoreDecals(fPos)
corpseGoreKill(iEnt)
}
stock corpseGoreDecals(const Float:fCenter[3])
{
new Float:fStart[3], Float:fEnd[3], Float:fFraction
fStart = fCenter
fEnd = fStart
fEnd[2] -= 24.0
engfunc(EngFunc_TraceLine, fStart, fEnd, IGNORE_MONSTERS, 0, 0)
get_tr2(0, TR_flFraction, fFraction)
if ( fFraction >= 1.0 )
return
get_tr2(0, TR_vecEndPos, fEnd)
message_begin_f(MSG_BROADCAST, SVC_TEMPENTITY, fEnd)
write_byte(TE_WORLDDECAL)
write_coord_f(fEnd[0])
write_coord_f(fEnd[1])
write_coord_f(fEnd[2])
write_byte(g_iDecal[random_num(0, sizeof(g_iDecal) - 1)])
message_end()
}
stock corpseGoreBlood(const Float:fPos[3])
{
message_begin_f(MSG_PVS, SVC_TEMPENTITY, fPos)
write_byte(TE_BLOODSPRITE)
write_coord_f(fPos[0])
write_coord_f(fPos[1])
write_coord_f(fPos[2])
write_short(g_iSpriteSpray)
write_short(g_iSprite)
write_byte(g_iBloodColor)
write_byte(random_num(g_iBloodScale - 3, g_iBloodScale + 3))
message_end()
}
stock isCorpseGore(iEnt)
{
return pev_valid(iEnt) && pev(iEnt, pev_impulse) == CORPSEGORE_KEY
}
stock corpseGoreKill(iEnt)
{
if ( pev_valid(iEnt) )
engfunc(EngFunc_RemoveEntity, iEnt)
}