/*****************************************************************************
*
*  Module:  plugin_spawndamage
*  
*  Description:  Prevents spawndamaging by detecting teamdamaging in the first
*                few seconds of play and punishing the perpetrator.
*  
*  Revision History:  11-01-01, initial creation by dodger
*                     12-11-01, revised by dodger, allows customized detection
*                               time
*                     12-17-01, revised by dodger, no longer uses timers
*                     03-04-02, revised by dodger, special cases grenades
*
*  DevNotes:  One nice feature would be to snapshot all user origins on 
*             Round_Start, and ignore spawn damage events if the player
*             has moved more than a certain distance from that point.
*
*****************************************************************************/
 
#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
 
#define ACCESS_CONSOLE 131072
#define ACCESS_RESTRICT 32
 
new STRING_VERSION[MAX_DATA_LENGTH] = "1.30";
 
new i_SDTime = 0;
new epoch_SDStart = 0;
 
 
/*****************************************************************************
*
*  Function:  admin_setsdtime
*  
*  Description:  set spawndamage time (not including buy time)
*  
*  Revision History:  12-11-01, initial creation by dodger
*
*****************************************************************************/
public admin_setsdtime( HLCommand, HLData, HLUserName, UserIndex ) {
 
  new data[MAX_DATA_LENGTH];
  new user[MAX_NAME_LENGTH];
  new text[MAX_TEXT_LENGTH];
 
  convert_string( HLData, data, MAX_DATA_LENGTH );
  convert_string( HLUserName, user, MAX_NAME_LENGTH );
 
  new i_time = strtonum( data );
  new i_buytime = getvar( "mp_freezetime" );
 
  if( i_time <= 0 ) {
    i_SDTime = 0;
    snprintf( text, MAX_TEXT_LENGTH, "[SPAWN] spawndamage time set to zero seconds.", i_time, i_buytime );
  } else {
    i_SDTime = i_time + i_buytime;
    snprintf( text, MAX_TEXT_LENGTH, "[SPAWN] spawndamage time set to %d seconds plus %d seconds buy time.", i_time, i_buytime );
  }
 
  messageex( user, text, print_console );
 
  return PLUGIN_HANDLED;
 
}
 
 
/*****************************************************************************
*
*  Function:  td_on
*  
*  Description:  Timer event function that turns spawndamage checking on.
*  
*  Revision History:  11-01-01, initial creation by dodger
*                     12-11-01, revised by dodger, allows customized detection
*                               time
*                     12-17-01, revised by dodger, no longer uses timers
*
*****************************************************************************/
public td_on( HLCommand, HLData, HLUserName, s_action ) {
 
  new data[MAX_DATA_LENGTH];
  convert_string( HLData, data, MAX_DATA_LENGTH );
 
  /* if Worldspawn signals the start of a round, enable detection and set the
     timer to turn it back off again */
  if( strcasecmp( data, "Round_Start" ) == 0 ) {    
    epoch_SDStart = systemtime();
  }
 
  return PLUGIN_CONTINUE;
 
}
 
 
/*****************************************************************************
*
*  Function:  handle_td
*  
*  Description:  Take a single injure event and determine if it is a valid
*                spawn damage event.
*  
*  Revision History:  11-01-01, initial creation by dodger
*                     12-17-01, revised by dodger, no longer uses timers
*                     01-22-02, revised by dodger, reversed the systemtime()
*                               call, which goes backwards for some reason.
*                               added coverage of CT <--> VIP damage.
*                     01-29-02, revised by dodger, no no, systemtime() counts
*                               properly, dodger == teh stupid
*
*****************************************************************************/
 
public handle_td( HLCommand, HLData, HLUserName, UserIndex ) {
 
  if( epoch_SDStart + i_SDTime < systemtime() ) {
    return PLUGIN_CONTINUE;
  }
 
  new data[MAX_DATA_LENGTH];
  convert_string( HLData, data, MAX_DATA_LENGTH );
 
  new attacker[MAX_DATA_LENGTH];
  new victim[MAX_DATA_LENGTH];
  new weapon[MAX_DATA_LENGTH];
  new strhealth[MAX_DATA_LENGTH];
  new strcolon[MAX_DATA_LENGTH];
  new damage[MAX_DATA_LENGTH];
  strsplit( data, " ", attacker, MAX_DATA_LENGTH, victim, MAX_DATA_LENGTH, weapon, MAX_DATA_LENGTH, strhealth, MAX_DATA_LENGTH, strcolon, MAX_DATA_LENGTH, damage, MAX_DATA_LENGTH );
 
  new attacker_id = strtonum( attacker );  
  new attacker_userid;
  new attacker_teamid;
  new attacker_wonid;
  if( !playerinfo( attacker_id, attacker, MAX_NAME_LENGTH, attacker_userid, attacker_wonid, attacker_teamid ) ) {
    return PLUGIN_CONTINUE;
  }
 
  new victim_id = strtonum( victim );
  new victim_userid;
  new victim_teamid;
  new victim_wonid;
  if( !playerinfo( victim_id, victim, MAX_NAME_LENGTH, victim_userid, victim_wonid, victim_teamid ) ) {
    return PLUGIN_CONTINUE;
  }
 
  if( attacker_userid == victim_userid ) {
    return PLUGIN_CONTINUE;
  }
 
  new response_message[MAX_TEXT_LENGTH];
 
  /* handle standard team damaging */
  if( attacker_teamid == victim_teamid ) {
 
    /* we're nice, and don't count grenades that don't do too much
       damage, which happens frequently */
    if( strcmp( weapon, "grenade" ) == 0 ) {
      if( strtonum(damage) < 10 ) {      
        snprintf( response_message, MAX_TEXT_LENGTH, "[SPAWN] %s, careful with the grenades.", attacker );
        typesay( response_message, 10, 255, 255, 255 );
        return PLUGIN_CONTINUE;
      }
    }
 
    snprintf( response_message, MAX_TEXT_LENGTH, "[SPAWN] %s slain for injuring a teammate.", attacker );
    typesay( response_message, 10, 255, 255, 255 );
    plugin_exec( "admin_slay", attacker );
 
    return PLUGIN_CONTINUE;
  }
 
  /* handle the VIP shooting his teammates */
  if( ( attacker_teamid >=2 ) && ( victim_teamid >= 2 ) ) {
    if( attacker_teamid == 3 ) {
      snprintf( response_message, MAX_TEXT_LENGTH, "[SPAWN] %s, the VIP, kicked for injuring a teammate.", attacker );
    } else {
      snprintf( response_message, MAX_TEXT_LENGTH, "[SPAWN] %s kicked for injuring the VIP.", attacker );    
    }
 
    typesay( response_message, 10, 255, 255, 255 );
    message( attacker, response_message );
    plugin_exec( "admin_kick", attacker );
    return PLUGIN_CONTINUE;
 
  }
 
  return PLUGIN_CONTINUE;
 
}
 
 
/*****************************************************************************
*
*  Function:  plugin_init
*  
*  Description:  Register functions with halflife engine and with LogD event
*                handler.
*  
*  Revision History:  11-01-01, initial creation by dodger
*                     12-11-01, revised by dodger, allows customized detection
*                               time
*                     12-13-01, revised by dodger, added default behavior
*
*****************************************************************************/
public plugin_init() {
 
  plugin_registerinfo( "Spawndamage prevention", "Auto detects and punishes spawn teamdamagers.", STRING_VERSION );
  plugin_registercmd( "td_on", "td_on", ACCESS_CONSOLE, "" );
  plugin_registercmd( "handle_td", "handle_td", ACCESS_CONSOLE, "" );
 
  plugin_registercmd( "admin_setsdtime", "admin_setsdtime", ACCESS_RESTRICT, "admin_setsdtime <sec>: enable spawndamage detection for <sec> seconds" );
 
  /* register td_on to receive all type 62 (World Action) messages */
  exec( "logd_reg 62 admin_command td_on" );
 
  /* register handle_td to receive all type 58 (Injure) messages */
  exec( "logd_reg 58 admin_command handle_td" );
 
  /* default spawndamage time is set to five seconds into the round */
  new i_buytime = getvar( "mp_freezetime" );
 
  if( i_buytime < 0 ) {
    i_buytime = 0;
  }
 
  i_SDTime = 5 + i_buytime;
 
  return PLUGIN_CONTINUE;
 
}