Werewolf: Handful of bugs fixed, timeouts rewritten, wolf assignment rewritten. (see ROLES:Werewolf)

This commit is contained in:
Elijah Perrault committed 2011-04-10 21:34:20 -06:00
1 parent fe353984c2
commit 38015434e1
2 files changed
+78 -81

No files matched your search

+2
View File
@@ -3,6 +3,8 @@ Auto IRC Bot 3.0: Change Log
3.0 Indev 3.0 Indev
=============================================================================== ===============================================================================
* Werewolf: Handful of bugs fixed, timeouts rewritten, wolf assignment
rewritten. (see ROLES:Werewolf)
* Werewolf: Fixed an annoyance in VOTES. * Werewolf: Fixed an annoyance in VOTES.
* Werewolf: Fixed another round of bugs. * Werewolf: Fixed another round of bugs.
* Werewolf: Fixed a grammatical error. Thanks TAD! * Werewolf: Fixed a grammatical error. Thanks TAD!
+76 -81
View File
@@ -7,8 +7,7 @@ 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, %BED, $LVOTEN, $SHOT, $DETECTED); my ($GAME, $PGAME, $GAMECHAN, $GAMETIME, %PLAYERS, %NICKS, @STATIC, $PHASE, $SEEN, $VISIT, $GUARD, %KILL, %WKILL, %LYNCH, %SPOKE, $LVOTEN, $SHOT, $DETECTED);
our $WAIT;
my $FCHAR = (conf_get('fantasy_pf'))[0][0]; my $FCHAR = (conf_get('fantasy_pf'))[0][0];
# Initialization subroutine. # Initialization subroutine.
@@ -55,6 +54,9 @@ sub _void {
# Delete the on_rehash hook. # Delete the on_rehash hook.
hook_del('on_rehash', 'werewolf.rehash') or return; hook_del('on_rehash', 'werewolf.rehash') or return;
# If a game is running, end it!
if ($GAME or $PGAME) { _gameover('n') }
# Success. # Success.
return 1; return 1;
} }
@@ -112,10 +114,6 @@ sub cmd_wolf {
$NICKS{lc $src->{nick}} = $src->{nick}; $NICKS{lc $src->{nick}} = $src->{nick};
$GAMETIME = time; $GAMETIME = time;
# Set waiting time.
$WAIT = 1;
timer_add('werewolf.join_wait', 1, 60, sub { $M::Werewolf::WAIT = 0 });
# 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.');
@@ -180,7 +178,7 @@ sub cmd_wolf {
} }
# Check join timeout. # Check join timeout.
if ($WAIT and keys %PLAYERS != 30) { if ((time - $GAMETIME) < 60) {
my $time = time - $GAMETIME; my $time = time - $GAMETIME;
$time = 60 - $time; $time = 60 - $time;
privmsg($src->{svr}, $src->{chan}, "$src->{nick}: Please wait at least \2$time\2 more seconds."); privmsg($src->{svr}, $src->{chan}, "$src->{nick}: Please wait at least \2$time\2 more seconds.");
@@ -194,13 +192,7 @@ sub cmd_wolf {
} }
# First, determine how many players to declare a wolf. # First, determine how many players to declare a wolf.
my $cwolves; my $cwolves = POSIX::ceil(keys(%PLAYERS) * .15);
if (keys %PLAYERS >= 4) { $cwolves++ }
if (keys %PLAYERS >= 9) { $cwolves++ }
if (keys %PLAYERS >= 15) { $cwolves++ }
if (keys %PLAYERS >= 21) { $cwolves++ }
if (keys %PLAYERS >= 25) { $cwolves++ }
if (keys %PLAYERS == 30) { $cwolves++ }
# 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 $cangels = my $ctraitors = my $cdetectives = 0;
@@ -281,13 +273,15 @@ sub cmd_wolf {
$GAME = 1; $GAME = 1;
$PGAME = 0; $PGAME = 0;
# Set bed variables. # Set spoke variables.
foreach (keys %PLAYERS) { $BED{$_} = 0 } foreach (keys %PLAYERS) { $SPOKE{$_} = time }
# All players have their role, so lets begin the game! # All players have their role, so lets begin the game!
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');
# Start timer for bed checking.
timer_add('werewolf.chkbed', 2, 5, \&M::Werewolf::_chkbed);
# Initialize the nighttime. # Initialize the nighttime.
_init_night(); _init_night();
} }
@@ -428,11 +422,12 @@ sub cmd_wolf {
if (keys %LYNCH) { if (keys %LYNCH) {
my $str; my $str;
foreach my $key (sort {keys %{$LYNCH{$b}} <=> keys %{$LYNCH{$a}}} keys %LYNCH) { foreach my $key (sort {keys %{$LYNCH{$b}} <=> keys %{$LYNCH{$a}}} keys %LYNCH) {
my $voters = 0; my $voters;
if (keys %{$LYNCH{$key}}) { if (keys %{$LYNCH{$key}}) {
foreach (keys %{$LYNCH{$key}}) { $voters .= " $NICKS{$_}" } foreach (keys %{$LYNCH{$key}}) { $voters .= " $NICKS{$_}" }
} }
$voters =~ s/^\s//xsm; if ($voters) { $voters =~ s/^\s//xsm }
else { $voters = 0 }
$str .= ", $NICKS{$key}: ".keys(%{$LYNCH{$key}})." ($voters)"; $str .= ", $NICKS{$key}: ".keys(%{$LYNCH{$key}})." ($voters)";
} }
$str = substr $str, 2; $str = substr $str, 2;
@@ -496,7 +491,16 @@ sub cmd_wolf {
# Massive randomizing here. 5 = 3-kill, 1-miss, 1-suicide # Massive randomizing here. 5 = 3-kill, 1-miss, 1-suicide
my $myr = int rand 6; my $myr = int rand 6;
given ($myr) { given ($myr) {
when (/^[1-3]$/) { # It's a hit. when (4) { # It's a miss.
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 is a lousy shooter. He/She missed!");
}
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!");
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});
return 1;
}
default { # It's a hit.
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 shot \2$real\2 with a silver bullet!"); privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 shot \2$real\2 with a silver bullet!");
# Check if the target is a wolf or a villager. # Check if the target is a wolf or a villager.
@@ -508,7 +512,13 @@ sub cmd_wolf {
# So, there's a 1/5 chance of a villager dying. # So, there's a 1/5 chance of a villager dying.
my $rint = int rand 6; my $rint = int rand 6;
given ($rint) { given ($rint) {
when (/^[1-4]$/) { # Only hurt. when (5) { # Killed.
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.");
if (_getrole(lc $real, 2) ne 'villager') { privmsg($src->{svr}, $src->{chan}, "Appears s(he) was a \2"._getrole(lc $real, 2)."\2."); }
# 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."); privmsg($src->{svr}, $src->{chan}, "\2$real\2 is a villager, and is hurt but will have a full recovery.");
$SHOT = lc $real; $SHOT = lc $real;
# Delete any votes they might've made today. # Delete any votes they might've made today.
@@ -517,24 +527,9 @@ sub cmd_wolf {
} }
$LVOTEN--; $LVOTEN--;
} }
when (5) { # Killed.
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.");
if (_getrole(lc $real, 2) ne 'villager') { privmsg($src->{svr}, $src->{chan}, "Appears s(he) was a \2"._getrole(lc $real, 2)."\2."); }
# Kill them.
_player_del(lc $real);
}
} }
} }
} }
when (4) { # It's a miss.
privmsg($src->{svr}, $src->{chan}, "\2$src->{nick}\2 is a lousy shooter. He/She missed!");
}
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!");
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});
return 1;
}
} }
# Remove the gun from them. # Remove the gun from them.
$PLAYERS{lc $src->{nick}} =~ s/b//gxsm; $PLAYERS{lc $src->{nick}} =~ s/b//gxsm;
@@ -1090,6 +1085,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 $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 The body of a young penguin pet is found. All villagers however, have survived.") }
elsif ($victim eq 1) { elsif ($victim eq 1) {
@@ -1097,13 +1093,13 @@ sub _init_day {
} }
else { else {
privmsg($gsvr, $gchan, "$msg The dead body of \2$NICKS{$victim}\2, a \2"._getrole($victim, 2)."\2, is found. Those remaining mourn his/her death."); privmsg($gsvr, $gchan, "$msg The dead body of \2$NICKS{$victim}\2, a \2"._getrole($victim, 2)."\2, is found. Those remaining mourn his/her death.");
_player_del($victim); $continue = _player_del($victim);
if ($harlotd == 1) { if ($harlotd == 1) {
my $harlot; my $harlot;
while (my ($cuser, $crole) = each %PLAYERS) { if ($crole =~ m/h/xsm) { $harlot = $cuser } } while (my ($cuser, $crole) = each %PLAYERS) { if ($crole =~ m/h/xsm) { $harlot = $cuser } }
if ($harlot) { # Unusual cases call for this. if ($harlot) { # Unusual cases call for this.
privmsg($gsvr, $gchan, "\2$NICKS{$harlot}\2, the village harlot, made the unfortunate mistake of visiting the victim last night, and is now dead."); privmsg($gsvr, $gchan, "\2$NICKS{$harlot}\2, the village harlot, made the unfortunate mistake of visiting the victim last night, and is now dead.");
_player_del($harlot); $continue = _player_del($harlot);
} }
} }
} }
@@ -1113,7 +1109,7 @@ sub _init_day {
while (my ($cuser, $crole) = each %PLAYERS) { if ($crole =~ m/h/xsm) { $harlot = $cuser } } while (my ($cuser, $crole) = each %PLAYERS) { if ($crole =~ m/h/xsm) { $harlot = $cuser } }
if ($harlot) { # Unusual cases call for this. if ($harlot) { # Unusual cases call for this.
privmsg($gsvr, $gchan, "\2$NICKS{$harlot}\2, the village harlot, made the unfortunate mistake of visiting a wolf last night, and is now dead."); privmsg($gsvr, $gchan, "\2$NICKS{$harlot}\2, the village harlot, made the unfortunate mistake of visiting a wolf last night, and is now dead.");
_player_del($harlot); $continue = _player_del($harlot);
} }
} }
# Check if the angel guarded a wolf. # Check if the angel guarded a wolf.
@@ -1122,10 +1118,13 @@ sub _init_day {
while (my ($cuser, $crole) = each %PLAYERS) { if ($crole =~ m/g/xsm) { $angel = $cuser } } while (my ($cuser, $crole) = each %PLAYERS) { if ($crole =~ m/g/xsm) { $angel = $cuser } }
if ($angel) { # Unusual cases call for this. if ($angel) { # Unusual cases call for this.
privmsg($gsvr, $gchan, "\2$NICKS{$angel}\2, the guardian angel, made the unfortunate mistake of guarding a wolf last night, attempted to escape, but failed and is now dead."); privmsg($gsvr, $gchan, "\2$NICKS{$angel}\2, the guardian angel, made the unfortunate mistake of guarding a wolf last night, attempted to escape, but failed and is now dead.");
_player_del($angel); $continue = _player_del($angel);
} }
} }
# If there was a winning condition, don't initialize daytime.
if (!$continue) { return 1 }
# Set number of votes required to lynch. # Set number of votes required to lynch.
$LVOTEN = int(scalar(keys(%PLAYERS)) / 2); $LVOTEN = int(scalar(keys(%PLAYERS)) / 2);
$LVOTEN++; $LVOTEN++;
@@ -1190,34 +1189,36 @@ sub _judgment {
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, "The villagers, after much debate, finally decide on lynching \2$NICKS{$nick}\2, who turned out to be... a \2"._getrole($nick, 2)."\2.");
my $ri = _player_del($nick); my $ri = _player_del($nick);
if ($ri) { # Initialize nighttime.
my @warn; if ($ri) { _init_night() }
# Check if any players failed to vote.
foreach my $plyr (keys %PLAYERS) { return 1;
my $bi; }
foreach my $acpl (keys %LYNCH) {
if (exists $LYNCH{$acpl}{$plyr}) { $bi = 1 } # Subroutine for checking who is in bed and who is not.
} sub _chkbed {
if (!$bi) { my ($gsvr, $gchan) = split '/', $GAMECHAN, 2;
# This player in particular didn't vote today, increase their bed variable. # Array for warnings.
# Also check if they should be kicked from the game (2 days without voting). my @warn;
if (++$BED{$plyr} >= 2) { # Iterate through all SPOKE players.
privmsg($gsvr, $gchan, "\2$NICKS{$plyr}\2 didn't get out of bed for two days. He/She is declared dead. Appears (s)he was a \2"._getrole($plyr, 2)."\2."); while (my ($plyr, $time) = each %SPOKE) {
$ri = _player_del($plyr); my $since = time - $time;
last unless $ri; # Check if they should be kicked right now.
} if ($since >= 300) {
else { # They didn't vote for today only. Just give them a friendly warning. privmsg($gsvr, $gchan, "\2$NICKS{$plyr}\2 didn't get out of bed for a very long time. He/She is declared dead. Appears (s)he was a \2"._getrole($plyr, 2)."\2.");
push @warn, $NICKS{$plyr}; my $ri = _player_del($plyr);
} if (!$ri) { last }
}
} }
if ($ri and scalar @warn) { # Perhaps they should just get a warning.
privmsg($gsvr, , join(' ', @warn).': You didn\'t vote today. Please remember to say something in the channel soon or you might be declared dead.') elsif ($since >= 180) {
push @warn, $plyr;
} }
} }
# Initialize nighttime. # Send out any warnings.
if ($ri) { _init_night() } 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.')
}
return 1; return 1;
} }
@@ -1260,7 +1261,7 @@ sub _player_del {
# Delete variables. # Delete variables.
delete $PLAYERS{$player}; delete $PLAYERS{$player};
delete $NICKS{$player}; delete $NICKS{$player};
delete $BED{$player}; delete $SPOKE{$player};
if (exists $KILL{$player}) { delete $KILL{$player} } if (exists $KILL{$player}) { delete $KILL{$player} }
foreach my $acpl (keys %LYNCH) { foreach my $acpl (keys %LYNCH) {
if (exists $LYNCH{$acpl}{$player}) { delete $LYNCH{$acpl}{$player} } if (exists $LYNCH{$acpl}{$player}) { delete $LYNCH{$acpl}{$player} }
@@ -1352,14 +1353,14 @@ 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') } }
if ($PGAME) { timer_del('werewolf.join_wait') } timer_del('werewolf.chkbed');
$GAME = $PGAME = $GAMECHAN = $GAMETIME = $WAIT = $PHASE = $SEEN = $VISIT = $GUARD = $LVOTEN = $SHOT = $DETECTED = 0; $GAME = $PGAME = $GAMECHAN = $GAMETIME = $PHASE = $SEEN = $VISIT = $GUARD = $LVOTEN = $SHOT = $DETECTED = 0;
%PLAYERS = (); %PLAYERS = ();
%NICKS = (); %NICKS = ();
%KILL = (); %KILL = ();
%WKILL = (); %WKILL = ();
%LYNCH = (); %LYNCH = ();
%BED = (); %SPOKE = ();
@STATIC = (); @STATIC = ();
return 1; return 1;
@@ -1375,8 +1376,8 @@ sub on_cprivmsg {
if (lc $src->{svr}.'/'.$chan eq lc $GAMECHAN) { if (lc $src->{svr}.'/'.$chan eq lc $GAMECHAN) {
# Check if this person is playing. # Check if this person is playing.
if (exists $PLAYERS{lc $src->{nick}}) { if (exists $PLAYERS{lc $src->{nick}}) {
# Reset their bed variable to 0. # Set their spoke variable to current time.
$BED{lc $src->{nick}} = 0; $SPOKE{lc $src->{nick}} = time;
} }
} }
} }
@@ -1428,10 +1429,10 @@ sub on_nick {
# Hopefully this will work right, but if it doesn't, someone please make a bug report. # Hopefully this will work right, but if it doesn't, someone please make a bug report.
$PLAYERS{$new} = $PLAYERS{lc $src->{nick}}; $PLAYERS{$new} = $PLAYERS{lc $src->{nick}};
$NICKS{$new} = $newnick; $NICKS{$new} = $newnick;
$BED{$new} = $BED{lc $src->{nick}}; $SPOKE{$new} = $SPOKE{lc $src->{nick}};
delete $PLAYERS{lc $src->{nick}}; delete $PLAYERS{lc $src->{nick}};
delete $NICKS{lc $src->{nick}}; delete $NICKS{lc $src->{nick}};
delete $BED{lc $src->{nick}}; delete $SPOKE{lc $src->{nick}};
if ($SHOT) { if ($SHOT eq lc $src->{nick}) { $SHOT = $new } } if ($SHOT) { if ($SHOT eq lc $src->{nick}) { $SHOT = $new } }
if ($GUARD) { if ($GUARD eq lc $src->{nick}) { $GUARD = $new } } if ($GUARD) { if ($GUARD eq lc $src->{nick}) { $GUARD = $new } }
if ($VISIT) { if ($VISIT eq lc $src->{nick}) { $VISIT = $new } } if ($VISIT) { if ($VISIT eq lc $src->{nick}) { $VISIT = $new } }
@@ -1532,7 +1533,7 @@ sub on_rehash {
} }
# Start initialization. # Start initialization.
API::Std::mod_init('Werewolf', 'Xelhua', '1.01', '3.0.0a10'); API::Std::mod_init('Werewolf', 'Xelhua', '1.02', '3.0.0a10');
# build: perl=5.010000 # build: perl=5.010000
__END__ __END__
@@ -1543,7 +1544,7 @@ Werewolf - IRC version of the Werewolf detective/social party game
=head1 VERSION =head1 VERSION
1.01 1.02
=head1 SYNOPSIS =head1 SYNOPSIS
@@ -1759,14 +1760,8 @@ During the day, the wolves at all costs (even if it means ratting out their own)
make the villagers believe they are innocent. You need to be clever in order to make the villagers believe they are innocent. You need to be clever in order to
survive. survive.
Werewolves are assigned as follows: This is the math formula of the werewolf count: <PLAYER COUNT> * .15 rounded
off UP, not normal mathematical rounding.
4-8 players One werewolf.
9-14 players Two werewolves.
15-20 players Three werewolves.
21-24 players Four werewolves.
25-29 players Five werewolves.
30 players Six werewolves.
=item Villager (gun holder) =item Villager (gun holder)