countdown/lib/CDBot.pm
2012-02-04 16:18:26 -05:00

159 lines
4.3 KiB
Perl

package CDBot;
use strict;
use warnings;
use base qw(Bot::BasicBot);
use Time::Duration;
use Scalar::Util qw(looks_like_number);
use POE::Component::IRC::Common qw(:ALL);
use POE::Component::IRC::State;
use POE;
use List::Util qw/reduce/;
use Math::Random::MT;
use Random::Quantum;
use Data::Dumper;
print "Seeding the PRNG from Quantum Source\n";
my $cl = new Random::Quantum(user => 'simcop2387', 'password' => 'sindarin');
my $gen = Math::Random::MT->new($cl->int4);
print "Seeded!\n";
my $float = qr/[0-9]*(?:\.?[0-9]+)?(?:[eE][-+]?[0-9]+)?/;
my $startform = DARK_BLUE.",01". BOLD . "[ ". BOLD. RED;
my $endform = DARK_BLUE.BOLD." ]";
sub _frm { $startform.$_[0].$endform };
sub isallowed {
my $self = shift;
my $message = shift;
my ($who, $where) = @{$message}{"who","channel"};
my $state = $self->{IRCOBJ};
return 1 if ($state->is_channel_operator($where, $who) ||
$state->is_channel_admin($where, $who) ||
$state->is_channel_owner($where, $who) ||
$state->is_channel_halfop($where, $who));
return 0;
}
sub said {
my $self = shift;
my $message = shift;
my $body = $message->{body};
return if ($message->{channel} ne "msg" && $message->{channel} ne "#minimafia");
if ($body =~ /^!dice\s*(?:(\d+)d(\d+))?/) {
my ($dice, $sides) = ($1, $2);
$dice ||= 1; $sides ||= 6;
if ($dice >= 31) {
$self->reply($message, _frm "Can't use that many dice!");
return;
}
my @a = map {int($gen->rand($sides)+1)} (1..$dice);
my $sum = reduce {$a + $b} @a;
my $msg;
if ($dice == 1) {$msg = "You rolled a $sum";}
else {$msg = "You rolled ".join(" + ", @a)." = $sum";}
print "DICE ROLL: ", $msg, "\n";
$self->reply($message, _frm $msg);
}
return if (!$self->isallowed($message));
if ($self->{active} && $body =~ /^!endcount(down)?/) {
$self->{active} = 0;
$self->reply($message, _frm "Countdown ended");
} elsif (!$self->{active} && $body =~ /^!countdown(?:bot)?\s*(?:($float)\s*([hms])?)?/i) {
$self->{active} = 1;
my $number = $1;
my $scale = lc($2 || "");
my $end;
my %scales = (h => 60 * 60, m => 60, s => 1, undef => 60, "" => 60);
if (looks_like_number($number)) {
$end = $number * $scales{$scale};
} else {
$end = 15*60; # default to 15 minutes
}
$self->{time} = time+$end;
$self->reply($message, _frm "Will count down for ".duration($end));
}
return;
}
# Called 5 seconds after bot startup, and then called again 'x' seconds
# later, where 'x' is whatever the function returns.
sub tick {
my $self = shift;
if ($self->{active}) {
# How long till the event?
my $secs = $self->{time} - time;
# What will we say?
my $body = _frm (($secs > 0) ? duration($secs, 1)." to go" : "Time's up!");
# Say this thing in all our channels.
$self->say( channel => $_, body => $body ) for (@{$self->{channels}});
# Now, depending on how long is left, wait a different amount of
# time.
if ($secs > 60 * 30) {
return 60 * 10
} elsif ( $secs > 60 ) {
return 60
} elsif ( $secs > 10 ) {
return 10
} elsif ( $secs > 5 ) {
return 5
} elsif ( $secs > 0 ) {
return 1;
} else {
$self->{active} = 0;
return 10; # done.
}
} else {
return 10;
}
}
sub start_state {
my ( $self, $kernel, $session ) = @_[ OBJECT, KERNEL, SESSION ];
$self->{kernel} = $kernel;
$self->{session} = $session;
# Make an alias for our session, to keep it from getting GC'ed.
$kernel->alias_set($self->{ALIASNAME});
$kernel->delay('tick', 30);
$self->{IRCOBJ} = POE::Component::IRC::State->spawn( alias => $self->{IRCNAME} );
$self->{IRCOBJ}->plugin_add('Connector', POE::Component::IRC::Plugin::Connector->new());
$kernel->post( $self->{IRCNAME}, 'register', 'all' );
$kernel->post($self->{IRCNAME}, 'connect',
{
Debug => 0,
Nick => $self->nick,
Server => $self->server,
Port => $self->port,
Password => $self->password,
UseSSL => $self->ssl,
Flood => $self->flood,
$self->charset_encode(
Nick => $self->nick,
Username => $self->username,
Ircname => $self->name,
),
}
);
return;
}