XShrubCommands.pm


package XSTAB::RTCW::XShrubCommands;
# RTCW shrub command module
#
# $Id: XShrubCommands.pm,v 1.30 2003/03/27 04:50:22 dranok Exp $
#
# This module is released under the GPL
# Author: DranoK
# Email: dranok@users.sourceforge.net
# Documentation: http://xstab.sourceforge.net
################################################

require XSTAB::RTCW::XCoreCommands;
use IO::File;
use XSTAB::XData;
use strict;

our @ISA = qw(XSTAB::RTCW::XCoreCommands);

my $VERSION = 0.9;

# Command list hash
# NOTE: VICTIM IS **ALWAYS** ARGUMENT 1!!!
my %Commands;
%Commands = ( 	"kick" => { "admin_flag" => 'k',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'clientkick',
			"protected" => 1,
			"help" => "kick <name|pbid> -- Kicks target player",
			"enabled" => 1},
		"grant" => { "admin_flag" => 'z',
			"function" => \&_grant_say,
			"num_args" => 2,
			"help" => "grant <name|pbid> <flag> -- Grants temporary admin access",
			"enabled" => 1},
		"delete" => { "admin_flag" => 'd',
			"function" => \&_delete_say,
			"num_args" => 1,
			"help" => "delete <name|pbid> -- Deletes target's record",
			"enabled" => 1},
		"ban" => { "admin_flag" => 'b',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'pb',
			"translate" => 'pb_sv_kick',
			"options" => '60',
			"protected" => 1,
			"help" => "ban <name|pbid> -- Bans target player for 60 minutes",
			"enabled" => 1},
		"permaban" => { "admin_flag" => 'p',
			"function" => \&_standard_say,
			"num_args" => 1,
 			"id" => 'pb',
			"translate" => 'pb_kick',
			"protected" => 1,
			"help" => "permaban <name|pbid> -- Bans player...Forever",
			"enabled" => 1},		
		"nextmap" => { "admin_flag" => 'n',
			"function" => \&_standard_say,
			"num_Args" => 0,
			"id" => 'world',
			"translate" => 'vstr',
			"options" => 'nextmap',
			"help" => "nextmap -- Warps to next map",
			"enabled" => 1},
		"skipwarmup" => { "admin_flag" => 'n',
			"function" => \&_standard_say,
			"num_args" => 0,
			"id" => 'world',	
			"translate" => 'g_warmup',
			"options" => '5',
			"help" => "skipwarmup -- Sets warmup to 5 seconds",
			"enabled" => 1},
		"endlesswarmup" => { "admin_flag" => 'n',
			"function" => \&_standard_say,
			"num_args" => 0,
			"id" => 'world',
			"translate" => 'g_warmup',
			"options" => '1000',
			"help" => "endlesswarmup -- Sets warmup to 1000 seconds",
			"enabled" => 1},
		"reset" => { "admin_flag" => 'r',
			"function" => \&_standard_say,
			"num_args" => 0,
			"id" => 'world',
			"translate" => 'reset_match',
			"help" => "reset -- Resets match",
			"enabled" => 1},
		"cv" => { "admin_flag" => 'c',
			"function" => \&_standard_say,
			"num_args" => 0,
			"id" => 'world',
			"translate" => 'cancelvote',
			"help" => "cv -- Cancles current vote",
			"enabled" => 1},
		"axis" => { "admin_flag" => 't',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'putteam axis',
			"help" => "axis <name|pbid> -- Places player on axis team",
			"enabled" => 1},
		"allies" => { "admin_flag" => 't',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'putteam allies',
			"help" => "allies <name|pbid> -- Places player on allied team",
			"enabled" => 1},
		"spec" => { "admin_flag" => 't',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'putteam spectator',
			"help" => "spec <name|pbid> -- Makes player a spectator",
			"enabled" => 1},
		"kill" => { "admin_flag" => 'i',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'killclient',
			"protected" => 1,
			"help" => "kill <name|pbid> -- Kills target player",
			"enabled" => 1},
		"slap" => { "admin_flag" => 's',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'slap',
			"protected" => 1,
			"help" => "slap <name|pbid> -- Slaps target player",
			"enabled" => 1},
		"ignore" => { "admin_flag" => 'g',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'ignore',
			"protected" => 1,
			"help" => "ignore <name|pbid> -- Ignores target player",
			"enabled" => 1},
		"unignore" => { "admin_flag" => 'g',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'unignore',
			"help" => "unignore <name|pbid> -- Unignores target player",
			"enabled" => 1},
		"respawn" => { "admin_flag" => 'i',
			"function" => \&_standard_say,
			"num_args" => 1,
			"id" => 'client',
			"translate" => 'respawn',
			"help" => "respawn <name|pbid> -- Respawns target player",
			"enabled" => 1},
		"shuffle" => { "admin_flag" => 'f',
			"function" => \&_standard_say,
			"num_args" => 0,
			"id" => 'world',
			"translate" => 'shuffle',
			"help" => "shuffle -- Shuffles teams",
			"enabled" => 1},
		"whoami" => { "admin_flag" => 'w',
			"function" => \&_whois_say,
			"num_args" => 0,
			"help" => "whoami -- Returns stats about yourself",
			"enabled" => 1},
		"whois" => { "admin_flag" => 'w',
			"function" => \&_whois_say,
			"num_args" => 1,
			"help" => "whois <name|pbid> -- Shows stats about target",
			"enabled" => 1},
		"help" => { "admin_flag" => 'w',
			"function" => \&_help_say,
			"num_args" => 0,
			"help" => "help -- Displays this help message",
			"enabled" => 1}
		);

# NAME: create
# FUNCTION: constructor
# ARGUMENTS: None explicit; class implicit
# RETURNS: The blessed object
# NOTES: Simple constructor
sub create
{
  my $class = shift;

  my $self = { };
  $self->{chatcmd} = 'chat';
  $self->{admins} = { };
  
  # Need to load admin stuff
  my $tmpbuf;
  my $fileh = IO::File->new($Global{Admin_list}) or die "Cannot open $Global{Admin_list}: $!\n";
  $fileh->sysread($tmpbuf, 65507);
  $fileh->close();
  
  my @tmpar = split('\n', $tmpbuf);
  foreach my $elem (@tmpar) {
    #                 GUID       : flags
    if ($elem =~ /^([a-zA-Z0-9]+):([a-zA-Z0-9]+)/) {
      $self->{admins}{lc($1)} = $2;
      do_log("Adding admin: $elem", 2);
    }
  } 

  bless($self, $class);
  $self->do_say("XStab starting.");
  return $self;
}

# NAME: do_log
# FUNCTION: Overloads default do_log
# ARGUMENTS: string text, int priority
# RETURNS: Nothing
# NOTES: See documentation for notes concerning
#   the need to overload do_log
sub do_log
{
  my $string = shift;
  my $prio = shift;
  XSTAB::XData::do_log("RTCW::XCoreCommands: $string", $prio);
}

sub do_single_say
{
  my $self = shift;
  my $client = shift;
  my $prefix = shift;
  my $postfix = shift;
  my $prio = shift;
  
  if (!$prio) {
    $prio = 1;
  }

  my $tstring = "";
  my $useprefix = 1;
  foreach my $elem (@_) {
    $tstring .= "[XStab] $elem :NEWLINE:";
    if (length($tstring) > 700) {
      $tstring =~ s/:NEWLINE:$//;
      $prio--;
      if ($useprefix) {
        $tstring = $prefix . $tstring;
        $prio++;
        $useprefix = 0;
      }
      push(@Voice_queue, "$prio$Global{sp}chatclient $client $tstring");
      $tstring = "";
    }
  }
  $prio--;
  $tstring =~ s/:NEWLINE:$//;
  $tstring .= $postfix;
  if ($useprefix) {
    $tstring = $prefix . $tstring;
  }
  push(@Voice_queue, "$prio$Global{sp}chatclient $client $tstring");
}

sub parse_command
{
  my $self = shift;
  my $client = shift;
  my $cmdstring = shift;

  $cmdstring = lc($cmdstring);
  my @tokens = split(' ', $cmdstring);
  my $numargs = scalar(@tokens);
  $numargs--;

  if ($Commands{$tokens[0]}{enabled}) {
    if ($self->check_flags($Players{$client}{admin_flags}, $Commands{$tokens[0]}{admin_flag})) {
      if ($Players{$client}{r_commands} > 10) {
        $self->do_cmd("clientkick $client", 100);
        $self->do_say("$Players{$client}{rawname} was kicked for spamming commands.");
      } else {
        $Players{$client}{r_commands}++;
        my $victim = ""; # Undefined can't pass
        if ($Commands{$tokens[0]}{num_args}) {
          $victim = $self->find_player($tokens[1]);
          if ($victim < 0) {
            $self->do_single_say($client, '', '', 50, "$Players{$client}{rawname}: Cannot find $tokens[1]");
            do_log("$Players{$client}{name} tried to issue $tokens[0] against $tokens[1], but $tokens[1] does not exist", 3);
            return;
          }
        }
        if (($numargs == $Commands{$tokens[0]}{num_args}) || !$Commands{$tokens[0]}{num_args}) {
          my $time = time;
          push(@Admin_queue, "$time$Global{sp}$Players{$client}{guid}$Global{sp}$Players{$victim}{guid}$Global{sp}$tokens[0]");
          &{$Commands{$tokens[0]}{function}}($self, $client, $victim, @tokens);
        } else {
          $self->do_single_say($client, '', '', 50, "Incorrect number of arguments supplied for $tokens[0]");
          do_log("$Players{$client}{name} supplied incorrect number of arguments for $tokens[0]", 3);
        }
      }
    } else {
      $self->do_single_say($client, '', '', 50, "You do not have permission to use $tokens[0]");
      do_log("$Players{$client}{name} does NOT have permission to call $tokens[0]", 3);
    }
  } else {
    $self->do_single_say($client, '', '', 50, "$tokens[0] is not a command");
    do_log("$Players{$client}{name} tried to run $tokens[0], but it is not enabled", 4);
  }
}

# NOTES: Standard say can only have one argument, the victim
sub _standard_say
{
  my $self = shift;
  my $admin = shift;
  my $victim = shift;
  my $command = shift;
  my $string = shift;
 
  my $tcmd = $Commands{$command}{translate};
  my $opts = $Commands{$command}{options};

  my $id = "";
  if ($Commands{$command}{id} eq 'client') {
    $id = $victim;
  } elsif ($Commands{$command}{id} eq 'pb') {
    $id = $Players{$victim}{pbid};
  }

  if ($Commands{$command}{protected}) {
    if ($self->check_flags($Players{$victim}{admin_flags}, 'P') && !$self->check_flags($Players{$admin}{admin_flags}, 'z')) {
      $self->do_single_say($admin, '', '', 50, "$Players{$victim}{rawname} is protected.");
      do_log("Cannot perform protected action on protected player $Players{$victim}{name}", 3);
    } else {
      $self->do_cmd("$tcmd $id $opts", 100);
    }
  } else {
    $self->do_cmd("$tcmd $id $opts", 100);
  }
}

sub _grant_say
{
  my $self = shift;
  my $admin = shift;
  my $victim = shift;
  my $command = shift;
  my $string = shift;
  my $flag = shift;
  
  if (!$self->check_flags($Players{$victim}{admin_flags}, $flag)) {
    $Players{$victim}{admin_flags} .= "$flag";
    do_log("$Players{$victim}{name} now has flag $flag", 2);
    $self->do_say("$Players{$victim}{rawname} now has flag $flag");
  } 
}

sub _delete_say
{
  my $self = shift;
  my $admin = shift;
  my $victim = shift;
  my $command = shift;
  my $string = shift;

  do_log("Attempting to delete record $Players{$victim}{name}");
  $main::storage->delete_record($victim);
  $self->do_say("$Players{$victim}{rawname} has been deleted.");
  delete $Players{$victim};
} 

sub _help_say
{
  my $self = shift;
  my $admin = shift;
  my $victim = shift;
  my $command = shift;
  
  my @rawsay = ();
  foreach my $command (keys %Commands) {
    if ($self->check_flags($Players{$admin}{admin_flags}, $Commands{$command}{admin_flag})) {
      push(@rawsay, "^2HELP: $Commands{$command}{help}^7"); 
    }
  }
  my $prefix =  "[XStab] -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-:NEWLINE:";
     $prefix .= "[XStab] -=-=-=-=-=-=- ^2Available XStab Commands^7 =-=-=-=-=-=-=-:NEWLINE:";
     $prefix .= "[XStab] -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-:NEWLINE:";
  my $postfix = ":NEWLINE:[XStab] -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-";
  $self->do_single_say($admin, $prefix, $postfix, 25, @rawsay);
}

sub _whois_say
{
  my $self = shift;
  my $admin = shift;
  my $victim = shift;
  my $command = shift;

  my $id = $admin;
  if (length($victim) >= 1) {
    $id = $victim;
  }
  
  my $avgping = 0;
  if ($Players{$id}{ping_size}) {
    $avgping = $Players{$id}{total_ping} / $Players{$id}{ping_size};
  }

  my @rawsay = ();
  push(@rawsay, "Kills: $Players{$id}{kills} Deaths: $Players{$id}{deaths}");
  push(@rawsay, "Revives: $Players{$id}{revives} Suicides: $Players{$id}{suoicides}");
  push(@rawsay, "TKs: $Players{$id}{tks} TGibs: $Players{$id}{tgibs}");
  push(@rawsay, "Sacrifices: $Players{$id}{sacrifices} Gibs: $Players{$id}{gibs}");
  push(@rawsay, "Rounds: $Players{$id}{rounds} Average Ping: $avgping");
  my $prefix = "[XStab] -=-=-=-=-=-= ^2Whois for $Players{$id}{rawname}^2 -=-=-=-=-:NEWLINE:";
  my $postfix = "[XStab] -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-";
  $self->do_single_say($admin, $prefix, $postfix, 25, @rawsay);
}

1;