62 Commits
Author SHA1 Message Date
Auto Bot 7079e203a8 Patched in whois support, for use with voicenonbots.pm 2011-04-23 11:49:50 +04:00
Matthew Barksdale 727062b14b Merge branch 'indev' of github.com:Xelhua/Auto into indev 2011-04-23 01:39:19 -04:00
Matthew Barksdale df31622f82 What is this I don't even.. 2011-04-23 01:39:11 -04:00
Elijah Perrault 76d2c03281 Werewolf 1.07: Various improvements. 2011-04-22 15:50:08 -06:00
Elijah Perrault 303e03f4ee Merge branch 'indev' of github.com:Xelhua/Auto into indev 2011-04-22 02:25:16 -06:00
Elijah Perrault 99bb0721ba Fixing Matt's fails. 2011-04-22 02:25:00 -06:00
Matthew Barksdale 6f9e6f0d5d Apparently these aren't needed 2011-04-21 23:27:30 -04:00
Matthew Barksdale ccab5e9ab9 Fixed a bug with MODE parsing 2011-04-21 23:24:40 -04:00
Elijah Perrault 03c1616364 Maybe I should include the actual changes... 2011-04-21 21:00:32 -06:00
Elijah Perrault 193461abf4 Updated Core::IRC::Users to be more efficient. 2011-04-21 21:00:13 -06:00
Elijah Perrault f1a9b91a30 Oops. 2011-04-21 20:58:48 -06:00
Elijah Perrault f3ad8e0e38 Use M::Werewolf, not ourselves. 2011-04-21 20:57:36 -06:00
Elijah Perrault 81ff64ba4f Slight errors. 2011-04-21 20:43:24 -06:00
Elijah Perrault 33b50a651a Added a WerewolfAdmin module for administering the Werewolf IRC game. 2011-04-21 20:39:55 -06:00
Elijah Perrault fdfc249ba8 Updated. 2011-04-21 20:39:21 -06:00
Elijah Perrault f68646d155 Small bug fix. 2011-04-21 18:51:23 -06:00
Elijah Perrault 6357c54574 Various other state bugs. 2011-04-21 15:48:26 -06:00
Elijah Perrault a8ea3f0e64 Fixed significant state mismatched data bugs. 2011-04-21 14:08:47 -06:00
Elijah Perrault 3fdf7dcaf5 What is this I don't even... 2011-04-21 14:02:34 -06:00
Elijah Perrault 105e83699d Added API::IRC::ison for checking if a user is on a channel. 2011-04-21 02:08:37 -06:00
Elijah Perrault 338551b44c Werewolf: Fixed a bug in harlot staying home. 2011-04-20 22:18:56 -06:00
Elijah Perrault 412261f478 Werewolf: Various bug fixes. 2011-04-20 21:36:11 -06:00
Elijah Perrault 988e93a6f1 Lets try this... 2011-04-20 21:27:46 -06:00
Elijah Perrault 6c4ff75a03 Here as well. 2011-04-20 20:56:21 -06:00
Elijah Perrault 362310b863 Regex is a bad idea for this. 2011-04-20 20:56:02 -06:00
Elijah Perrault a2002882d6 Oops. 2011-04-20 20:48:04 -06:00
Elijah Perrault 3ebe82ec28 Werewolf 1.06: Fixed an annoyance and added traitor transformation. 2011-04-20 20:44:59 -06:00
Elijah Perrault 42faabeef5 Updated. 2011-04-20 20:37:49 -06:00
Elijah Perrault 21fb5d4974 Commands now work with prefixes even in PM. 2011-04-20 20:37:31 -06:00
Elijah Perrault 8147e9e32a We're alpha11. 2011-04-20 20:25:04 -06:00
Elijah Perrault 0864f549d1 Ping: Determines end by numeric 315 instead of a 3-second timer now. 2011-04-20 20:20:58 -06:00
Elijah Perrault ba5de67e4a Werewolf: Fixed a GUARD issue and made it possible to VISIT yourself. 2011-04-19 20:23:37 -06:00
Elijah Perrault 3bd8e9369d Possibly fixed a rare fatal error. 2011-04-19 11:09:19 -06:00
Elijah Perrault e33fd1df8d Werewolf: Rewrote WAIT to be more decent. 2011-04-19 02:04:31 -06:00
Elijah Perrault 3ef78078c4 Werewolf: Wounded villagers are now excluded from winning villager count. 2011-04-18 17:35:36 -06:00
Elijah Perrault a1beabe76a Werewolf: Bold lynched nick. 2011-04-18 16:18:31 -06:00
Elijah Perrault f12b7ef527 Werewolf: Dynamic lynch and no victim messages. 2011-04-18 16:11:19 -06:00
Elijah Perrault ed56d53f1e Werewolf 1.05: Added WAIT command. 2011-04-18 15:35:23 -06:00
Elijah Perrault e590c0dee3 Werewolf: Improved STATS to be smart. 2011-04-18 14:23:58 -06:00
Elijah Perrault 9fca160de5 Drunks = villagers. 2011-04-16 23:40:11 -06:00
Elijah Perrault 28e29f2dba *sigh* 2011-04-16 22:11:32 -06:00
Elijah Perrault c30f300b24 Removed the "villager gunner" role. 2011-04-16 22:05:05 -06:00
Elijah Perrault 0d9a714c4a Oops. 2011-04-16 21:55:03 -06:00
Elijah Perrault 87ff93945f Fixed slight issue. 2011-04-16 21:43:50 -06:00
Elijah Perrault c13a4e2ffe Werewolf 1.04: Added village drunks and fixed other issues. 2011-04-16 21:39:01 -06:00
Elijah Perrault 42fcac5cc0 Err... 2011-04-16 19:38:28 -06:00
Elijah Perrault 01a432f023 Updated. 2011-04-16 19:14:57 -06:00
Elijah Perrault a47211763c Fixed various annoyances in Werewolf. 2011-04-16 19:13:50 -06:00
Elijah Perrault 8cddc69209 Been writing too much Python today. 2011-04-16 02:14:18 -06:00
Elijah Perrault b6eb0c17cc Whoops. 2011-04-16 02:09:49 -06:00
Elijah Perrault 38b3e4c3d8 Werewolf: Fixed a nasty lynch nick exploit. 2011-04-16 02:08:15 -06:00
Elijah Perrault 503a7ed990 Fixed spelling failures. 2011-04-15 22:40:37 -06:00
Elijah Perrault 579485776d Moved bolds a bit. 2011-04-15 22:19:27 -06:00
Elijah Perrault f5db549052 Improvements. 2011-04-15 18:06:15 -06:00
Elijah Perrault 72006a8e7e Fixed an issue in HELP. 2011-04-14 19:26:48 -06:00
Elijah Perrault 2ca0885741 Added a Ping module. 2011-04-14 18:43:48 -06:00
Elijah Perrault 6c6b8604bc Merge branch 'indev' of github.com:Xelhua/Auto into indev 2011-04-14 18:37:27 -06:00
Elijah Perrault da28c54652 Moved Werewolf back to stable. 2011-04-14 18:32:08 -06:00
Matthew Barksdale f0b49acbd0 Added cleaning up inconsistencies in modules to TODO 2011-04-14 03:53:19 -04:00
Matthew Barksdale 58447eb40a Added more French translations 2011-04-14 03:41:40 -04:00
Matthew Barksdale 363a724ed3 Added french help translation 2011-04-14 03:34:27 -04:00
Matthew Barksdale a122977644 Added deoper subroutine to deoper Auto on a server 2011-04-14 03:27:58 -04:00
21 changed files with 909 additions and 202 deletions

No files matched your search

+6 -14
View File
@@ -10,23 +10,15 @@
The future of IRC bots is here! Xelhua gives to you, Auto 3.0, a new version of The future of IRC bots is here! Xelhua gives to you, Auto 3.0, a new version of
the popular Auto IRC bot. the popular Auto IRC bot.
In this alpha10 release, we have added: In this alpha11 release, we have added:
* German translation for AUR command help. * Ping: Speed improvements.
* German translation for Bitly command help. * An advanced IRC version of the popular party game Werewolf (AKA Mafia).
* German translation for Calc command help. * Commands with prefixes now work in PM's too.
* German translation for Dictionary command help.
* German translation for EightBall command help.
* German translation for Eval command help.
* German translation for FML command help.
* German translation for Greet command help.
* Aliases now work in PM's to the bot too.
Bug fixes: Bug fixes:
* Fixed parsing of host masks with a / in them. * Fixed significant state mismatched data bugs.
* Security exploit (causes fatal error) in the HELP command.
* Security exploit (wide characters) in plaintext socket management.
Incompatibilities: Incompatibilities:
@@ -40,4 +32,4 @@ created by anyone and uploaded there for everyone to use.
Auto's goal is to create an efficient, stable and highly customizable IRC bot Auto's goal is to create an efficient, stable and highly customizable IRC bot
in Perl. To offer an alternative to other platforms. in Perl. To offer an alternative to other platforms.
Enjoy Auto 3.0.0 Alpha 10! Enjoy Auto 3.0.0 Alpha 11!
+15 -13
View File
@@ -481,19 +481,21 @@ if (conf_get('aliases:alias')) {
while (1) { while (1) {
# Timer check. # Timer check.
foreach my $tk (keys %TIMERS) { foreach my $tk (keys %TIMERS) {
if ($TIMERS{$tk}{time} <= time) { if (exists $TIMERS{$tk}) {
&{ $TIMERS{$tk}{sub} }(); if ($TIMERS{$tk}{time} <= time) {
if ($TIMERS{$tk}{type} == 1) { &{ $TIMERS{$tk}{sub} }();
# If it's type 1, delete from memory. if ($TIMERS{$tk}{type} == 1) {
delete $TIMERS{$tk}; # If it's type 1, delete from memory.
} delete $TIMERS{$tk};
elsif ($TIMERS{$tk}{type} == 2) { }
# If it's type 2, reset timer. elsif ($TIMERS{$tk}{type} == 2) {
$TIMERS{$tk}{time} = time + $TIMERS{$tk}{secs}; # If it's type 2, reset timer.
} $TIMERS{$tk}{time} = time + $TIMERS{$tk}{secs};
else { }
# This should never happen. else {
delete $TIMERS{$tk}; # This should never happen.
delete $TIMERS{$tk};
}
} }
} }
} }
+23 -1
View File
@@ -3,7 +3,29 @@ Auto IRC Bot 3.0: Change Log
3.0 Indev 3.0 Indev
=============================================================================== ===============================================================================
* Werewolf 1.07: Various improvements.
* Updated Core::IRC::Users to be more efficient.
* Added a WerewolfAdmin module for administering the Werewolf IRC game.
* Fixed significant state mismatched data bugs.
* Added API::IRC::ison for checking if a user is on a channel.
* Werewolf: Fixed a bug in harlot staying home.
* Werewolf: Various bug fixes.
* Werewolf 1.06: Fixed an annoyance and added traitor transformation.
* Commands now work with prefixes even in PM.
* Ping: Determines end by numeric 315 instead of a 3-second timer now.
* Werewolf: Fixed a GUARD issue and made it possible to VISIT yourself.
* Possibly fixed a rare fatal error.
* Werewolf: Rewrote WAIT to be more decent.
* Werewolf: Wounded villagers are now excluded from winning villager count.
* Werewolf: Dynamic lynch and no victim messages.
* Werewolf 1.05: Added WAIT command.
* Werewolf: Improved STATS to be smart.
* Werewolf 1.04: Added village drunks and fixed other issues.
* Werewolf: Fixed various annoyances. Also raised chance of gun hitting.
* Werewolf: Fixed a nasty lynch nick exploit.
* Fixed an issue in HELP.
* Added a Ping module.
* Moved Werewolf back to stable.
3.0 Alpha 10 3.0 Alpha 10
=============================================================================== ===============================================================================
+1
View File
@@ -10,6 +10,7 @@ Legend:
[ ] Cleanup [ ] Cleanup
[ ] Replace println with Perl 5.10's say. [ ] Replace println with Perl 5.10's say.
[ ] Fix inconsistencies in official modules
[X] Language [X] Language
[X] Create method of translation. [X] Create method of translation.
+22 -1
View File
@@ -9,7 +9,7 @@ use Exporter;
use base qw(Exporter); use base qw(Exporter);
our @EXPORT_OK = qw(ban cjoin cpart cmode umode kick privmsg notice quit nick names our @EXPORT_OK = qw(ban cjoin cpart cmode umode kick privmsg notice quit nick names
topic who usrc match_mask); topic who whois usrc match_mask ison);
# Create the on_disconnect event. # Create the on_disconnect event.
API::Std::event_add('on_disconnect'); API::Std::event_add('on_disconnect');
@@ -130,6 +130,18 @@ sub act {
return 1; return 1;
} }
# Check if a given nickname is on a channel.
sub ison {
my ($svr, $chan, $nick) = @_;
$chan = lc $chan;
if (!exists $State::IRC::chanusers{$svr}) { return }
if (!exists $State::IRC::chanusers{$svr}{$chan}) { return }
if (!exists $State::IRC::chanusers{$svr}{$chan}{lc $nick}) { return }
return 1;
}
# Change bot nickname. # Change bot nickname.
sub nick { sub nick {
my ($svr, $newnick) = @_; my ($svr, $newnick) = @_;
@@ -194,6 +206,15 @@ sub who {
return 1; return 1;
} }
# Send a WHOIS.
sub whois {
my ($svr, $nick) = @_;
Auto::socksnd($svr, "WHOIS $nick");
return 1;
}
# Get nick, ident and host from a <nick>!<ident>@<host> # Get nick, ident and host from a <nick>!<ident>@<host>
sub usrc { sub usrc {
my ($ex) = @_; my ($ex) = @_;
+1 -1
View File
@@ -26,7 +26,7 @@ sub mod_init {
if (keys %Auto::SOCKET) { API::Log::slog('MODULES: Attempting to load '.$name.' (version '.$version.') by '.$author.'...') } if (keys %Auto::SOCKET) { API::Log::slog('MODULES: Attempting to load '.$name.' (version '.$version.') by '.$author.'...') }
# Check if this module is compatible with this version of Auto. # Check if this module is compatible with this version of Auto.
if ($autover !~ m/^3\.0\.0a(7|8|9|10)$/xsm) { if ($autover !~ m/^3\.0\.0a(7|8|9|10|11)$/xsm) {
API::Log::dbug('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.'); API::Log::dbug('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.');
API::Log::alog('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.'); API::Log::alog('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.');
if (keys %Auto::SOCKET) { API::Log::slog('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.') } if (keys %Auto::SOCKET) { API::Log::slog('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.') }
+30 -25
View File
@@ -265,41 +265,46 @@ sub cmd_help
# Help for a specific command was requested. Lets get it. # Help for a specific command was requested. Lets get it.
my $rcm = uc($argv[0]); my $rcm = uc($argv[0]);
if (exists $API::Std::CMDS{$rcm}{help}) { # If there is help for this command.
# If there is help for this command. if (exists $API::Std::CMDS{$rcm}) {
if (exists $API::Std::CMDS{$rcm}{help}) {
# Check for necessary privileges. # Check for necessary privileges.
if ($API::Std::CMDS{$rcm}{priv}) { if ($API::Std::CMDS{$rcm}{priv}) {
if (!has_priv(match_user(%$src), $API::Std::CMDS{$rcm}{priv})) { if (!has_priv(match_user(%$src), $API::Std::CMDS{$rcm}{priv})) {
notice($src->{svr}, $src->{nick}, trans("Access denied")."."); notice($src->{svr}, $src->{nick}, trans("Access denied").".");
return; return;
}
} }
}
if ($API::Std::CMDS{$rcm}{help}) { if ($API::Std::CMDS{$rcm}{help}) {
# If there is valid help for this command. # If there is valid help for this command.
# Get the language. # Get the language.
my ($lang, undef) = split('_', $Auto::LOCALE); my ($lang, undef) = split('_', $Auto::LOCALE);
if (exists ${ $API::Std::CMDS{$rcm}{help} }{$lang}) { if (exists ${ $API::Std::CMDS{$rcm}{help} }{$lang}) {
# If help for this command is available in the configured language. # If help for this command is available in the configured language.
notice($src->{svr}, $src->{nick}, "Help for \002".$rcm."\002: ".${ $API::Std::CMDS{$rcm}{help} }{$lang}); notice($src->{svr}, $src->{nick}, "Help for \002".$rcm."\002: ".${ $API::Std::CMDS{$rcm}{help} }{$lang});
}
else {
# If it isn't, default to English.
if (exists ${ $API::Std::CMDS{$rcm}{help} }{en}) {
# If help for this command is available in English.
notice($src->{svr}, $src->{nick}, "Help for \002".$rcm."\002: ".${ $API::Std::CMDS{$rcm}{help} }{en});
} }
else { else {
# If it isn't, no help. # If it isn't, default to English.
notice($src->{svr}, $src->{nick}, "No help for \002".$rcm."\002 available."); if (exists ${ $API::Std::CMDS{$rcm}{help} }{en}) {
# If help for this command is available in English.
notice($src->{svr}, $src->{nick}, "Help for \002".$rcm."\002: ".${ $API::Std::CMDS{$rcm}{help} }{en});
}
else {
# If it isn't, no help.
notice($src->{svr}, $src->{nick}, "No help for \002".$rcm."\002 available.");
}
} }
} }
else {
# If it isn't valid, no help.
notice($src->{svr}, $src->{nick}, "No help for \002".$rcm."\002 available.");
}
} }
else { else {
# If it isn't valid, no help. # If there is no help, don't give any.
notice($src->{svr}, $src->{nick}, "No help for \002".$rcm."\002 available."); notice($src->{svr}, $src->{nick}, "No help for \002".$rcm."\002 available.");
} }
} }
+4 -3
View File
@@ -64,6 +64,8 @@ hook_add('on_cprivmsg', 'irc.commands.aliases', sub {
# Command alias parsing for private messages. # Command alias parsing for private messages.
hook_add('on_uprivmsg', 'irc.commands.aliases', sub { hook_add('on_uprivmsg', 'irc.commands.aliases', sub {
my (($src, ($cmd, @args))) = @_; my (($src, ($cmd, @args))) = @_;
my $cprefix = (conf_get('fantasy_pf'))[0][0];
if (substr($cmd, 0, 1) eq $cprefix) { $cmd = substr $cmd, 1 }
# Check for an alias. # Check for an alias.
if (defined $API::Std::ALIASES{uc $cmd}) { if (defined $API::Std::ALIASES{uc $cmd}) {
@@ -95,7 +97,7 @@ hook_add("on_quit", "quit_update_chanusers", sub {
# Delete the user from all channels. # Delete the user from all channels.
foreach my $ccu (keys %{ $State::IRC::chanusers{$src{svr}}}) { foreach my $ccu (keys %{ $State::IRC::chanusers{$src{svr}}}) {
if (defined $State::IRC::chanusers{$src{svr}}{$ccu}{$src{nick}}) { delete $State::IRC::chanusers{$src{svr}}{$ccu}{$src{nick}} } if (defined $State::IRC::chanusers{$src{svr}}{$ccu}{lc $src{nick}}) { delete $State::IRC::chanusers{$src{svr}}{$ccu}{lc $src{nick}} }
} }
return 1; return 1;
@@ -233,8 +235,7 @@ hook_add('on_isupport', 'core.prefixchanmode.getdata', sub {
return 1; return 1;
}); });
sub clear_usercmd_timer sub clear_usercmd_timer {
{
# If ratelimit is set to 1 in config, add this timer. # If ratelimit is set to 1 in config, add this timer.
if ((conf_get('ratelimit'))[0][0] eq 1) { if ((conf_get('ratelimit'))[0][0] eq 1) {
# Clear usercmd hash every X seconds. # Clear usercmd hash every X seconds.
+2 -8
View File
@@ -28,14 +28,8 @@ hook_add('on_rcjoin', 'ircusers.onjoin', sub {
hook_add('on_namesreply', 'ircusers.names', sub { hook_add('on_namesreply', 'ircusers.names', sub {
my ($svr, $chan, undef) = @_; my ($svr, $chan, undef) = @_;
# Iterate through the users for this channel. # WHO the channel.
foreach (keys %{$State::IRC::chanusers{$svr}{$chan}}) { API::IRC::who($svr, $chan);
# Check if the user already exists.
if (!$users{$svr}{$_}) {
# They do not; WHO them.
API::IRC::who($svr, $_);
}
}
return 1; return 1;
}); });
+17 -15
View File
@@ -359,7 +359,7 @@ sub cjoin {
} }
else { else {
# It isn't. Update chanusers and trigger on_rcjoin. # It isn't. Update chanusers and trigger on_rcjoin.
$State::IRC::chanusers{$svr}{lc $chan}{$src{nick}} = 1; $State::IRC::chanusers{$svr}{lc $chan}{lc $src{nick}} = 1;
$src{svr} = $svr; $src{svr} = $svr;
API::Std::event_run("on_rcjoin", (\%src, $chan)); API::Std::event_run("on_rcjoin", (\%src, $chan));
} }
@@ -374,9 +374,6 @@ sub kick {
my %src = API::IRC::usrc(substr($ex[0], 1)); my %src = API::IRC::usrc(substr($ex[0], 1));
$src{svr} = $svr; $src{svr} = $svr;
# Update chanusers.
delete $State::IRC::chanusers{$svr}{$ex[2]}{$ex[3]} if defined $State::IRC::chanusers{$svr}{$ex[2]}{$ex[3]};
# Set $msg to the kick message. # Set $msg to the kick message.
my $msg = 0; my $msg = 0;
if (defined $ex[4]) { if (defined $ex[4]) {
@@ -393,7 +390,7 @@ sub kick {
# We were kicked! # We were kicked!
# Delete channel from botchans. # Delete channel from botchans.
delete $botchans{$svr}{$ex[2]}; delete $botchans{$svr}{lc $ex[2]};
# Log this horrible act. # Log this horrible act.
API::Log::alog("I was kicked from ".$svr."/".$ex[2]." by ".$src{nick}."! Reason: ".$msg); API::Log::alog("I was kicked from ".$svr."/".$ex[2]." by ".$src{nick}."! Reason: ".$msg);
@@ -410,7 +407,7 @@ sub kick {
} }
else { else {
# We weren't. Update chanusers and trigger on_kick. # We weren't. Update chanusers and trigger on_kick.
if (defined $State::IRC::chanusers{$svr}{$ex[2]}{$ex[3]}) { delete $State::IRC::chanusers{$svr}{$ex[2]}{$ex[3]} } if (defined $State::IRC::chanusers{$svr}{lc $ex[2]}{lc $ex[3]}) { delete $State::IRC::chanusers{$svr}{lc $ex[2]}{lc $ex[3]} }
API::Std::event_run("on_kick", (\%src, $ex[2], $ex[3], $msg)); API::Std::event_run("on_kick", (\%src, $ex[2], $ex[3], $msg));
} }
@@ -423,7 +420,7 @@ sub mode {
if ($ex[2] ne $State::IRC::botinfo{$svr}{nick}) { if ($ex[2] ne $State::IRC::botinfo{$svr}{nick}) {
# Set data we'll need later. # Set data we'll need later.
my $chan = $ex[2]; my $chan = lc $ex[2];
$ex[3] =~ s/^://xsm; $ex[3] =~ s/^://xsm;
my $modes = $ex[3]; my $modes = $ex[3];
my $fmodes = join ' ', @ex[3..$#ex]; my $fmodes = join ' ', @ex[3..$#ex];
@@ -467,10 +464,11 @@ sub mode {
if ($nnt) { if ($nnt) {
# It is a status mode, lets parse changes. # It is a status mode, lets parse changes.
my $user = shift(@ex); my $user = lc shift @ex;
if (defined $State::IRC::chanusers{$svr}{$chan}{$user}) { if (defined $State::IRC::chanusers{$svr}{$chan}{$user}) {
if ($op == 1) { if ($op == 1) {
return if $State::IRC::chanusers{$svr}{$chan}{$user} =~ m/$maf/xsm;
if ($State::IRC::chanusers{$svr}{$chan}{$user} eq 1) { if ($State::IRC::chanusers{$svr}{$chan}{$user} eq 1) {
$State::IRC::chanusers{$svr}{$chan}{$user} = $maf; $State::IRC::chanusers{$svr}{$chan}{$user} = $maf;
} }
@@ -531,9 +529,9 @@ sub nick {
else { else {
# It isn't. Update chanusers and trigger on_nick. # It isn't. Update chanusers and trigger on_nick.
foreach my $chk (keys %{ $State::IRC::chanusers{$svr} }) { foreach my $chk (keys %{ $State::IRC::chanusers{$svr} }) {
if (defined $State::IRC::chanusers{$svr}{$chk}{$src{nick}}) { if (defined $State::IRC::chanusers{$svr}{$chk}{lc $src{nick}}) {
$State::IRC::chanusers{$svr}{$chk}{$nex} = $State::IRC::chanusers{$svr}{$chk}{$src{nick}}; $State::IRC::chanusers{$svr}{$chk}{lc $nex} = $State::IRC::chanusers{$svr}{$chk}{lc $src{nick}};
delete $State::IRC::chanusers{$svr}{$chk}{$src{nick}}; delete $State::IRC::chanusers{$svr}{$chk}{lc $src{nick}};
} }
} }
API::Std::event_run("on_nick", (\%src, $nex)); API::Std::event_run("on_nick", (\%src, $nex));
@@ -572,13 +570,13 @@ sub part {
# Check if it's from us or someone else. # Check if it's from us or someone else.
if ($src{nick} eq $State::IRC::botinfo{$svr}{nick}) { if ($src{nick} eq $State::IRC::botinfo{$svr}{nick}) {
# Delete this channel from botchans. # Delete this channel from botchans.
if ($botchans{$svr}{$ex[2]}) { delete $botchans{$svr}{$ex[2]} } if ($botchans{$svr}{lc $ex[2]}) { delete $botchans{$svr}{lc $ex[2]} }
# Trigger on_upart. # Trigger on_upart.
API::Std::event_run('on_upart', ($svr, $ex[2])); API::Std::event_run('on_upart', ($svr, $ex[2]));
} }
else { else {
# Delete them from chanusers. # Delete them from chanusers.
delete $State::IRC::chanusers{$svr}{$ex[2]}{$src{nick}} if defined $State::IRC::chanusers{$svr}{$ex[2]}{$src{nick}}; delete $State::IRC::chanusers{$svr}{lc $ex[2]}{lc $src{nick}} if defined $State::IRC::chanusers{$svr}{lc $ex[2]}{lc $src{nick}};
# Set $msg to the part message. # Set $msg to the part message.
my $msg = 0; my $msg = 0;
@@ -624,9 +622,13 @@ sub privmsg {
if (lc($ex[2]) eq lc($State::IRC::botinfo{$svr}{nick})) { if (lc($ex[2]) eq lc($State::IRC::botinfo{$svr}{nick})) {
# It is coming to us in a private message. # It is coming to us in a private message.
# Check for a prefix.
$cprefix = (conf_get('fantasy_pf'))[0][0];
# Ensure it's a valid length. # Ensure it's a valid length.
if (length($ex[3]) > 1) { if (length($ex[3]) > 2) {
$cmd = uc(substr($ex[3], 1)); $cmd = uc substr $ex[3], 1;
if (substr($cmd, 0, 1) eq $cprefix) { $cmd = substr $cmd, 1 }
if (defined $API::Std::CMDS{$cmd}) { if (defined $API::Std::CMDS{$cmd}) {
# If this is indeed a command, continue. # If this is indeed a command, continue.
if ($API::Std::CMDS{$cmd}{lvl} == 1 or $API::Std::CMDS{$cmd}{lvl} == 2) { if ($API::Std::CMDS{$cmd}{lvl} == 1 or $API::Std::CMDS{$cmd}{lvl} == 2) {
+1
View File
@@ -10,6 +10,7 @@ our (%chanusers, %botinfo);
# Create on_namesreply hook. # Create on_namesreply hook.
hook_add('on_namesreply', 'state.irc.names', sub { hook_add('on_namesreply', 'state.irc.names', sub {
my ($svr, $chan, @data) = @_; my ($svr, $chan, @data) = @_;
$chan = lc $chan;
# Delete the old chanusers hash if it exists. # Delete the old chanusers hash if it exists.
if (defined $chanusers{$svr}{$chan}) { delete $chanusers{$svr}{$chan} } if (defined $chanusers{$svr}{$chan}) { delete $chanusers{$svr}{$chan} }
+1
View File
@@ -30,6 +30,7 @@ sub _void {
our %HELP_AUR = ( our %HELP_AUR = (
en => "This command allows you to lookup a module in the Arch Linux AUR. \2Syntax:\2 AUR <module>", en => "This command allows you to lookup a module in the Arch Linux AUR. \2Syntax:\2 AUR <module>",
de => "Dieser Befehl ermoeglicht du auf nachschlagst ein Modul in der Arch Linux AUR. \2Syntax:\2 AUR <module>", de => "Dieser Befehl ermoeglicht du auf nachschlagst ein Modul in der Arch Linux AUR. \2Syntax:\2 AUR <module>",
fr => "Cette commande vous permet de rechercher un module dans le Arch Linux AUR. \2Syntaxe:\2 AUR <module>",
); );
# Callback for AUR command. # Callback for AUR command.
+2 -2
View File
@@ -13,8 +13,8 @@ use URI::Escape;
sub _init sub _init
{ {
# Check for required configuration values. # Check for required configuration values.
if (!(conf_get('bitly:user'))[0][0] or !(conf_get('bitly:key'))[0][0]) { if (!conf_get('bitly:user') or !conf_get('bitly:key')) {
err(2, 'Please verify that you have bitly_user and bitly_key defined in your configuration file.', 0); err(2, 'Bitly: Please verify that you have bitly_user and bitly_key defined in your configuration file.', 0);
return; return;
} }
# Create the SHORTEN and REVERSE commands. # Create the SHORTEN and REVERSE commands.
+1
View File
@@ -30,6 +30,7 @@ sub _void {
our %HELP_EVAL = ( our %HELP_EVAL = (
en => "This command allows you to eval Perl code. USE WITH CAUTION. \2Syntax:\2 EVAL <expression>", en => "This command allows you to eval Perl code. USE WITH CAUTION. \2Syntax:\2 EVAL <expression>",
de => "Dieser Befehl ermoeglicht du auf bewertst Perl Code. GEBRAUCH MIT VORSICHT. \2Syntax:\2 EVAL <expression>", de => "Dieser Befehl ermoeglicht du auf bewertst Perl Code. GEBRAUCH MIT VORSICHT. \2Syntax:\2 EVAL <expression>",
fr => "Cette commande vous permet d'évaluer du code Perl. UTILISER AVEC PRUDENCE. \2Syntaxe:\2 EVAL <expression>",
); );
# Callback for EVAL command. # Callback for EVAL command.
+1
View File
@@ -31,6 +31,7 @@ sub _void
# Help hashes. # Help hashes.
our %HELP_ISITUP = ( our %HELP_ISITUP = (
'en' => "This command will check if a website appears up or down to the bot. \002Syntax:\002 ISITUP <url>", 'en' => "This command will check if a website appears up or down to the bot. \002Syntax:\002 ISITUP <url>",
'fr' => "Cette commande va vérifier si un site Web semble être vers le haut ou vers le bas pour le bot. \002Syntaxe:\002 ISITUP <url>",
); );
# Callback for ISITUP command. # Callback for ISITUP command.
+1
View File
@@ -27,6 +27,7 @@ sub _void {
# Help for LOLCAT. # Help for LOLCAT.
our %HELP_LOLCAT = ( our %HELP_LOLCAT = (
en => "This command will translate English to LOLCAT speak. \2Syntax:\2 LOLCAT <text>", en => "This command will translate English to LOLCAT speak. \2Syntax:\2 LOLCAT <text>",
fr => "Cette commande va traduire l'anglais vers LOLCAT parler. \2Syntaxe:\2 LOLCAT <texte",
); );
# Callback for LOLCAT command. # Callback for LOLCAT command.
+10 -1
View File
@@ -13,7 +13,7 @@ sub _init
# Add a hook for when we join a channel. # Add a hook for when we join a channel.
hook_add('on_connect', 'Oper.onconnect', \&M::Oper::on_connect) or return; hook_add('on_connect', 'Oper.onconnect', \&M::Oper::on_connect) or return;
# Add a hook for when we get numeric 491 (ERR_NOOPERHOST) # Add a hook for when we get numeric 491 (ERR_NOOPERHOST)
rchook_add('491', 'Oper.on381', \&M::Oper::on_num491) or return; rchook_add('491', 'Oper.on491', \&M::Oper::on_num491) or return;
return 1; return 1;
} }
@@ -70,6 +70,15 @@ sub oper {
return 1; return 1;
} }
# Deopers Auto on the specified server.
sub deoper {
my ($svr) = @_;
Auto::socksnd($svr, "MODE $State::IRC::botinfo{$svr}{nick} -o");
return 1;
}
# End of the API
# Start initialization. # Start initialization.
API::Std::mod_init('Oper', 'Xelhua', '1.01', '3.0.0a10'); API::Std::mod_init('Oper', 'Xelhua', '1.01', '3.0.0a10');
# build: perl=5.010000 # build: perl=5.010000
+136
View File
@@ -0,0 +1,136 @@
# Module: Ping. See below for documentation.
# Copyright (C) 2010-2011 Xelhua Development Group, et al.
# This program is free software; rights to this code are stated in doc/LICENSE.
package M::Ping;
use strict;
use warnings;
use API::Std qw(cmd_add cmd_del hook_add hook_del rchook_add rchook_del);
use API::IRC qw(privmsg notice who);
my (@PING, $STATE);
my $LAST = 0;
# Initialization subroutine.
sub _init {
# Create the PING command.
cmd_add('PING', 0, 'cmd.ping', \%M::Ping::HELP_PING, \&M::Ping::cmd_ping) or return;
# Create the on_whoreply hook.
hook_add('on_whoreply', 'ping.who', \&M::Ping::on_whoreply) or return;
# Hook onto numeric 315.
rchook_add('315', 'ping.eow', \&M::Ping::ping) or return;
# Success.
return 1;
}
# Void subroutine.
sub _void {
# Delete the PING command.
cmd_del('PING') or return;
# Delete the on_whoreply hook.
hook_del('on_whoreply', 'ping.who') or return;
# Delete 315 hook.
rchook_del('315', 'ping.eow') or return;
# Success.
return 1;
}
# Help for PING.
our %HELP_PING = (
en => "This command will ping all non-/away users in the channel. \2Syntax:\2 PING",
);
# Callback for PING command.
sub cmd_ping {
my ($src, @argv) = @_;
# Check ratelimit (once every five minutes).
if ((time - $LAST) < 300) {
notice($src->{svr}, $src->{nick}, 'This command is ratelimited. Please wait a while before using it again.');
return;
}
# Set last used time to current time.
$LAST = time;
# Set state.
$STATE = $src->{svr}.'::'.$src->{chan};
# Ship off a WHO.
who($src->{svr}, $src->{chan});
return 1;
}
# Callback for WHO reply.
sub on_whoreply {
my ($svr, $nick, $target, undef, undef, undef, $status, undef, undef) = @_;
# If it's us, just return.
if ($nick eq $State::IRC::botinfo{$svr}{nick}) { return 1 }
# Check if we're doing a ping right now.
if ($STATE) {
# Check if this is the target channel.
if ($STATE eq $svr.'::'.$target) {
# If their status is not away, push to ping array.
if ($status !~ m/G/xsm) {
push @PING, $nick;
}
}
}
return 1;
}
# Ping!
sub ping {
if ($STATE) {
my ($svr, $chan) = split '::', $STATE, 2;
privmsg($svr, $chan, 'PING! '.join(' ', @PING));
@PING = ();
$STATE = 0;
}
return 1;
}
# Start initialization.
API::Std::mod_init('Ping', 'Xelhua', '1.01', '3.0.0a11');
# build: perl=5.010000
__END__
=head1 NAME
Ping - A module for pinging a channel.
=head1 VERSION
1.01
=head1 SYNOPSIS
<Hermione> .ping
<howlbot> PING! `A` tdubellz Hermione Oakfeather LightToagac shadowm_goat kitten starcoder2 Suiseiseki metabill theknife Trashlord Cam HardDisk_WP nerdshark2 MJ94 JonathanD Julius2 CensoredBiscuit LordVoldemort e36freak alyx mth starcoder
=head1 DESCRIPTION
This merely creates the PING command, which will highlight everyone in the
channel, excluding the bot itself and those who are /away.
=head1 AUTHOR
This module was written by Elijah Perrault.
This module is maintained by Xelhua Development Group.
=head1 LICENSE AND COPYRIGHT
This module is Copyright 2010-2011 Xelhua Development Group. All rights
reserved.
This module is released under the same licensing terms as Auto itself.
=cut
# vim: set ai et ts=4 sw=4:
+1
View File
@@ -32,6 +32,7 @@ sub _void
# Help hashes. # Help hashes.
our %HELP_WEATHER = ( our %HELP_WEATHER = (
'en' => "This command will retrieve the weather via Wunderground for the specified location. \002Syntax:\002 WEATHER <location>", 'en' => "This command will retrieve the weather via Wunderground for the specified location. \002Syntax:\002 WEATHER <location>",
'fr' => "Cette commande permet de récupérer la météo via Wunderground pour l'emplacement spécifié. \002Syntaxe:\002 WEATHER <emplacement>",
); );
# Callback for Weather command. # Callback for Weather command.
@@ -7,7 +7,8 @@ use warnings;
use feature qw(switch); use feature qw(switch);
use API::Std qw(cmd_add cmd_del trans hook_add hook_del timer_add timer_del trans conf_get has_priv match_user); use API::Std qw(cmd_add cmd_del trans hook_add hook_del timer_add timer_del trans conf_get has_priv match_user);
use API::IRC qw(privmsg notice cmode); use API::IRC qw(privmsg notice cmode);
my ($GAME, $PGAME, $GAMECHAN, $GAMETIME, %PLAYERS, %NICKS, @STATIC, $PHASE, $SEEN, $VISIT, $GUARD, %KILL, %WKILL, %LYNCH, %SPOKE, %WARN, $LVOTEN, @SHOT, $BULLETS, $DETECTED); our ($GAME, $PGAME, $GAMECHAN, $GAMETIME, %PLAYERS, %NICKS, @STATIC, $PHASE, $SEEN, $VISIT, $GUARD, %KILL, %WKILL, %LYNCH, %SPOKE, %WARN, $LVOTEN, @SHOT,
$BULLETS, $DETECTED, $WAIT, $WAITED, $FM);
my $FCHAR = (conf_get('fantasy_pf'))[0][0]; my $FCHAR = (conf_get('fantasy_pf'))[0][0];
# Initialization subroutine. # Initialization subroutine.
@@ -64,6 +65,7 @@ sub _void {
# Commands hash. # Commands hash.
my %COMMANDS = ( my %COMMANDS = (
'join' => 'wolf join', 'join' => 'wolf join',
'wait' => 'wolf wait',
'start' => 'wolf start', 'start' => 'wolf start',
'see' => 'wolf see <nick>', 'see' => 'wolf see <nick>',
'visit' => 'wolf visit <nick>', 'visit' => 'wolf visit <nick>',
@@ -74,9 +76,24 @@ my %COMMANDS = (
'id' => 'wolf id <nick>', 'id' => 'wolf id <nick>',
); );
# No villagers dead messages.
my @NOVICTIM = (
'A pool of blood and wolf paw prints are found.',
'The body of a young penguin pet is found.',
'Traces of wolf fur are found.',
);
# Lynch messages.
my @LYNCHMSG = (
"The villagers, after much debate, finally decide on lynching \2%s\2, who turned out to be... a \2%s\2.",
"Under a lot of noise, the pitchfork-bearing villagers lynch \2%s\2, who turned out to be... a \2%s\2.",
"The mob drags a protesting \2%s\2 to the hanging tree. He/She succumbs to the will of the horde, and is hanged. It is discovered (s)he was a \2%s\2.",
"Resigned to his/her fate, \2%s\2 is led to the gallows. After death, it is discovered (s)he was a \2%s\2.",
);
# Help hash for the WOLF command. # Help hash for the WOLF command.
our %HELP_WOLF = ( our %HELP_WOLF = (
en => "This command allows you to perform various actions in a game of Werewolf (A.K.A. Mafia). \2Syntax:\2 WOLF (JOIN|START|LYNCH|RETRACT|SHOOT|QUIT|KICK|VOTES|STATS / SEE|ID|VISIT|GUARD|KILL) [parameters]", en => "This command allows you to perform various actions in a game of Werewolf (A.K.A. Mafia). \2Syntax:\2 WOLF (JOIN|WAIT|START|LYNCH|RETRACT|SHOOT|QUIT|VOTES|STATS / SEE|ID|VISIT|GUARD|KILL) [parameters]",
); );
# Callback for the WOLF command. # Callback for the WOLF command.
@@ -113,10 +130,16 @@ sub cmd_wolf {
$PLAYERS{lc $src->{nick}} = 0; $PLAYERS{lc $src->{nick}} = 0;
$NICKS{lc $src->{nick}} = $src->{nick}; $NICKS{lc $src->{nick}} = $src->{nick};
$GAMETIME = time; $GAMETIME = time;
$WAIT = 60;
$WAITED = 0;
# Start wait timer.
timer_add('werewolf.joinwait', 2, 1, sub {
if ($M::Werewolf::WAIT) { $M::Werewolf::WAIT-- }
});
# Game started. # Game started.
cmode($src->{svr}, $src->{chan}, "+v $src->{nick}"); cmode($src->{svr}, $src->{chan}, "+v $src->{nick}");
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 has started a game of Werewolf. Type \"".$FCHAR.$COMMANDS{'join'}.'" to join. Type "'.$FCHAR.$COMMANDS{start}.'" to start the game.'); privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 has started a game of Werewolf. Type \"".$FCHAR.$COMMANDS{'join'}.'" to join. Type "'.$FCHAR.$COMMANDS{start}.'" to start the game. Type "'.$FCHAR.$COMMANDS{wait}.'" to increase join wait time.');
} }
elsif ($GAME) { elsif ($GAME) {
notice($src->{svr}, $src->{nick}, 'Sorry, but the game is already running. Try again next time.'); notice($src->{svr}, $src->{nick}, 'Sorry, but the game is already running. Try again next time.');
@@ -150,6 +173,45 @@ sub cmd_wolf {
privmsg($gsvr, $gchan, "\2$src->{nick}\2 joined the game."); privmsg($gsvr, $gchan, "\2$src->{nick}\2 joined the game.");
} }
} }
when (/^(WAIT|W)$/) {
# WOLF WAIT
# Check if a game is running.
if (!$PGAME) {
if (!$GAME) {
notice($src->{svr}, $src->{nick}, 'No game is currently running.');
return;
}
else {
notice($src->{svr}, $src->{nick}, 'Werewolf is already in play.');
return;
}
}
# Check if this is the game channel.
if ($src->{svr}.'/'.$src->{chan} ne $GAMECHAN) {
notice($src->{svr}, $src->{nick}, "Werewolf is currently running in \2$GAMECHAN\2.");
return;
}
# Make sure they're playing.
if (!defined $PLAYERS{lc $src->{nick}}) {
notice($src->{svr}, $src->{nick}, 'You\'re not currently playing.');
return;
}
# Check if we're already waiting a while.
if ($WAITED >= 2) {
privmsg($src->{svr}, $src->{chan}, "$src->{nick}: Already waiting 100 seconds.");
return;
}
# Increase WAIT.
$WAIT += 20;
# And WAITED.
$WAITED++;
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 increased join wait time by 20 seconds.");
}
when ('START') { when ('START') {
# WOLF START # WOLF START
@@ -177,11 +239,9 @@ sub cmd_wolf {
return; return;
} }
# Check join timeout. # Check join wait time.
if ((time - $GAMETIME) < 60) { if ($WAIT) {
my $time = time - $GAMETIME; privmsg($src->{svr}, $src->{chan}, "$src->{nick}: Please wait at least \2$WAIT\2 more seconds.");
$time = 60 - $time;
privmsg($src->{svr}, $src->{chan}, "$src->{nick}: Please wait at least \2$time\2 more seconds.");
return; return;
} }
@@ -195,8 +255,9 @@ sub cmd_wolf {
my $cwolves = POSIX::ceil(keys(%PLAYERS) * .14); my $cwolves = POSIX::ceil(keys(%PLAYERS) * .14);
# Only one seer, harlot, guardian angel, traitor and detective. # Only one seer, harlot, guardian angel, traitor and detective.
my $cseers = 1; my $cseers = 1;
my $charlots = my $cangels = my $ctraitors = my $cdetectives = 0; my $charlots = my $cdrunks = my $cangels = my $ctraitors = my $cdetectives = 0;
if (keys %PLAYERS >= 6) { $charlots++ unless conf_get('werewolf:rated-g') } if (keys %PLAYERS >= 6) { $charlots++ unless conf_get('werewolf:rated-g') }
if (keys %PLAYERS >= 7) { $cdrunks++ unless conf_get('werewolf:rated-g') }
if (keys %PLAYERS >= 9) { $cangels++ unless conf_get('werewolf:no-angels') } if (keys %PLAYERS >= 9) { $cangels++ unless conf_get('werewolf:no-angels') }
if (keys %PLAYERS >= 12 and conf_get('werewolf:traitors')) { $ctraitors++ } if (keys %PLAYERS >= 12 and conf_get('werewolf:traitors')) { $ctraitors++ }
if (keys %PLAYERS >= 16 and conf_get('werewolf:detectives')) { $cdetectives++ } if (keys %PLAYERS >= 16 and conf_get('werewolf:detectives')) { $cdetectives++ }
@@ -234,6 +295,14 @@ sub cmd_wolf {
$STATIC[2] = "\2$NICKS{$rpi}\2"; $STATIC[2] = "\2$NICKS{$rpi}\2";
} }
} }
# Set drunks.
while ($cdrunks > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($PLAYERS{$rpi} =~ m/v/xsm) {
$PLAYERS{$rpi} = 'vi';
$cdrunks--;
}
}
# Set guardian angels. # Set guardian angels.
while ($cangels > 0) { while ($cangels > 0) {
my $rpi = $plyrs[int rand scalar @plyrs]; my $rpi = $plyrs[int rand scalar @plyrs];
@@ -262,14 +331,16 @@ sub cmd_wolf {
} }
} }
# If there's 6 or more players, give one of them a gun. # If there's 8 or more players, give one of them a gun.
if (keys %PLAYERS >= 6) { if (keys %PLAYERS >= 8) {
my $rpi = $plyrs[int rand scalar @plyrs]; my $rpi = $plyrs[int rand scalar @plyrs];
while ($PLAYERS{$rpi} =~ m/w/xsm || $PLAYERS{$rpi} =~ m/t/xsm) { $rpi = $plyrs[int rand scalar @plyrs] } while ($PLAYERS{$rpi} =~ m/w/xsm || $PLAYERS{$rpi} =~ m/t/xsm) { $rpi = $plyrs[int rand scalar @plyrs] }
$PLAYERS{$rpi} .= 'b'; $PLAYERS{$rpi} .= 'b';
# And give them PLAYER COUNT * .12 bullets rounded up. # And give them PLAYER COUNT * .12 bullets rounded up.
$BULLETS = POSIX::ceil(keys(%PLAYERS) * .12); $BULLETS = POSIX::ceil(keys(%PLAYERS) * .12);
if ($PLAYERS{$rpi} =~ m/i/xsm) { $BULLETS = $BULLETS * 3 }
} }
# Set variables. # Set variables.
@@ -283,6 +354,8 @@ sub cmd_wolf {
my ($gsvr, $gchan) = split '/', $GAMECHAN; my ($gsvr, $gchan) = split '/', $GAMECHAN;
privmsg($gsvr, $gchan, 'Game is now starting.'); privmsg($gsvr, $gchan, 'Game is now starting.');
cmode($gsvr, $gchan, '+m'); cmode($gsvr, $gchan, '+m');
# Delete waiting timer.
timer_del('werewolf.joinwait');
# Start timer for bed checking. # Start timer for bed checking.
timer_add('werewolf.chkbed', 2, 5, \&M::Werewolf::_chkbed); timer_add('werewolf.chkbed', 2, 5, \&M::Werewolf::_chkbed);
# Initialize the nighttime. # Initialize the nighttime.
@@ -497,44 +570,54 @@ sub cmd_wolf {
# All good, lets go! # All good, lets go!
my $real = $NICKS{lc $argv[1]}; my $real = $NICKS{lc $argv[1]};
# Massive randomizing here. 5 = 3-kill, 1-miss, 1-suicide # Massive randomizing here. 7 = 5-hit, 1-miss, 1-suicide
my $myr = int rand 6; my $myr = int rand 8;
given ($myr) { given ($myr) {
when (4) { # It's a miss. when (4) { # It's a miss.
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 is a lousy shooter. He/She missed!"); privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 is a lousy shooter. He/She missed!");
} }
when (5) { # Gun explodes = suicide. when (5) { # Gun explodes = suicide.
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 should clean his/her weapons more often. The gun exploded and killed him/her!"); privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 should clean his/her weapons more often. The gun exploded and killed him/her!");
if (_getrole(lc $src->{nick}, 2) ne 'villager') { privmsg($src->{svr}, $src->{chan}, "Appears s(he) was a \2"._getrole(lc $src->{nick}, 2)."\2."); } if (_getrole(lc $src->{nick}, 2) ne 'villager') { privmsg($src->{svr}, $src->{chan}, "Appears (s)he was a \2"._getrole(lc $src->{nick}, 2)."\2."); }
_player_del(lc $src->{nick}); _player_del(lc $src->{nick});
return 1; return 1;
} }
default { # It's a hit. default { # It's a hit.
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 shot \2$real\2 with a silver bullet!"); # Or not!
if ($PLAYERS{lc $src->{nick}} =~ m/i/xsm and $_ =~ m/^[1-3]$/xsm) {
# Check if the target is a wolf or a villager. privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 is a lousy shooter. He/She missed!");
if ($PLAYERS{lc $argv[1]} =~ m/w/xsm) { # Wolf.
privmsg($src->{svr}, $src->{chan}, "\2$real\2 is a wolf, and is dying from the silver bullet.");
_player_del(lc $argv[1]);
} }
else { # Villager. else {
# So, there's a 1/5 chance of a villager dying. privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 shot \2$real\2 with a silver bullet!");
my $rint = int rand 6;
given ($rint) { # Check if the target is a wolf or a villager.
when (5) { # Killed. if ($PLAYERS{lc $argv[1]} =~ m/w/xsm) { # Wolf.
privmsg($src->{svr}, $src->{chan}, "\2$real\2 is a villager, but \2$src->{nick}\2 accidentally shot them in the head and they are now dying."); privmsg($src->{svr}, $src->{chan}, "\2$real\2 is a wolf, and is dying from the silver bullet.");
if (_getrole(lc $real, 2) ne 'villager') { privmsg($src->{svr}, $src->{chan}, "Appears s(he) was a \2"._getrole(lc $real, 2)."\2."); } _player_del(lc $argv[1]);
# Kill them. }
_player_del(lc $real); else { # Villager.
} # So, there's a 1/5 chance of a villager dying.
default { # Only hurt. my $rint = int rand 6;
privmsg($src->{svr}, $src->{chan}, "\2$real\2 is a villager, and is hurt but will have a full recovery. He/She will be resting for the day."); given ($rint) {
push @SHOT, lc $real; when (5) { # Killed.
# Delete any votes they might've made today. privmsg($src->{svr}, $src->{chan}, "\2$real\2 is a villager, but \2$src->{nick}\2 accidentally shot them in the head and they are now dying.");
foreach my $plyr (keys %LYNCH) { if (_getrole(lc $real, 2) ne 'villager') { privmsg($src->{svr}, $src->{chan}, "Appears (s)he was a \2"._getrole(lc $real, 2)."\2."); }
if (exists $LYNCH{$plyr}{lc $real}) { delete $LYNCH{$plyr}{lc $real} } # Kill them.
_player_del(lc $real);
}
default { # Only hurt.
privmsg($src->{svr}, $src->{chan}, "\2$real\2 is a villager, and is hurt but will have a full recovery. He/She will be resting for the day.");
push @SHOT, lc $real;
# Delete any votes they might've made today.
foreach my $plyr (keys %LYNCH) {
if (exists $LYNCH{$plyr}{lc $real}) { delete $LYNCH{$plyr}{lc $real} }
}
# Set number of votes required to lynch.
_calclvn();
# Check for winning conditions.
_chkwin();
} }
$LVOTEN--;
} }
} }
} }
@@ -574,6 +657,7 @@ sub cmd_wolf {
privmsg($src->{svr}, $src->{chan}, "$src->{nick}: \2".keys(%PLAYERS)."\2 players: $str"); privmsg($src->{svr}, $src->{chan}, "$src->{nick}: \2".keys(%PLAYERS)."\2 players: $str");
# If all roles have been assigned, return the count of each. # If all roles have been assigned, return the count of each.
if ($GAME) { if ($GAME) {
# Get a count of all roles.
my $cwolves = my $cseers = my $charlots = my $cangels = my $ctraitors = my $cdetectives = 0; my $cwolves = my $cseers = my $charlots = my $cangels = my $ctraitors = my $cdetectives = 0;
foreach my $flags (values %PLAYERS) { foreach my $flags (values %PLAYERS) {
if ($flags =~ m/w/xsm) { $cwolves++ } if ($flags =~ m/w/xsm) { $cwolves++ }
@@ -583,41 +667,23 @@ sub cmd_wolf {
if ($flags =~ m/t/xsm) { $ctraitors++ } if ($flags =~ m/t/xsm) { $ctraitors++ }
if ($flags =~ m/d/xsm) { $cdetectives++ } if ($flags =~ m/d/xsm) { $cdetectives++ }
} }
privmsg($src->{svr}, $src->{chan}, "$src->{nick}: There are \2$cwolves\2 wolves, \2$cseers\2 seers, ". # Prepare an array of data.
"\2$charlots\2 ".((conf_get('werewolf:rated-g')) ? '<removed>' : 'harlots').", \2$ctraitors\2 traitors, \2$cdetectives\2 detectives, ". my @data;
"and \2$cangels\2 guardian angels."); push @data, "\2$cwolves\2 wolves";
} push @data, "\2$cseers\2 seers";
}
when (/^(KICK|K)$/) {
# WOLF KICK
# Check if a game is running. # Push extra roles.
if (!$GAME and !$PGAME) { if (!conf_get('werewolf:rated-g')) { push @data, "\2$charlots\2 harlots" }
notice($src->{svr}, $src->{nick}, 'No game is currently running.'); if (!conf_get('werewolf:no-angels')) { push @data, "\2$cangels\2 guardian angels" }
return; if (conf_get('werewolf:traitors')) { push @data, "\2$ctraitors\2 traitors" }
} if (conf_get('werewolf:detectives')) { push @data, "\2$cdetectives\2 detectives" }
# Check if this is the game channel. # Prepare message.
if ($src->{svr}.'/'.$src->{chan} ne $GAMECHAN) { my $msg = "$src->{nick}: There are ".join(', ', @data[0..$#data-1]);
notice($src->{svr}, $src->{nick}, "Werewolf is currently running in \2$GAMECHAN\2."); $msg .= ", and $data[$#data].";
return;
}
# Check for the werewolf.admin privilege. privmsg($src->{svr}, $src->{chan}, $msg);
if (!has_priv(match_user(%{$src}), 'werewolf.admin')) {
notice($src->{svr}, $src->{nick}, trans('Permission denied').q{.});
return;
} }
# Requires an extra parameter.
if (!defined $argv[1]) {
notice($src->{svr}, $src->{nick}, trans('Not enough parameters').q{.});
return;
}
# Kill the target.
privmsg($src->{svr}, $src->{chan}, "\2$argv[1]\2 died of an unknown disease. He/She was a \2"._getrole(lc $argv[1], 2)."\2.");
_player_del(lc $argv[1]);
} }
when (/^(QUIT|Q)$/) { when (/^(QUIT|Q)$/) {
# WOLF QUIT # WOLF QUIT
@@ -790,7 +856,7 @@ sub cmd_wolf {
# They can only protect one person per round. # They can only protect one person per round.
if ($GUARD) { if ($GUARD) {
privmsg($src->{svr}, $src->{nick}, "You are already protecting \2$NICKS{$VISIT}\2."); privmsg($src->{svr}, $src->{nick}, "You are already protecting \2$NICKS{$GUARD}\2.");
return; return;
} }
@@ -848,7 +914,10 @@ sub cmd_wolf {
# They can only visit one person per round. # They can only visit one person per round.
if ($VISIT) { if ($VISIT) {
privmsg($src->{svr}, $src->{nick}, "You are already spending the night with \2$NICKS{$VISIT}\2!"); my $friend;
if ($VISIT eq 1) { $friend = 'at home' }
else { $friend = "with $NICKS{$VISIT}" }
privmsg($src->{svr}, $src->{nick}, "You are already spending the night \2$friend\2!");
return; return;
} }
@@ -864,10 +933,12 @@ sub cmd_wolf {
return; return;
} }
# They can't sleep with themselves. # Check if they've selected themselves.
if (lc $argv[1] eq lc $src->{nick}) { if (lc $argv[1] eq lc $src->{nick}) {
privmsg($src->{svr}, $src->{nick}, 'You cannot sleep with yourself!'); privmsg($src->{svr}, $src->{nick}, 'You have chosen to stay home for the night.');
return; $VISIT = 1;
_chknight();
return 1;
} }
# All good, set variables and stuff. # All good, set variables and stuff.
@@ -929,7 +1000,9 @@ sub cmd_wolf {
} }
# If they're changing their selection, reverse the old victim's data. # If they're changing their selection, reverse the old victim's data.
if ($WKILL{lc $src->{nick}}) { $KILL{lc $WKILL{lc $src->{nick}}}-- } if ($WKILL{lc $src->{nick}}) {
$KILL{lc $WKILL{lc $src->{nick}}}--;
}
# All good, proceed. # All good, proceed.
$KILL{lc $argv[1]}++; $KILL{lc $argv[1]}++;
@@ -961,7 +1034,7 @@ sub _init_night {
$erole = 'wolf'; $erole = 'wolf';
$msg = "It is your job to kill all the villagers. Use \"$COMMANDS{kill}\" to kill a villager. Also, if you send a PM to me, it will be relayed to all other wolves.\n&pi&"; $msg = "It is your job to kill all the villagers. Use \"$COMMANDS{kill}\" to kill a villager. Also, if you send a PM to me, it will be relayed to all other wolves.\n&pi&";
my $cwolves = 0; my $cwolves = 0;
for (values %PLAYERS) { if (m/w/xsm) { $cwolves++ } } for (values %PLAYERS) { if (m/(w|t)/xsm) { $cwolves++ } }
if ($cwolves > 1) { $msg .= "\nAlso, please consider using PM's or a channel to speak with your fellow wolves rather than my relay, to prevent from me lagging." } if ($cwolves > 1) { $msg .= "\nAlso, please consider using PM's or a channel to speak with your fellow wolves rather than my relay, to prevent from me lagging." }
} }
# For harlots. # For harlots.
@@ -1017,9 +1090,14 @@ sub _init_night {
} }
# Check if they have the gun. # Check if they have the gun.
if ($role =~ m/b/xsm and $BULLETS) { if ($role =~ m/b/xsm and $BULLETS) {
privmsg($gsvr, $NICKS{$plyr}, 'You hold a special gun. You may only use it during the day. If you shoot a wolf, (s)he will die instantly, if you shoot a villager, they will likely live. You get '.$BULLETS.' shot(s).'); privmsg($gsvr, $NICKS{$plyr}, 'You hold a gun with special silver bullet(s). You may only use it during the day. If you shoot a wolf, (s)he will die instantly, if you shoot a villager, they will likely live. You get '.$BULLETS.' shot(s).');
privmsg($gsvr, $NICKS{$plyr}, 'To shoot someone, type "'.$FCHAR.$COMMANDS{shoot}.'" in the channel during the day.'); privmsg($gsvr, $NICKS{$plyr}, 'To shoot someone, type "'.$FCHAR.$COMMANDS{shoot}.'" in the channel during the day.');
} }
# And for drunks.
if ($role =~ m/i/xsm and $role !~ m/a/xsm) {
privmsg($gsvr, $NICKS{$plyr}, 'You have been drinking too much! You are the village drunk.');
$PLAYERS{$plyr} .= 'a';
}
} }
# It is now nighttime. # It is now nighttime.
@@ -1071,12 +1149,12 @@ sub _init_day {
} }
} }
# Now check if the harlot spent the night with a wolf last night. # Now check if the harlot spent the night with a wolf last night.
if (!$harlotd and $VISIT) { if (!$harlotd and $VISIT) { if (exists $PLAYERS{$VISIT}) {
if ($PLAYERS{$VISIT} =~ m/w/xsm) { if ($PLAYERS{$VISIT} =~ m/w/xsm) {
# Ouch! He/She did, gotta kill them. :( # Ouch! He/She did, gotta kill them. :(
$harlotd = 2; $harlotd = 2;
} }
} } }
# Last check; lets find out if the guardian angel protected a wolf last night. # Last check; lets find out if the guardian angel protected a wolf last night.
my $angeld; my $angeld;
@@ -1093,10 +1171,10 @@ sub _init_day {
} }
# Finally, check if the harlot was targeted and wasn't home. # Finally, check if the harlot was targeted and wasn't home.
if (_getrole($victim, 2) eq 'harlot' and $VISIT) { if (_getrole($victim, 2) eq 'harlot' and $VISIT) { if ($VISIT ne 1) {
privmsg($gsvr, $gchan, 'The wolves attempted to attack the harlot last night, but (s)he wasn\'t home...'); privmsg($gsvr, $gchan, 'The wolves attempted to attack the harlot last night, but (s)he wasn\'t home...');
$victim = 0; $victim = 0;
} } }
# Set phase to day. # Set phase to day.
$PHASE = 'd'; $PHASE = 'd';
@@ -1104,7 +1182,7 @@ sub _init_day {
# Cool, all data should be ready for shipment. Lets go! # Cool, all data should be ready for shipment. Lets go!
my $continue = 1; my $continue = 1;
my $msg = 'It is now daytime. The villagers awake, thankful for surviving the night, and search the village...'; my $msg = 'It is now daytime. The villagers awake, thankful for surviving the night, and search the village...';
if (!$victim) { privmsg($gsvr, $gchan, "$msg The body of a young penguin pet is found. All villagers however, have survived.") } if (!$victim) { privmsg($gsvr, $gchan, "$msg ".$NOVICTIM[int rand scalar @NOVICTIM]." All villagers however, have survived.") }
elsif ($victim eq 1) { elsif ($victim eq 1) {
privmsg($gsvr, $gchan, "$msg \2$NICKS{$GUARD}\2 was attacked by the wolves last night, but luckily, the guardian angel protected them."); privmsg($gsvr, $gchan, "$msg \2$NICKS{$GUARD}\2 was attacked by the wolves last night, but luckily, the guardian angel protected them.");
} }
@@ -1143,8 +1221,7 @@ sub _init_day {
if (!$continue) { return 1 } if (!$continue) { return 1 }
# Set number of votes required to lynch. # Set number of votes required to lynch.
$LVOTEN = int(scalar(keys(%PLAYERS)) / 2); _calclvn();
$LVOTEN++;
privmsg($gsvr, $gchan, 'The villagers must now vote for who to lynch. Use "'.$FCHAR.$COMMANDS{lynch}.'" to cast your vote. '.$LVOTEN.' votes are required to lynch.'); privmsg($gsvr, $gchan, 'The villagers must now vote for who to lynch. Use "'.$FCHAR.$COMMANDS{lynch}.'" to cast your vote. '.$LVOTEN.' votes are required to lynch.');
# Clear variables. # Clear variables.
@@ -1203,7 +1280,7 @@ sub _judgment {
# Kill him/her! # Kill him/her!
my ($gsvr, $gchan) = split '/', $GAMECHAN; my ($gsvr, $gchan) = split '/', $GAMECHAN;
privmsg($gsvr, $gchan, "The villagers, after much debate, finally decide on lynching \2$NICKS{$nick}\2, who turned out to be... a \2"._getrole($nick, 2)."\2."); privmsg($gsvr, $gchan, sprintf($LYNCHMSG[int rand scalar @LYNCHMSG], $NICKS{$nick}, _getrole($nick, 2)));
my $ri = _player_del($nick, 1); my $ri = _player_del($nick, 1);
# Initialize nighttime. # Initialize nighttime.
@@ -1212,6 +1289,15 @@ sub _judgment {
return 1; return 1;
} }
# Subroutine for re-calculating LVOTEN.
sub _calclvn {
my $pc = keys %PLAYERS;
$pc -= scalar @SHOT;
$LVOTEN = int($pc / 2) + 1;
return 1;
}
# Subroutine for checking who is in bed and who is not. # Subroutine for checking who is in bed and who is not.
sub _chkbed { sub _chkbed {
my ($gsvr, $gchan) = split '/', $GAMECHAN, 2; my ($gsvr, $gchan) = split '/', $GAMECHAN, 2;
@@ -1237,7 +1323,7 @@ sub _chkbed {
# Send out any warnings. # Send out any warnings.
if (scalar @warn) { if (scalar @warn) {
privmsg($gsvr, $gchan, join(', ', @warn).': You have been idling for a while. Please remember to say something soon or you might be declared dead.') privmsg($gsvr, $gchan, join(', ', @warn).": \2You have been idling for a while. Please remember to say something soon or you might be declared dead.\2")
} }
return 1; return 1;
@@ -1257,6 +1343,7 @@ sub _getrole {
elsif ($PLAYERS{$plyr} =~ m/h/xsm) { $role = 'harlot' } elsif ($PLAYERS{$plyr} =~ m/h/xsm) { $role = 'harlot' }
elsif ($PLAYERS{$plyr} =~ m/g/xsm) { $role = 'guardian angel' } elsif ($PLAYERS{$plyr} =~ m/g/xsm) { $role = 'guardian angel' }
elsif ($PLAYERS{$plyr} =~ m/d/xsm) { $role = 'detective' } elsif ($PLAYERS{$plyr} =~ m/d/xsm) { $role = 'detective' }
elsif ($PLAYERS{$plyr} =~ m/i/xsm) { $role = 'village drunk' }
elsif ($PLAYERS{$plyr} =~ m/(v|t)/xsm) { $role = 'villager' } elsif ($PLAYERS{$plyr} =~ m/(v|t)/xsm) { $role = 'villager' }
} }
elsif ($lev == 2) { elsif ($lev == 2) {
@@ -1266,6 +1353,7 @@ sub _getrole {
elsif ($PLAYERS{$plyr} =~ m/g/xsm) { $role = 'guardian angel' } elsif ($PLAYERS{$plyr} =~ m/g/xsm) { $role = 'guardian angel' }
elsif ($PLAYERS{$plyr} =~ m/d/xsm) { $role = 'detective' } elsif ($PLAYERS{$plyr} =~ m/d/xsm) { $role = 'detective' }
elsif ($PLAYERS{$plyr} =~ m/t/xsm) { $role = 'traitor' } elsif ($PLAYERS{$plyr} =~ m/t/xsm) { $role = 'traitor' }
elsif ($PLAYERS{$plyr} =~ m/i/xsm) { $role = 'village drunk' }
elsif ($PLAYERS{$plyr} =~ m/v/xsm) { $role = 'villager' } elsif ($PLAYERS{$plyr} =~ m/v/xsm) { $role = 'villager' }
} }
} }
@@ -1305,27 +1393,32 @@ sub _player_del {
} }
if ($SEEN) { if ($SEEN eq $player) { $SEEN = 0 } } if ($SEEN) { if ($SEEN eq $player) { $SEEN = 0 } }
# If there are no more wolves, check if we have a traitor.
my $cwolves;
for (values %PLAYERS) { if (m/w/xsm) { $cwolves++ } }
if (!$cwolves) {
my $traitor;
while (my ($tp, $tv) = each %PLAYERS) { if ($tv =~ m/t/xsm) { $traitor = $tp } }
# Now if we have a traitor...
if ($traitor) {
# Transform them into a wolf.
$PLAYERS{$traitor} = 'w';
privmsg($gsvr, $NICKS{$traitor}, 'HOOOOOOOOOWL. You have become... a wolf! It is up to you to avenge your fallen leaders!');
privmsg($gsvr, $gchan, "\2The villagers, during their celebrations, are frightened as they hear a loud howl. The wolves are not gone!\2");
}
}
# Update LVOTEN. # Update LVOTEN.
if ($LVOTEN) { $LVOTEN-- } if ($LVOTEN) { _calclvn() }
# Check for winning conditions.
if (!_chkwin()) { return }
# Call lynch management IF judgment did not call us. # Call lynch management IF judgment did not call us.
if ($PHASE and !$judgment) { if ($PHASE and !$judgment) {
if ($PHASE eq 'd') { _lynchmng() } if ($PHASE eq 'd') { _lynchmng() }
} }
# Check for winning conditions.
if (!$PGAME) {
my $wolves;
for (values %PLAYERS) { if (m/w/xsm) { $wolves++ } }
if (!$wolves) { _gameover('v'); return }
my $villagers;
for (values %PLAYERS) { if (m/(v|s|g|h|d)/xsm) { $villagers++ } }
if ($villagers <= $wolves) { _gameover('w'); return }
}
else {
# Check if there's any more players.
if (!keys %PLAYERS) { _gameover('n') }
}
# Check if nighttime should end, given we are night. # Check if nighttime should end, given we are night.
if ($PHASE) { if ($PHASE eq 'n') { _chknight() } } if ($PHASE) { if ($PHASE eq 'n') { _chknight() } }
@@ -1350,6 +1443,25 @@ sub _lynchmng {
return 1; return 1;
} }
# Subroutine for checking if we have a winner.
sub _chkwin {
if (!$PGAME) {
my $wolves;
for (values %PLAYERS) { if (m/w/xsm) { $wolves++ } }
if (!$wolves) { _gameover('v'); return }
my $villagers;
for (values %PLAYERS) { if (m/(v|s|g|h|d)/xsm) { $villagers++ } }
$villagers -= scalar @SHOT;
if ($villagers <= $wolves) { _gameover('w'); return }
}
else {
# Check if there's any more players.
if (!keys %PLAYERS) { _gameover('n') }
}
return 1;
}
# Handling the end of the game. # Handling the end of the game.
sub _gameover { sub _gameover {
my ($winner) = @_; my ($winner) = @_;
@@ -1391,7 +1503,8 @@ sub _gameover {
# Clear all variables. # Clear all variables.
if ($PHASE) { if ($PHASE eq 'n') { timer_del('werewolf.goto_daytime') } } if ($PHASE) { if ($PHASE eq 'n') { timer_del('werewolf.goto_daytime') } }
timer_del('werewolf.chkbed'); timer_del('werewolf.chkbed');
$GAME = $PGAME = $GAMECHAN = $GAMETIME = $PHASE = $SEEN = $VISIT = $GUARD = $LVOTEN = $BULLETS = $DETECTED = 0; timer_del('werewolf.joinwait');
$GAME = $PGAME = $GAMECHAN = $GAMETIME = $PHASE = $SEEN = $VISIT = $GUARD = $LVOTEN = $BULLETS = $DETECTED = $WAIT = $WAITED = 0;
%PLAYERS = (); %PLAYERS = ();
%NICKS = (); %NICKS = ();
%KILL = (); %KILL = ();
@@ -1439,12 +1552,24 @@ sub on_uprivmsg {
if ($PLAYERS{lc $src->{nick}} =~ m/w/xsm or $PLAYERS{lc $src->{nick}} =~ m/t/xsm) { if ($PLAYERS{lc $src->{nick}} =~ m/w/xsm or $PLAYERS{lc $src->{nick}} =~ m/t/xsm) {
# Get wolf count. # Get wolf count.
my $cwolves = 0; my $cwolves = 0;
foreach my $flags (values %PLAYERS) { if ($flags =~ m/w/xsm) { $cwolves++ } } foreach my $flags (values %PLAYERS) { if ($flags =~ m/(w|t)/xsm) { $cwolves++ } }
# If there's more than one wolf, relay this message to the others. # If there's more than one wolf, relay this message to the others.
if ($cwolves > 1) { if ($cwolves > 1) {
while ((my $plyr, my $flags) = each %PLAYERS) { while ((my $plyr, my $flags) = each %PLAYERS) {
if ($plyr ne lc $src->{nick} and $flags =~ m/w/xsm or $flags =~ m/t/xsm) { if ($plyr ne lc $src->{nick} and $flags =~ m/w/xsm or $flags =~ m/t/xsm) {
privmsg($src->{svr}, $NICKS{$plyr}, "\2$src->{nick}\2 says: ".join(q{ }, @msg)) # Also, lets try to ignore simulations.
if (uc(join(q{ }, @msg)) =~ m/^WOLF\sKILL/xsmi and
$COMMANDS{kill} !~ m/^WOLF\sKILL/xsmi) { return 1 }
# All good.
if ($msg[0] =~ m/^\001ACTION/xsm) {
shift @msg;
$msg[$#msg] =~ s/\001$//xsm;
privmsg($src->{svr}, $NICKS{$plyr}, "* \2$src->{nick}\2 ".join(q{ }, @msg));
}
else {
privmsg($src->{svr}, $NICKS{$plyr}, "\2$src->{nick}\2 says: ".join(q{ }, @msg));
}
} }
} }
} }
@@ -1497,10 +1622,13 @@ sub on_nick {
$LYNCH{$new} = $LYNCH{lc $src->{nick}}; $LYNCH{$new} = $LYNCH{lc $src->{nick}};
delete $LYNCH{lc $src->{nick}}; delete $LYNCH{lc $src->{nick}};
} }
while (my ($accu, $ser) = each %LYNCH) { foreach my $accu (keys %LYNCH) {
if ($ser eq lc $src->{nick}) { my %sers = %{$LYNCH{$accu}};
$LYNCH{$accu}{$new} = 1; foreach my $ser (keys %sers) {
delete $LYNCH{$accu}{$ser}; if ($ser eq lc $src->{nick}) {
$LYNCH{$accu}{$new} = 1;
delete $LYNCH{$accu}{$ser};
}
} }
} }
# That should be everything. # That should be everything.
@@ -1582,7 +1710,7 @@ sub on_rehash {
} }
# Start initialization. # Start initialization.
API::Std::mod_init('Werewolf', 'Xelhua', '1.03', '3.0.0a10'); API::Std::mod_init('Werewolf', 'Xelhua', '1.07', '3.0.0a11');
# build: perl=5.010000 # build: perl=5.010000
__END__ __END__
@@ -1593,7 +1721,7 @@ Werewolf - IRC version of the Werewolf detective/social party game
=head1 VERSION =head1 VERSION
1.03 1.07
=head1 SYNOPSIS =head1 SYNOPSIS
@@ -1625,7 +1753,7 @@ Internet Relay Chat.
It, obviously, is a complete module for Auto, and has absolutely no extra It, obviously, is a complete module for Auto, and has absolutely no extra
dependencies. dependencies.
It includes a whopping eight player roles, four of which are optional. See the It includes a whopping nine player roles, five of which are optional. See the
ROLES section for more information on them. ROLES section for more information on them.
If you want the best out of Werewolf, please be sure to read over CONFIGURATION. If you want the best out of Werewolf, please be sure to read over CONFIGURATION.
@@ -1649,13 +1777,13 @@ and use aliases.
Here is a list of channel commands: Here is a list of channel commands:
WOLF JOIN|J - Start/Join a game. WOLF JOIN|J - Start/Join a game.
WOLF WAIT|W - Increases join wait time by 20 seconds.
WOLF START - Start the game play. WOLF START - Start the game play.
WOLF LYNCH|L - Cast vote for who to lynch. WOLF LYNCH|L - Cast vote for who to lynch.
WOLF RETRACT|R - Retract lynch vote. WOLF RETRACT|R - Retract lynch vote.
WOLF VOTES|V - Return current votes. WOLF VOTES|V - Return current votes.
WOLF SHOOT - Shoot someone with the gun. WOLF SHOOT - Shoot someone with the gun.
WOLF STATS|S - Return current player statistics. WOLF STATS|S - Return current player statistics.
WOLF KICK|K - Kick a player from the game.
WOLF QUIT|Q - Leave the game. WOLF QUIT|Q - Leave the game.
Here is a list of private commands: Here is a list of private commands:
@@ -1666,8 +1794,6 @@ Here is a list of private commands:
WOLF GUARD - Guard a player. WOLF GUARD - Guard a player.
WOLF ID - Investigate a player. WOLF ID - Investigate a player.
The WOLF KICK command requires the werewolf.admin privilege.
=head1 RULES =head1 RULES
Since the rules for this particular version of Werewolf differ from the Since the rules for this particular version of Werewolf differ from the
@@ -1686,7 +1812,6 @@ Typing "!wolf join" in a channel starts a game, and a 60 second timer. Others
can join the game with "!wolf join". "!wolf start" starts play. can join the game with "!wolf join". "!wolf start" starts play.
START will fail if the 60 second timer has not stopped and there is less than START will fail if the 60 second timer has not stopped and there is less than
the maximum amount of players. the maximum amount of players.
The bot moderates the channel (it voices all players). The bot moderates the channel (it voices all players).
@@ -1814,25 +1939,38 @@ off UP, not normal mathematical rounding.
=item Villager (gun holder) =item Villager (gun holder)
If a game has 6+ players, one villager (can also be seer/harlot/etc., but not If a game has 8+ players, one villager (can also be seer/harlot/etc., but not
wolves or traitors.), will be given a gun with a certain amount special silver wolves or traitors.), will be given a gun with a certain amount special silver
bullets. To be exact, <PLAYER COUNT> * .12 rounded off UP. bullets. To be exact, <PLAYER COUNT> * .12 rounded off UP.
During the day, (s)he can use "!wolf shoot <nick>" to shoot someone with that During the day, (s)he can use "!wolf shoot <nick>" to shoot someone with that
gun, and the effect varies widely. Lets go over those. gun, and the effect varies widely. Lets go over those.
* 1/5 chance - Miss. - Person misses. But at least they're confirmed safe, as * 1/7 chance - Miss. - Person misses. But at least they're confirmed safe, as
wolves and traitors don't get to have guns. wolves and traitors don't get to have guns.
* 1/5 chance - Unclean gun. - Gun explodes, in turn killing the shooter. Bummer! * 1/7 chance - Unclean gun. - Gun explodes, in turn killing the shooter. Bummer!
* 3/5 chance - Hit. - If it hits a wolf, they die instantly (and are revealed * 5/7 chance - Hit. - If it hits a wolf, they die instantly (and are revealed
to be a wolf.). If it hits a villager, 4/5 chance it'll just wound them and to be a wolf.). If it hits a villager, 4/5 chance it'll just wound them and
make them unable to vote for the day. 1/5 chance it kills them. Oops! make them unable to vote for the day. 1/5 chance it kills them. Oops!
So, obviously no matter what the case might be, the gun holder will always So, obviously no matter what the case might be, the gun holder will always
reveal the innocence of at least someone. reveal the innocence of at least someone.
=item Villager (drunk)
ATTENTION: Xelhua does NOT endorse drinking, especially underage, thus the
village drunk might be considered NSFW and can be disabled with
werewolf:rated-g. See CONFIGURATION.
If a game has 7+ players, one villager will be made the "drunk". Basically,
this is mostly just a name. But, if they also get the gun, there's extras:
* Person's bullet count gets tripled.
* Higher chance of missing when shooting.
=item Seer =item Seer
The seer is like a villager, but gets a special ability, the ability of The seer is like a villager, but gets a special ability, the ability of
@@ -1947,6 +2085,9 @@ AS SOON AS POSSIBLE.
A single traitor is assigned to a game if it has twelve or more players. A single traitor is assigned to a game if it has twelve or more players.
Oh and one more thing, if all wolves die yet the traitor remains, the traitor
is transformed into a wolf.
=item Detective =item Detective
NOTE: Some people think that detectives make the game less interesting, or even NOTE: Some people think that detectives make the game less interesting, or even
@@ -2002,6 +2143,8 @@ required. Also, it is case-sensitive.
*DEFINING* this configuration option will disable harlots (A.K.A. prostitutes), *DEFINING* this configuration option will disable harlots (A.K.A. prostitutes),
because you might consider them to be inappropriate for your target audience. because you might consider them to be inappropriate for your target audience.
It will also disable the village drunk, because they're also NSFW.
NOTE: Defining it disables harlots, regardless of the actual value. Remove it NOTE: Defining it disables harlots, regardless of the actual value. Remove it
to re-enable harlots. to re-enable harlots.
+373
View File
@@ -0,0 +1,373 @@
# Module: WerewolfAdmin. See below for documentation.
# Copyright (C) 2010-2011 Xelhua Development Group, et al.
# This program is free software; rights to this code are stated in doc/LICENSE.
package M::WerewolfAdmin;
use strict;
use warnings;
use feature qw(switch);
use API::Std qw(cmd_add cmd_del timer_add timer_del trans conf_get);
use API::IRC qw(privmsg notice cmode ison);
# Initialization subroutine.
sub _init {
# Create the WOLFA command.
cmd_add('WOLFA', 0, 'werewolf.admin', \%M::WerewolfAdmin::HELP_WOLFA, \&M::WerewolfAdmin::cmd_wolfa) or return;
# Success.
return 1;
}
# Void subroutine.
sub _void {
# Delete the WOLFA command.
cmd_del('WOLFA') or return;
# Success.
return 1;
}
# Help hash for the WOLFA command.
our %HELP_WOLFA = (
en => "This command allows you to perform various administrative actions in a game of Werewolf (A.K.A. Mafia). \2Syntax:\2 WOLFA (JOIN|WAIT|START|KICK|STOP) [parameters]",
);
# Callback for the WOLFA command.
sub cmd_wolfa {
my ($src, @argv) = @_;
# We require at least one parameter.
if (!defined $argv[0]) {
notice($src->{svr}, $src->{nick}, trans('Not enough parameters').q{.});
return;
}
# Iterate the parameter.
given (uc $argv[0]) {
when (/^(JOIN|J)$/) {
# WOLFA JOIN
# Requires an extra parameter.
if (!defined $argv[1]) {
notice($src->{svr}, $src->{nick}, trans('Not enough parameters').q{.});
return;
}
# Check if a game is running.
if (!$M::Werewolf::PGAME and !$M::Werewolf::GAME) {
notice($src->{svr}, $src->{nick}, 'No game is currently running.');
}
elsif ($M::Werewolf::GAME) {
notice($src->{svr}, $src->{nick}, 'Sorry, but the game is already running. Try again next time.');
}
else {
# Check if this is the game channel.
if ($src->{svr}.'/'.$src->{chan} ne $M::Werewolf::GAMECHAN) {
notice($src->{svr}, $src->{nick}, "Werewolf is currently running in \2$M::Werewolf::GAMECHAN\2.");
return;
}
# Check if this user exists in channel.
if (!ison($src->{svr}, $src->{chan}, lc $argv[1])) {
notice($src->{svr}, $src->{nick}, "No such user \2$argv[1]\2 is on the channel.");
return;
}
# Make sure they're not already playing.
if (exists $M::Werewolf::PLAYERS{lc $argv[1]}) {
notice($src->{svr}, $src->{nick}, 'They\'re already playing!');
return;
}
# Set variables.
$M::Werewolf::PLAYERS{lc $argv[1]} = 0;
my $nick = $M::Werewolf::NICKS{lc $argv[1]} = $Core::IRC::Users::users{$src->{svr}}{lc $argv[1]};
# Send message.
my ($gsvr, $gchan) = split '/', $M::Werewolf::GAMECHAN, 2;
cmode($gsvr, $gchan, "+v $nick");
privmsg($gsvr, $gchan, "\2$nick\2 was forced to join the game by \2$src->{nick}\2.");
}
}
when (/^(WAIT|W)$/) {
# WOLFA WAIT
# Check if a game is running.
if (!$M::Werewolf::PGAME) {
if (!$M::Werewolf::GAME) {
notice($src->{svr}, $src->{nick}, 'No game is currently running.');
return;
}
else {
notice($src->{svr}, $src->{nick}, 'Werewolf is already in play.');
return;
}
}
# Check if this is the game channel.
if ($src->{svr}.'/'.$src->{chan} ne $M::Werewolf::GAMECHAN) {
notice($src->{svr}, $src->{nick}, "Werewolf is currently running in \2$M::Werewolf::GAMECHAN\2.");
return;
}
# Increase WAIT.
$M::Werewolf::WAIT += 20;
# And WAITED.
$M::Werewolf::WAITED++;
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 forcibly increased join wait time by 20 seconds.");
}
when ('START') {
# WOLFA START
# Check if a game is running.
if (!$M::Werewolf::PGAME) {
if (!$M::Werewolf::GAME) {
notice($src->{svr}, $src->{nick}, 'No game is currently running.');
return;
}
else {
notice($src->{svr}, $src->{nick}, 'Werewolf is already in play.');
return;
}
}
# Check if this is the game channel.
if ($src->{svr}.'/'.$src->{chan} ne $M::Werewolf::GAMECHAN) {
notice($src->{svr}, $src->{nick}, "Werewolf is currently running in \2$M::Werewolf::GAMECHAN\2.");
return;
}
# Need four or more players.
if (keys %M::Werewolf::PLAYERS < 4) {
privmsg($src->{svr}, $src->{chan}, "$src->{nick}: Four or more players are required to play.");
return;
}
# First, determine how many players to declare a wolf.
my $cwolves = POSIX::ceil(keys(%M::Werewolf::PLAYERS) * .14);
# Only one seer, harlot, guardian angel, traitor and detective.
my $cseers = 1;
my $charlots = my $cdrunks = my $cangels = my $ctraitors = my $cdetectives = 0;
if (keys %M::Werewolf::PLAYERS >= 6) { $charlots++ unless conf_get('werewolf:rated-g') }
if (keys %M::Werewolf::PLAYERS >= 7) { $cdrunks++ unless conf_get('werewolf:rated-g') }
if (keys %M::Werewolf::PLAYERS >= 9) { $cangels++ unless conf_get('werewolf:no-angels') }
if (keys %M::Werewolf::PLAYERS >= 12 and conf_get('werewolf:traitors')) { $ctraitors++ }
if (keys %M::Werewolf::PLAYERS >= 16 and conf_get('werewolf:detectives')) { $cdetectives++ }
# Give all players a role.
foreach my $plyr (keys %M::Werewolf::PLAYERS) { $M::Werewolf::PLAYERS{$plyr} = 'v' }
# Push players into a temporary array.
my @plyrs = keys %M::Werewolf::PLAYERS;
# Set wolves.
while ($cwolves > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($M::Werewolf::PLAYERS{$rpi} !~ m/^(w|s|g|h|d|t)$/xsm) {
$M::Werewolf::PLAYERS{$rpi} = 'w';
$cwolves--;
$M::Werewolf::STATIC[0] .= ", \2$M::Werewolf::NICKS{$rpi}\2";
}
}
$M::Werewolf::STATIC[0] = substr $M::Werewolf::STATIC[0], 2;
# Set seers.
while ($cseers > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($M::Werewolf::PLAYERS{$rpi} !~ m/^(w|g|h|d|t)$/xsm) {
$M::Werewolf::PLAYERS{$rpi} = 's';
$cseers--;
$M::Werewolf::STATIC[1] = "\2$M::Werewolf::NICKS{$rpi}\2";
}
}
# Set harlots.
while ($charlots > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($M::Werewolf::PLAYERS{$rpi} !~ m/^(w|g|s|d|t)$/xsm) {
$M::Werewolf::PLAYERS{$rpi} = 'h';
$charlots--;
$M::Werewolf::STATIC[2] = "\2$M::Werewolf::NICKS{$rpi}\2";
}
}
# Set drunks.
while ($cdrunks > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($M::Werewolf::PLAYERS{$rpi} =~ m/v/xsm) {
$M::Werewolf::PLAYERS{$rpi} = 'vi';
$cdrunks--;
}
}
# Set guardian angels.
while ($cangels > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($M::Werewolf::PLAYERS{$rpi} !~ m/^(w|h|s|d|t)$/xsm) {
$M::Werewolf::PLAYERS{$rpi} = 'g';
$cangels--;
$M::Werewolf::STATIC[3] = "\2$M::Werewolf::NICKS{$rpi}\2";
}
}
# Set traitors.
while ($ctraitors > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($M::Werewolf::PLAYERS{$rpi} !~ m/^(w|h|s|d|g)$/xsm) {
$M::Werewolf::PLAYERS{$rpi} = 't';
$ctraitors--;
$M::Werewolf::STATIC[4] = "\2$M::Werewolf::NICKS{$rpi}\2";
}
}
# Set detectives.
while ($cdetectives > 0) {
my $rpi = $plyrs[int rand scalar @plyrs];
if ($M::Werewolf::PLAYERS{$rpi} !~ m/^(w|h|s|g|t)$/xsm) {
$M::Werewolf::PLAYERS{$rpi} = 'd';
$cdetectives--;
$M::Werewolf::STATIC[5] = "\2$M::Werewolf::NICKS{$rpi}\2";
}
}
# If there's 8 or more players, give one of them a gun.
if (keys %M::Werewolf::PLAYERS >= 8) {
my $rpi = $plyrs[int rand scalar @plyrs];
while ($M::Werewolf::PLAYERS{$rpi} =~ m/w/xsm || $M::Werewolf::PLAYERS{$rpi} =~ m/t/xsm) { $rpi = $plyrs[int rand scalar @plyrs] }
$M::Werewolf::PLAYERS{$rpi} .= 'b';
# And give them PLAYER COUNT * .12 bullets rounded up.
$M::Werewolf::BULLETS = POSIX::ceil(keys(%M::Werewolf::PLAYERS) * .12);
if ($M::Werewolf::PLAYERS{$rpi} =~ m/i/xsm) { $M::Werewolf::BULLETS = $M::Werewolf::BULLETS * 3 }
}
# Set variables.
$M::Werewolf::GAME = 1;
$M::Werewolf::PGAME = 0;
# Set spoke variables.
foreach (keys %M::Werewolf::PLAYERS) { $M::Werewolf::SPOKE{$_} = time }
# All players have their role, so lets begin the game!
my ($gsvr, $gchan) = split '/', $M::Werewolf::GAMECHAN, 2;
privmsg($gsvr, $gchan, "Game is now starting. (forced start by \2$src->{nick}\2)");
cmode($gsvr, $gchan, '+m');
# Delete waiting timer.
timer_del('werewolf.joinwait');
# Start timer for bed checking.
timer_add('werewolf.chkbed', 2, 5, \&M::Werewolf::_chkbed);
# Initialize the nighttime.
M::Werewolf::_init_night();
}
when (/^(KICK|K)$/) {
# WOLFA KICK
# Check if a game is running.
if (!$M::Werewolf::GAME and !$M::Werewolf::PGAME) {
notice($src->{svr}, $src->{nick}, 'No game is currently running.');
return;
}
# Check if this is the game channel.
if ($src->{svr}.'/'.$src->{chan} ne $M::Werewolf::GAMECHAN) {
notice($src->{svr}, $src->{nick}, "Werewolf is currently running in \2$M::Werewolf::GAMECHAN\2.");
return;
}
# Requires an extra parameter.
if (!defined $argv[1]) {
notice($src->{svr}, $src->{nick}, trans('Not enough parameters').q{.});
return;
}
# Check if the target is playing.
if (!exists $M::Werewolf::PLAYERS{lc $argv[1]}) {
notice($src->{svr}, $src->{nick}, "\2$argv[1]\2 is not currently playing.");
return;
}
# Kill the target.
privmsg($src->{svr}, $src->{chan}, "\2$argv[1]\2 died of an unknown disease. He/She was a \2".M::Werewolf::_getrole(lc $argv[1], 2)."\2.");
M::Werewolf::_player_del(lc $argv[1]);
}
when ('STOP') {
# WOLFA STOP
# Check if a game is running.
if (!$M::Werewolf::GAME and !$M::Werewolf::PGAME) {
notice($src->{svr}, $src->{nick}, 'No game is currently running.');
return;
}
# Check if this is the game channel.
if ($src->{svr}.'/'.$src->{chan} ne $M::Werewolf::GAMECHAN) {
notice($src->{svr}, $src->{nick}, "Werewolf is currently running in \2$M::Werewolf::GAMECHAN\2.");
return;
}
# End the game.
my ($gsvr, $gchan) = split '/', $M::Werewolf::GAMECHAN, 2;
privmsg($gsvr, $gchan, "\2$src->{nick}\2 is forcing the game to end...");
M::Werewolf::_gameover('n');
}
default { notice($src->{svr}, $src->{nick}, trans('Unknown action', $_).q{.}) }
}
return 1;
}
# Start initialization.
API::Std::mod_init('WerewolfAdmin', 'Xelhua', '1.00', '3.0.0a11');
# build: perl=5.010000
__END__
=head1 NAME
WerewolfAdmin - Administrative functions for Werewolf
=head1 VERSION
1.00
=head1 SYNOPSIS
None
=head1 DESCRIPTION
This module allows one to administer the Werewolf IRC game, provided by the
Werewolf module.
It provides the following commands:
WOLFA JOIN|J - Force join.
WOLFA WAIT - Force wait.
WOLFA START - Force start.
WOLFA KICK|K - Kick a player.
WOLFA STOP - Stop a game forcibly.
And requires the werewolf.admin privilege.
=head1 DEPENDENCIES
This module depends on the following Auto module(s):
=over
=item Werewolf
The Werewolf module provides the game that this module provides administrative
commands for. Using this module without Werewolf will likely cause a fatal
error.
=back
=head1 AUTHOR
This module was written by Elijah Perrault.
This module is maintained by Xelhua Development Group.
=head1 LICENSE AND COPYRIGHT
This module is Copyright (C) 2010-2011, Xelhua Development Group.
This module is released under the same terms as Auto itself.
=cut
# vim: set ai et ts=4 sw=4: