/* 
*   AMXMOD script. 
*   (plugin_gore.sma) 
*   by mike_cao <mike@mikecao.com> 
*   This file is provided as is (no warranties). 
* 
*   This plugin adds gore effects. It is configured 
*   with the cvar "amx_gore" using these flags: 
* 
*   a - Headshot blood 
*   b - Extra blood effects 
*   c - Bleeding on low health 
*   d - Gib explosion (knife, HE, high damage only) 
* 
*/ 
#include <amxmod> 
#include <dodxmod>

#define MAX_PLAYERS 32 

#define GORE_HEADSHOT       (1<<0) // "a" 
#define GORE_BLOOD          (1<<1) // "b" 
#define GORE_BLEEDING       (1<<2) // "c" 
#define GORE_GIB            (1<<3) // "d" 

#define TE_BLOODSPRITE      115 
#define TE_BLOODSTREAM      101 
#define TE_MODEL            106 
#define TE_WORLDDECAL       116 

/************************************************************ 
* MAIN 
************************************************************/ 

new gHealthIndex[MAX_PLAYERS+1] 

new mdl_gib_flesh 
new mdl_gib_head 
new mdl_gib_legbone 
new mdl_gib_lung 
new mdl_gib_meat 
new mdl_gib_spine 

new spr_blood_drop 
new spr_blood_spray 

public damage_info(attacker,victim,damage,wpnindex,hitplace,TA) 
{ 
   new iFlags = get_gore_flags() 
   gHealthIndex[victim] = get_user_health(victim) 
    
   if (iFlags&GORE_BLOOD) { 
      new iOrigin[3] 
      get_user_origin(victim,iOrigin) 
      fx_blood(iOrigin) 
      fx_blood_small(iOrigin,10) 
   } 
   return PLUGIN_CONTINUE 
} 

public death_info(killer,victim,wpnindex,hitplace,TK) 
{ 
   new iFlags = get_gore_flags() 
   new iOrigin[3] 
   new iHeadshot = ( hitplace == HIT_HEAD ) ? 1:0 
    
   if (iFlags&GORE_HEADSHOT && iHeadshot) { 
      get_user_origin(victim,iOrigin) 
      fx_headshot(iOrigin) 
   } 
   else if (iFlags&GORE_GIB && (is_melee(wpnindex) || wpnindex==DODW_HANDGRENADE || wpnindex==DODW_STICKGRENADE || wpnindex==DODW_MILLS_BOMB || (gHealthIndex[victim] - get_user_health(victim)) > 100)) { 
      get_user_origin(victim,iOrigin) 
      // Effects 
      fx_trans(victim,0) 
      fx_gib_explode(iOrigin,5) 
      fx_blood_large(iOrigin,3) 
      fx_blood_small(iOrigin,20) 
      // Hide body 
      iOrigin[2] = iOrigin[2]-20 
      set_user_origin(victim,iOrigin) 
   } 
} 

public event_blood() 
{ 

   new iFlags = get_gore_flags() 
   if (iFlags&GORE_BLEEDING) { 
      new iPlayer, iPlayers[MAX_PLAYERS], iNumPlayers, iOrigin[3] 
      get_players(iPlayers,iNumPlayers,"a") 
      for (new i = 0; i < iNumPlayers; i++) { 
         iPlayer = iPlayers[i] 
         if (get_user_health(iPlayer) < 20) { 
            get_user_origin(iPlayer,iOrigin) 
            fx_bleed(iOrigin) 
            fx_blood_small(iOrigin,5) 
         } 
      } 
   } 
} 

public event_respawn(id) 
{ 
   gHealthIndex[id] = get_user_health(id) 
   return PLUGIN_CONTINUE 
} 

public get_gore_flags() 
{ 
   new sFlags[24] 
   get_cvar_string("amx_gore",sFlags,24) 
   return read_flags(sFlags) 
} 

/************************************************************ 
* FX FUNCTIONS 
************************************************************/ 

static fx_trans(player,amount) 
{ 
   set_user_rendering(player,kRenderFxNone,0,0,0,kRenderTransAlpha,amount) 
   return PLUGIN_CONTINUE 
} 

public fx_blood(origin[3]) 
{ 
      message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
      write_byte(TE_BLOODSPRITE) 
      write_coord(origin[0]+random_num(-20,20)) 
      write_coord(origin[1]+random_num(-20,20)) 
      write_coord(origin[2]+random_num(-20,20)) 
      write_short(spr_blood_spray) 
      write_short(spr_blood_drop) 
      write_byte(248) // color index 
      write_byte(10) // size 
      message_end() 
} 

public fx_bleed(origin[3]) 
{ 
   // Blood spray 
   message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
   write_byte(TE_BLOODSTREAM) 
   write_coord(origin[0]) 
   write_coord(origin[1]) 
   write_coord(origin[2]+10) 
   write_coord(random_num(-100,100)) // x 
   write_coord(random_num(-100,100)) // y 
   write_coord(random_num(-10,10)) // z 
   write_byte(70) // color 
   write_byte(random_num(50,100)) // speed 
   message_end() 
} 

static fx_blood_small(origin[3],num) 
{ 
   // Blood decals 
   static const blood_small[7] = {204,205,206,207,208,209,210} 
    
   // Small splash 
   for (new j = 0; j < num; j++) { 
      message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
      write_byte(TE_WORLDDECAL) 
      write_coord(origin[0]+random_num(-100,100)) 
      write_coord(origin[1]+random_num(-100,100)) 
      write_coord(origin[2]-36) 
      write_byte(blood_small[random_num(0,6)]) // index 
      message_end() 
   } 
} 

static fx_blood_large(origin[3],num) 
{ 
   // Blood decals 
   static const blood_large[2] = {217,218} 

   // Large splash 
   for (new i = 0; i < num; i++) { 
      message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
      write_byte(TE_WORLDDECAL) 
      write_coord(origin[0]+random_num(-50,50)) 
      write_coord(origin[1]+random_num(-50,50)) 
      write_coord(origin[2]-36) 
      write_byte(blood_large[random_num(0,1)]) // index 
      message_end() 
   } 
} 

static fx_gib_explode(origin[3],num) 
{ 
   new flesh[3], x, y, z 
   flesh[0] = mdl_gib_flesh 
   flesh[1] = mdl_gib_meat 
   flesh[2] = mdl_gib_legbone 

   // Gib explosion 
   // Head 
   message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
   write_byte(TE_MODEL) 
   write_coord(origin[0]) 
   write_coord(origin[1]) 
   write_coord(origin[2]) 
   write_coord(random_num(-100,100)) 
   write_coord(random_num(-100,100)) 
   write_coord(random_num(100,200)) 
   write_angle(random_num(0,360)) 
   write_short(mdl_gib_head) 
   write_byte(0) // bounce 
   write_byte(500) // life 
   message_end() 
    
   // Spine 
   message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
   write_byte(TE_MODEL) 
   write_coord(origin[0]) 
   write_coord(origin[1]) 
   write_coord(origin[2]) 
   write_coord(random_num(-100,100)) 
   write_coord(random_num(-100,100)) 
   write_coord(random_num(100,200)) 
   write_angle(random_num(0,360)) 
   write_short(mdl_gib_spine) 
   write_byte(0) // bounce 
   write_byte(500) // life 
   message_end() 
    
   // Lung 
   for(new i = 0; i < random_num(1,2); i++) { 
      message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
      write_byte(TE_MODEL) 
      write_coord(origin[0]) 
      write_coord(origin[1]) 
      write_coord(origin[2]) 
      write_coord(random_num(-100,100)) 
      write_coord(random_num(-100,100)) 
      write_coord(random_num(100,200)) 
      write_angle(random_num(0,360)) 
      write_short(mdl_gib_lung) 
      write_byte(0) // bounce 
      write_byte(500) // life 
      message_end() 
   } 
    
   // Parts, 5 times 
   for(new i = 0; i < 5; i++) { 
      message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
      write_byte(TE_MODEL) 
      write_coord(origin[0]) 
      write_coord(origin[1]) 
      write_coord(origin[2]) 
      write_coord(random_num(-100,100)) 
      write_coord(random_num(-100,100)) 
      write_coord(random_num(100,200)) 
      write_angle(random_num(0,360)) 
      write_short(flesh[random_num(0,2)]) 
      write_byte(0) // bounce 
      write_byte(500) // life 
      message_end() 
   } 
    
   // Blood 
   for(new i = 0; i < num; i++) { 
      x = random_num(-100,100) 
      y = random_num(-100,100) 
      z = random_num(0,100) 
      for(new j = 0; j < 5; j++) { 
         message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
         write_byte(TE_BLOODSPRITE) 
         write_coord(origin[0]+(x*j)) 
         write_coord(origin[1]+(y*j)) 
         write_coord(origin[2]+(z*j)) 
         write_short(spr_blood_spray) 
         write_short(spr_blood_drop) 
         write_byte(248) // color index 
         write_byte(15) // size 
         message_end() 
      } 
   } 
} 

public fx_headshot(origin[3]) 
{ 
   // Blood spray, 5 times 
   for (new i = 0; i < 5; i++) { 
      message_begin(MSG_BROADCAST,SVC_TEMPENTITY) 
      write_byte(101) 

      write_coord(origin[0]) 
      write_coord(origin[1]) 
      write_coord(origin[2]+30) 
      write_coord(random_num(-20,20)) // x 
      write_coord(random_num(-20,20)) // y 
      write_coord(random_num(50,300)) // z 
      write_byte(70) // color 
      write_byte(random_num(100,200)) // speed 
      message_end() 
   } 
} 

/************************************************************ 
* PLUGIN FUNCTIONS 
************************************************************/ 

public plugin_precache() 
{ 
   spr_blood_drop = precache_model("sprites/blood.spr") 
   spr_blood_spray = precache_model("sprites/bloodspray.spr") 

   mdl_gib_flesh = precache_model("models/Fleshgibs.mdl") 
   mdl_gib_head = precache_model("models/GIB_Skull.mdl") 
   mdl_gib_legbone = precache_model("models/GIB_Legbone.mdl") 
   mdl_gib_lung = precache_model("models/GIB_Lung.mdl") 
   mdl_gib_meat = precache_model("models/GIB_B_Gib.mdl") 
   mdl_gib_spine = precache_model("models/GIB_B_Bone.mdl") 
} 

public plugin_init() 
{ 
   register_plugin("Plugin Gore","1.0","mike_cao") 
   register_event("ResetHUD","event_respawn","be","1=1") 
   register_cvar("amx_gore","abcd") 
   set_task(1.0,"event_blood",0,"",0,"b") 

   return PLUGIN_CONTINUE 
}