[SNIPPET] NPC DeathMSG
Posted: Sun Oct 11, 2026 6:26 pm
I've found a way to make an npc fake deathmsg, i thought i'd share since i had never found something similar on the web.
basically what this function do is it creates a bot if an npc entity id was passed into either the killer or id ( victim ) parameters or both, and it kicks the bot/s once the fake deathmsg is sent.
NPC entity name must be set into globalname keyvalue, or you can change that if you're using one npc name for all.
Adding a delay of 1.0 second to Make_NPC_DeathMsg is recommended if you're going to call it many times per second.
Code: Select all
#include <fakemeta>
#define TASK_NPC_DEATHMSG 11030
enum any:DEATHMSG_DATA (+=1) {
DEATHMSG_VICTIM_ID = 0,
DEATHMSG_KILLER_ID,
bool:DEATHMSG_bHEADSHOT,
DEATHMSG_WEAPON_NAME[24],
DEATHMSG_VIC_NAME[32],
DEATHMSG_KILLER_NAME[32]
}
public NPC_ENTITY_KILLED_PRE(const id, const killer, const gibs)
{
static szClass[32];
pev(id, pev_classname, szClass, charsmax(szClass));
set_pev(id, pev_deadflag, DEAD_DYING);
set_pev(id, pev_takedamage, DAMAGE_NO);
set_pev(id, pev_solid, SOLID_NOT);
set_pev(id, PEV_TASK, NPC_DEATH);
static szVicName[32];
pev(id, pev_netname, szVicName, charsmax(szVicName));
pev(id, PEV_WEAPON_INFLICTOR, szClass, charsmax(szClass));
if(!szVicName[0])
{
copy(szVicName, charsmax(szVicName), "Unnamed");
set_pev(id, pev_netname, szVicName);
}
new iPlayerPointer = get_user_index(szVicName);
if( iPlayerPointer )
{
remove_task( iPlayerPointer + TASK_NPC_DEATHMSG );
}
static iNPC_DeathMSG_Data[DEATHMSG_DATA];
iNPC_DeathMSG_Data[DEATHMSG_VICTIM_ID] = id;
iNPC_DeathMSG_Data[DEATHMSG_KILLER_ID] = killer;
iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME][0] = EOS;
if(IsPlayer(killer))
{
get_user_name(killer, iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME], charsmax(iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME]));
}
else if(killer && (pev(killer, pev_flags) & FL_MONSTER))
{
static szKillerName[32];
pev(killer, pev_netname, szKillerName, charsmax(szKillerName));
if(!szKillerName[0])
{
copy(szKillerName, charsmax(szKillerName), "Unnamed");
set_pev(killer, pev_netname, szKillerName);
}
copy(iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME], charsmax(iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME]), szKillerName);
iPlayerPointer = get_user_index(szKillerName);
if( iPlayerPointer )
{
remove_task( iPlayerPointer + TASK_NPC_DEATHMSG );
}
}
iNPC_DeathMSG_Data[DEATHMSG_bHEADSHOT] = false;
copy(iNPC_DeathMSG_Data[DEATHMSG_WEAPON_NAME], charsmax(iNPC_DeathMSG_Data[DEATHMSG_WEAPON_NAME]), szClass);
copy(iNPC_DeathMSG_Data[DEATHMSG_VIC_NAME], charsmax(iNPC_DeathMSG_Data[DEATHMSG_VIC_NAME]), szVicName);
static xFuncID, iReturnVal;
pev(id, pev_classname, szClass, charsmax(szClass));
TrieGetCell(g_trie_NPC_CLASS_DEATH_CALLBACK, szClass, xFuncID);
if( xFuncID != INVALID_HANDLE )
{
ExecuteForward(xFuncID, iReturnVal, id, killer, gibs);
}
Initiate_NPC_DEATHMSG(iNPC_DeathMSG_Data);
// Lets call think
set_pev(id, pev_nextthink, get_gametime() + NPC_THINK_LEN);
call_think(id);
return HAM_SUPERCEDE;
}
stock Initiate_NPC_DEATHMSG(const iNPC_DeathMSG_Data[DEATHMSG_DATA])
{
static szParam[16], Array:xArray;
ArrayPushArray((xArray = ArrayCreate(DEATHMSG_DATA, 1)), iNPC_DeathMSG_Data);
num_to_str(_:xArray, szParam, charsmax(szParam));
static const Float:fInterval_len = 1.0;
static Float:finterval = 0.0, Float:fGameTime;
fGameTime = get_gametime();
if(finterval >= fGameTime)
finterval += fInterval_len;
else
finterval = fGameTime + fInterval_len;
set_task((finterval - fGameTime), "task_interval_NPC_DEATHMSG", iNPC_DeathMSG_Data[DEATHMSG_VICTIM_ID] + TASK_NPC_DEATHMSG, szParam, sizeof szParam);
}
public task_interval_NPC_DEATHMSG(const param[], taskid)
{
static Array:xArray, iNPC_DeathMSG_Data[DEATHMSG_DATA];
xArray = any:str_to_num(param);
ArrayGetArray(xArray, 0, iNPC_DeathMSG_Data);
ArrayDestroy(xArray);
Make_NPC_DeathMsg(iNPC_DeathMSG_Data[DEATHMSG_VICTIM_ID], iNPC_DeathMSG_Data[DEATHMSG_KILLER_ID],
iNPC_DeathMSG_Data[DEATHMSG_VIC_NAME], iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME],
iNPC_DeathMSG_Data[DEATHMSG_bHEADSHOT], iNPC_DeathMSG_Data[DEATHMSG_WEAPON_NAME]);
}
stock Make_NPC_DeathMsg(id, killer, const vicName[32], const killerName[32], const bool:bHeadshot, const weapon[24])
{
if(!id || vicName[0] == EOS)
{
log_error(AMX_ERR_NATIVE, "Attempting to create an NPC DeathMSG with invalid id or vicName!");
return;
}
static iMsg_TeamInfo = 0;
if(!iMsg_TeamInfo) iMsg_TeamInfo = get_user_msgid("TeamInfo");
enum (+=1) {
VICTIM_ID = 0,
KILLER_ID
}
new iTargets[2];
iTargets[VICTIM_ID] = id;
iTargets[KILLER_ID] = killer;
static szRejectReason[128], szName[2][32];
copy(szName[VICTIM_ID], charsmax(szName[]), vicName);
copy(szName[KILLER_ID], charsmax(szName[]), killerName);
if(killerName[0] == EOS)
{
copy(szName[KILLER_ID], charsmax(szName[]), "World");
}
for(new i, iTarget; i < 2; i++)
{
if(szName[i][0] == EOS) continue;
iTarget = iTargets[i];
if(get_user_index(szName[i]) != iTarget)
{
iTarget = iTargets[i] = get_user_index(szName[i]);
}
if( iTarget > 0 )
{
if( IsPlayer(iTarget) && (is_user_connected(iTarget) || is_user_connecting(iTarget)) )
{
remove_task( iTarget + TASK_NPC_DEATHMSG );
continue;
}
}
if( (KILLER_ID == i && iTargets[i] == iTargets[VICTIM_ID]) )
{
continue;
}
iTargets[i] = iTarget = engfunc(EngFunc_CreateFakeClient, szName[i]);
if(!iTarget)
continue;
engfunc(EngFunc_FreeEntPrivateData, iTarget);
if(dllfunc(DLLFunc_ClientConnect, iTarget , szName[i], "127.0.0.1", szRejectReason))
{
dllfunc(DLLFunc_ClientPutInServer, iTarget);
set_pev(iTarget, pev_flags, pev(iTarget, pev_flags) | FL_FAKECLIENT);
set_pev(iTarget, pev_deadflag, DEAD_DISCARDBODY);
message_begin(MSG_BROADCAST, iMsg_TeamInfo, {0,0,0}, 0);
write_byte(iTarget);
write_string("TERRORIST");
message_end();
set_rendering(iTarget, kRenderFxNone, 0, 0, 0, kRenderTransAlpha);
}
}
new szParam[16], Array:xArray, iNPC_DeathMSG_Data[DEATHMSG_DATA];
iNPC_DeathMSG_Data[DEATHMSG_VICTIM_ID] = get_user_userid(iTargets[VICTIM_ID]);
iNPC_DeathMSG_Data[DEATHMSG_KILLER_ID] = get_user_userid(iTargets[KILLER_ID]);
iNPC_DeathMSG_Data[DEATHMSG_bHEADSHOT] = _:bHeadshot;
copy(iNPC_DeathMSG_Data[DEATHMSG_WEAPON_NAME], charsmax(iNPC_DeathMSG_Data[DEATHMSG_WEAPON_NAME]), weapon);
copy(iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME], charsmax(iNPC_DeathMSG_Data[DEATHMSG_KILLER_NAME]), killerName);
copy(iNPC_DeathMSG_Data[DEATHMSG_VIC_NAME], charsmax(iNPC_DeathMSG_Data[DEATHMSG_VIC_NAME]), vicName);
ArrayPushArray((xArray = ArrayCreate(DEATHMSG_DATA,1)), iNPC_DeathMSG_Data);
num_to_str(_:xArray, szParam, charsmax(szParam));
set_task(0.5, "declare_npc_deathmsg", id + TASK_NPC_DEATHMSG, szParam, sizeof szParam);
}
public declare_npc_deathmsg(const szParam[16], const taskid)
{
new Array:xArray = any:str_to_num(szParam), iNPC_DeathMSG_Data[DEATHMSG_DATA];
ArrayGetArray(xArray, 0, iNPC_DeathMSG_Data);
new victim = find_player("k", iNPC_DeathMSG_Data[DEATHMSG_VICTIM_ID]),
killer = find_player("k", iNPC_DeathMSG_Data[DEATHMSG_KILLER_ID]);
if( !is_user_connected(victim) && !is_user_connecting(victim) ||
!is_user_connected(killer) && !is_user_connecting(killer) )
{
ArrayDestroy(xArray);
remove_task(victim + TASK_NPC_DEATHMSG);
remove_task(killer + TASK_NPC_DEATHMSG);
iNPC_DeathMSG_Data[DEATHMSG_VICTIM_ID] = victim;
iNPC_DeathMSG_Data[DEATHMSG_KILLER_ID] = killer;
Initiate_NPC_DEATHMSG(iNPC_DeathMSG_Data);
return;
}
new szNetName[2];
pev(victim, pev_netname, szNetName, 1);
if(szNetName[0] == EOS)
{
set_task(0.1, "declare_npc_deathmsg", taskid, szParam, sizeof szParam);
return;
}
ArrayDestroy(xArray);
make_deathmsg(killer, victim, iNPC_DeathMSG_Data[DEATHMSG_bHEADSHOT], iNPC_DeathMSG_Data[DEATHMSG_WEAPON_NAME]);
if(killer > 0 && pev(killer, pev_flags) & FL_FAKECLIENT)
{
remove_task(killer + TASK_NPC_DEATHMSG);
set_task(1.0, "task_kick_bot", killer + TASK_NPC_DEATHMSG);
}
if(victim > 0 && pev(victim, pev_flags) & FL_FAKECLIENT)
{
remove_task(victim + TASK_NPC_DEATHMSG);
set_task(1.0, "task_kick_bot", victim + TASK_NPC_DEATHMSG);
}
}
public task_kick_bot(id)
{
id -= TASK_NPC_DEATHMSG;
if(is_user_bot(id))
{
server_cmd("kick #%d;", get_user_userid(id));
}
} NPC entity name must be set into globalname keyvalue, or you can change that if you're using one npc name for all.
Adding a delay of 1.0 second to Make_NPC_DeathMsg is recommended if you're going to call it many times per second.