#include <amxmodx>
#include <hamsandwich>
#include <csx>
#include <fakemeta_stocks>
//Definitions
#define VERSION "0.2"
#define IsPlayer(%1) (1 <= %1 <= g_iMaxPlayers && is_user_alive(%1))
#define ResetLen(%1) (%1 = "")
//Enums
enum {
FLASHBANG,
HEGRENADE,
SMOKE
};
enum _:eModels{
VIEW,
PLAYER,
WORLD
};
//Booleans
new bool:g_bIsTouched[0x21][0x200];
//Floats
new Float:g_fMultiplier[0x21];
new Float:g_fValue;
//Strings
new g_sMessage[0x21][0x10];
//Integers
new g_pCvarDamage;
new g_pCvarFade;
new g_mDeath;
new g_mScreenShake;
new g_mSendAudio;
new g_mScreenFade;
new g_iMaxPlayers;
new g_sSprite;
//Constants
new const g_sDownloadableContent[eModels + 2][] = {
"models/flashbangs_can_kill/v_model.mdl",
"models/flashbangs_can_kill/p_model.mdl",
"models/flashbangs_can_kill/w_model.mdl",
"sprites/flashbangs_can_kill/smoczek.spr",
"flashbangs_can_kill/rzut.wav"
};
new const g_iTaskId = 0x539;
new const g_iThrownId = 0x540;
//Unused atm, maybe in next update
#pragma unused g_iThrownId
public plugin_init() {
//Register the plugin
register_plugin("Flashbangs can kill", VERSION, "diablix")
//Define the variables
g_pCvarDamage = register_cvar("flashbang_damage", "5");
g_pCvarFade = register_cvar("flashbang_fade", "1");
g_mDeath = get_user_msgid("DeathMsg");
g_mScreenShake = get_user_msgid("ScreenShake");
g_mSendAudio = get_user_msgid("SendAudio");
g_mScreenFade = get_user_msgid("ScreenFade");
g_iMaxPlayers = get_maxplayers();
g_fValue = float( get_pcvar_num(g_pCvarDamage) );
//Register messages, forward & events
register_message(g_mSendAudio, "msgSendAudio");
register_message(g_mScreenFade, "msgScreenFade");
register_forward(FM_Touch, "fwTouch");
register_forward(FM_SetModel, "fwSetModel");
register_event("CurWeapon", "eventCurWeapon", "be");
RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_flashbang", "fwPrimAttackPost", 1);
}
public plugin_precache(){
//static
static i;
//Precache the whole content (fakemeta way)
for(i = 0 ; i < eModels ; i ++)
engfunc(EngFunc_PrecacheModel, g_sDownloadableContent[i]);
engfunc(EngFunc_PrecacheSound, g_sDownloadableContent[4]);
g_sSprite = engfunc(EngFunc_PrecacheModel, g_sDownloadableContent[3]);
}
public eventCurWeapon(id){
//Reset shake & aim multiplier
g_fMultiplier[id] = 0.0;
//Clear the message
ResetLen(g_sMessage[id]);
//Check for flashbang model
new sModel[0x40];
pev(id, pev_viewmodel2, sModel, sizeof sModel - 1);
set_pev(id, pev_viewmodel2, equal(sModel, "models/v_flashbang.mdl") ? g_sDownloadableContent[VIEW] : sModel);
pev(id, pev_weaponmodel2, sModel, sizeof sModel - 1);
set_pev(id, pev_weaponmodel2, equal(sModel, "models/p_flashbang.mdl") ? g_sDownloadableContent[PLAYER] : sModel);
}
public grenade_throw(iPlayer, iEntity, iGrenadeIndex){
if(iGrenadeIndex == CSW_FLASHBANG){
//Add trail if thrown grenade is flashbang
message_begin(MSG_BROADCAST, SVC_TEMPENTITY);//engfunc(EngFunc_MessageBegin, MSG_ALL, SVC_TEMPENTITY); /*FAKEMETA WAY*/
write_byte(0x16);
write_short(iEntity);
write_short(g_sSprite);
write_byte(0x2D);
write_byte(0x4);
write_byte(0xFF);
write_byte(0xFF);
write_byte(0xFF);
write_byte(0xFF);
message_end();
//Also emit cool sound
emit_sound(iPlayer, CHAN_STATIC, g_sDownloadableContent[4], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
}
}
public fwPrimAttackPost(iEnt){
//static ofc
static iOwner;
//Get entity's owner
iOwner = pev(iEnt, pev_owner);
//Lets modify multiplier
g_fMultiplier[iOwner] = floatround(g_fMultiplier[iOwner]) >= 0x10 ? g_fMultiplier[iOwner] : g_fMultiplier[iOwner] + 0.01;
//Float into integer
new iAmt = floatround(g_fMultiplier[iOwner]);
//While iAmt >= 1
while(iAmt){
//Decrease the iAmt
iAmt--;
//Add '|' char into message (Yes, power bar)
add(g_sMessage[iOwner], 0xF, "|");
}
//Show power bar
set_hudmessage(0xFF, strlen(g_sMessage[iOwner]) == 0xF ? 0x20 : 0xFF, strlen(g_sMessage[iOwner]) == 0xF ? 0 : 0xFF, 0.52, 0.45, 0, 0.1, 0.1, 0.2, 0.2, -1);
show_hudmessage(iOwner, "POWER: [%s]", g_sMessage[iOwner]);
//Write ScreenShake message depending on user's multiplier
message_begin(MSG_ONE, g_mScreenShake, {0,0,0}, iOwner);
write_short(floatround(4096.0 * g_fMultiplier[iOwner]));
write_short(floatround(4096.0));
write_short(floatround(4096.0 * g_fMultiplier[iOwner]));
message_end();
}
public fwTouch(iToucher, iTouched){
//Get grenade type by pdata offset (LINUX)
new iGrenadeType = (get_pdata_int(iToucher, 114) & 3);
//String
new sClass[0x40];
//Add entity's classname into array
pev(iToucher, pev_classname, sClass, sizeof sClass - 1);
if(equal(sClass, "grenade") && iGrenadeType == FLASHBANG){
//Get the grenade's owner
new iOwner = pev(iToucher, pev_owner);
//Remove friendly fire effect
if(get_user_team(iOwner) != get_user_team(iTouched)){
if(IsPlayer(iTouched) && !g_bIsTouched[iTouched][iToucher]){
//Recoil effect
set_pev(iTouched, pev_punchangle, {0.55, 1.0, 0.0});
//Write some screenshake for victim
message_begin(MSG_ONE, g_mScreenShake, {0,0,0}, iTouched);//engfunc(EngFunc_MessageBegin, MSG_ONE, g_mScreenShake, {0,0,0}, iTouched);
write_short(0xC33C);
write_short(0x7A8);
write_short(0xC33C);
message_end();
//Ezcute damage to victim
Diablix_ExecuteDamage(iOwner, iTouched, g_fValue);
//Victim has been touched by grenade's id
g_bIsTouched[iTouched][iToucher] = true;
//Remove task if it exists
if((task_exists(iTouched + g_iTaskId))) remove_task(iTouched + g_iTaskId);
//Remove all the entities user's touching
set_task(1.0, "taskTouched", iTouched + g_iTaskId);
}
}
}
}
public fwSetModel(iEntity, sModel[]){
//Lets replace world model
if(equal(sModel,"models/w_flashbang.mdl")){
//Model changed succesfully
engfunc(EngFunc_SetModel, iEntity, g_sDownloadableContent[WORLD]);
//Return supercede and stop the function
return FMRES_SUPERCEDE;
}
return FMRES_IGNORED;
}
public msgScreenFade(iMessageID, iMessageDestinity, iEntity){
//Make sure screenfade was made by flashbang
if(get_msg_arg_int(4) == 0xFF && get_msg_arg_int(5) == 0xFF && get_msg_arg_int(6) == 0xFF && get_msg_arg_int(7) > 0xC7){
//if flashbang_fade < 1 block message
if(!(get_pcvar_num(g_pCvarFade)))
return 1;
}
return 0;
}
public msgSendAudio(iMessageID, iMessageDestinity, iEntity){
if((get_msg_argtype(2) == ARG_STRING)){
//String
new sArg[0x40];
//Add audio's type into array
get_msg_arg_string(2, sArg, sizeof sArg - 1);
//Block the fire in the hole message
if(equal(sArg ,"%!MRAD_FIREINHOLE"))
return 1; //Succes
}
return 0; // Continue
}
public taskTouched(iTouched){
//Change the temp id into normal id
new id = (iTouched - g_iTaskId);
//static:)
static i;
//Loop, reset variable
for(i = 0 ; i < 0x200 ; i ++){
//If boolean is set to false, continue
if(!g_bIsTouched[id][i]) continue;
// Flase = !False (true)
g_bIsTouched[id][i] = !g_bIsTouched[id][i];
}
}
//fakedamage + some addons by me to write new deathmsg and remove suicide icon
stock Diablix_ExecuteDamage(iAttacker, iVictim, Float:fDmg){
//Float, String, String, Integer
new Float:fHealth, sClassname[0x40], sValue[0x20], iEntity;
//Classname into Array
add(sClassname, sizeof sClassname - 1, "trigger_hurt");
//Health (Float) into variable
pev(iVictim, pev_health, fHealth);
//Block the deathmsg
set_msg_block(g_mDeath, BLOCK_ONCE);
//Create the new entity
iEntity = engfunc( EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, sClassname) );
//Instead of pev_valid()
assert iEntity;
//Set the damage amount
float_to_str(fDmg * 2, sValue, sizeof sValue - 1);
fm_set_kvd(iEntity, "dmg", sValue, sClassname);
//Set the damagetype
num_to_str(DMG_ALWAYSGIB, sValue, sizeof sValue - 1);
fm_set_kvd(iEntity, "damagetype", sValue, sClassname);
//Set the origin (fake origin ofc)
fm_set_kvd(iEntity, "origin", "8192 8192 8192", sClassname);
//Spawn the entity
dllfunc(DLLFunc_Spawn, iEntity);
//Set local classname
set_pev(iEntity, pev_classname, "flashbang");
//Make "fake touch"
dllfunc(DLLFunc_Touch, iEntity, iVictim);
//If succesfully, remove "fake" entity
engfunc(EngFunc_RemoveEntity, iEntity);
//Unlock the deathmsg
set_msg_block(g_mDeath, BLOCK_NOT);
//And create the new one if it has to
if(floatround((fHealth - fDmg)) < 1){
make_deathmsg(iAttacker, iVictim, 0, "");
//Also add frag
new Float:fFrags;
pev(iAttacker, pev_frags, fFrags);
set_pev(iAttacker, pev_frags, ( fFrags + 1.0) );
}
}
//set_kvd by fakemeta way
stock fm_set_kvd(entity, const key[], const value[], const classname[] = "") {
if (classname[0])
set_kvd(0, KV_ClassName, classname);
else {
new class[0x20];
pev(entity, pev_classname, class, sizeof class - 1);
set_kvd(0, KV_ClassName, class);
}
set_kvd(0, KV_KeyName, key);
set_kvd(0, KV_Value, value);
set_kvd(0, KV_fHandled, 0);
return dllfunc(DLLFunc_KeyValue, entity, 0);
}