Initial commit 0.001
authorMarius Gavrilescu <marius@ieval.ro>
Mon, 26 Aug 2013 20:13:06 +0000 (23:13 +0300)
committerMarius Gavrilescu <marius@ieval.ro>
Mon, 26 Aug 2013 20:13:06 +0000 (23:13 +0300)
17 files changed:
Changes [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
lib/Mafia.pm [new file with mode: 0644]
t/00-use.t [new file with mode: 0644]
t/examples.t [new file with mode: 0644]
t/examples/Newbie-0001.out [new file with mode: 0644]
t/examples/Newbie-0001.pl [new file with mode: 0644]
t/examples/Newbie-0002.out [new file with mode: 0644]
t/examples/Newbie-0002.pl [new file with mode: 0644]
t/examples/Newbie-0003.out [new file with mode: 0644]
t/examples/Newbie-0003.pl [new file with mode: 0644]
t/examples/Newbie-0004.out [new file with mode: 0644]
t/examples/Newbie-0004.pl [new file with mode: 0644]
t/examples/Newbie-0005.out [new file with mode: 0644]
t/examples/Newbie-0005.pl [new file with mode: 0644]

diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..4ecf2c3
--- /dev/null
+++ b/Changes
@@ -0,0 +1,4 @@
+Revision history for Perl extension Mafia.
+
+0.001 Mon 26 Aug 23:07:19 EEST 2013
+       - Initial release
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..10b7764
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,17 @@
+Changes
+Makefile.PL
+MANIFEST
+README
+t/00-use.t
+t/examples.t
+t/examples/Newbie-0005.out
+t/examples/Newbie-0003.pl
+t/examples/Newbie-0001.out
+t/examples/Newbie-0004.pl
+t/examples/Newbie-0003.out
+t/examples/Newbie-0001.pl
+t/examples/Newbie-0004.out
+t/examples/Newbie-0002.pl
+t/examples/Newbie-0005.pl
+t/examples/Newbie-0002.out
+lib/Mafia.pm
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..ebf1e0c
--- /dev/null
@@ -0,0 +1,26 @@
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    NAME              => 'Mafia',
+    VERSION_FROM      => 'lib/Mafia.pm',
+       ABSTRACT_FROM     => 'lib/Mafia.pm',
+       AUTHOR            => 'Marius Gavrilescu <marius@ieval.ro>',
+       MIN_PERL_VERSION  => '5.14.0',
+       LICENSE           => 'perl',
+    PREREQ_PM         => {
+         Storable => 0,
+       },
+       BUILD_REQUIRES => {
+         File::Basename => 0,
+         File::Slurp => 0,
+       },
+       META_ADD => {
+         resources => {
+               repository => {
+                 url => 'http://git.ieval.ro/git/mafia.git',
+                 web => 'http://git.ieval.ro/?p=mafia.git',
+                 type => 'git',
+               }
+         }
+       }
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..7af06e0
--- /dev/null
+++ b/README
@@ -0,0 +1,27 @@
+Mafia version 0.001
+===================
+
+Mafia.pm is a Perl extension for easily moderating Mafia games.
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+* File::Slurp (only for testing)
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2013 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.14.2 or,
+at your option, any later version of Perl 5 you may have available.
diff --git a/lib/Mafia.pm b/lib/Mafia.pm
new file mode 100644 (file)
index 0000000..e984481
--- /dev/null
@@ -0,0 +1,576 @@
+package Mafia;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+
+use constant;
+use Storable qw/dclone/;
+
+our $VERSION = '0.001';
+
+sub defconst { constant->import($_ => $_) for @_ }
+
+BEGIN {
+  # Roles
+  defconst qw/vanilla goon doctor vigilante roleblocker jailkeeper gunsmith tracker watcher bodyguard rolecop cop sk hider/;
+
+  # Factions
+  defconst qw/mafia town/;
+
+  # Extra traits
+  defconst qw/miller godfather weak macho bulletproof/;
+
+  # Messages
+  defconst qw/MSG_NIGHT MSG_DAY MSG_PLAYERS_ALIVE MSG_DEATH MSG_GUNCHECK MSG_NORESULT MSG_TRACK MSG_WATCH MSG_COP MSG_ROLECOP/;
+
+  # Action types
+  defconst qw/ACT_KILL ACT_LYNCH ACT_PROTECT ACT_GUARD ACT_ROLEBLOCK ACT_GUNCHECK ACT_TRACK ACT_WATCH ACT_ROLECOP ACT_COP ACT_TRACK_RESULT ACT_WATCH_RESULT ACT_HIDE/;
+}
+
+use constant +{
+  townie => town,
+  ROLE => [vanilla, goon, doctor, vigilante, roleblocker, jailkeeper, gunsmith, tracker, watcher, bodyguard, rolecop, cop, sk, hider],
+  FACTION => [mafia, town],
+  FLAG => [miller, godfather, weak, macho, bulletproof],
+  ACTION_ORDER => [ACT_HIDE, ACT_ROLEBLOCK, ACT_PROTECT, ACT_GUARD, ACT_GUNCHECK, ACT_ROLECOP, ACT_COP, ACT_TRACK, ACT_WATCH, ACT_KILL, ACT_LYNCH, ACT_TRACK_RESULT, ACT_WATCH_RESULT],
+  INVESTIGATIVE_ACTIONS => [ACT_GUNCHECK, ACT_TRACK, ACT_WATCH, ACT_ROLECOP, ACT_COP],
+  GUNROLES => [vigilante, gunsmith],
+};
+
+our @EXPORT = do {
+  no strict 'refs';
+  grep { $_ !~ [qw/import/] and exists &$_ } keys %{__PACKAGE__ . '::'};
+};
+
+################################################## Helper subs
+
+sub import {
+  strict->import;
+  goto &Exporter::import;
+}
+
+my (%players, %tplayers, @actions);
+my $daycnt = 0;
+my $nightcnt = 0;
+my $isday = 0;
+my $first = 1;
+
+sub clean{
+  %players = ();
+  %tplayers = ();
+  @actions = ();
+  $daycnt = 0;
+  $nightcnt = 0;
+  $isday = 0;
+  $first = 1;
+}
+
+sub uniq {
+  my %hash = map { $_ => 1 } @_;
+  keys %hash
+}
+
+sub phase {
+  return "Day $daycnt" if $isday;
+  return "Night $nightcnt" unless $isday;
+}
+
+sub rolename {
+  my %player = %{$players{$_[0]}};
+  my ($faction, $role) = ($player{faction}, $player{role});
+  if (defined $faction && $faction eq town && $role eq vanilla){
+       undef $faction;
+       $role = 'Vanilla Townie';
+  };
+  my @tokens = ();
+  push @tokens, ucfirst $faction if $faction;
+  for my $flag (@{FLAG()}) {
+       push @tokens, ucfirst $flag if $player{$flag}
+  }
+  push @tokens, ucfirst $role unless $role eq goon && $player{godfather};
+  "@tokens"
+}
+
+sub msg {
+  my ($type, @args) = @_;
+  given ($type){
+       when (MSG_NIGHT) {
+         my ($night) = @args;
+         say '' unless $first;
+         $first = 0;
+         say "It is Night $night";
+       }
+
+       when (MSG_DAY) {
+         my ($day) = @args;
+         say '' unless $first;
+         $first = 0;
+         say "It is Day $day";
+       }
+
+       when (MSG_PLAYERS_ALIVE) {
+         @args = sort @args;
+         say "Players alive: ", join ', ', @args
+       }
+
+       when (MSG_DEATH) {
+         my %args = @args;
+         my ($who, $reason) = @args{'target', 'reason'};
+         my $phase = phase;
+         my $rolename = rolename $who;
+         say "$who ($rolename) — $reason $phase";
+       }
+
+       when (MSG_GUNCHECK) {
+         my %args = @args;
+         my ($gunsmith, $who, $hasgun) = @args{'source', 'target', 'result'};
+         say "$gunsmith: $who has a gun" if $hasgun;
+         say "$gunsmith: $who does not have a gun" unless $hasgun;
+       }
+
+       when (MSG_NORESULT) {
+         my %args = @args;
+         my ($who) = $args{'source'};
+         say "$who: No result"
+       }
+
+       when (MSG_TRACK) {
+         my %args = @args;
+         my ($tracker, $who, $result) = @args{'source', 'target', 'result'};
+         my @result = @{$result};
+         local $, = ', ';
+         say "$tracker: $who did not visit anyone" unless scalar @result;
+         say "$tracker: $who visited: @result" if scalar @result;
+       }
+
+       when (MSG_WATCH) {
+         my %args = @args;
+         my ($watcher, $who, $result) = @args{'source', 'target', 'result'};
+         my @result = @{$result};
+         local $, = ', ';
+         say "$watcher: $who was not visited by anyone" unless scalar @result;
+         say "$watcher: $who was visited by: @result" if scalar @result;
+       }
+
+       when (MSG_ROLECOP) {
+         my %args = @args;
+         my ($rolecop, $who, $role) = @args{'source', 'target', 'result'};
+         say "$rolecop: $who\'s role is: $role"
+       }
+
+       when (MSG_COP) {
+         my %args = @args;
+         my ($cop, $who, $ismafia) = @args{'source', 'target', 'result'};
+         say "$cop: $who is mafia" if $ismafia;
+         say "$cop: $who is not mafia" unless $ismafia;
+       }
+  }
+}
+
+sub putaction {
+  my ($delay,  $type, %args) = @_;
+  $actions[$delay]->{$type} //= [];
+  if (exists $args{target} && exists $args{source} && $players{$args{target}}{faction} eq mafia && $players{$args{source}}{weak}) {
+       putaction($delay, ACT_KILL, target => $args{source}, reason => 'targeted scum');
+  }
+  push $actions[$delay]->{$type}, \%args
+}
+
+sub doaction {
+  my ($type, $args) = @_;
+  my %args = %$args;
+  my $source = $args{source};
+  my $target = $args{target};
+  if (defined $source && defined $target) {
+       # Watcher and tracker variables
+       $tplayers{$source}{targets} //= [];
+       push $tplayers{$source}{targets}, $target;
+       $tplayers{$target}{sources} //= [];
+       push $tplayers{$target}{sources}, $source;
+
+       # Copy this action to everybody hiding behind $target
+       if (exists $tplayers{$target}{hiders}) {
+         for my $target (@{$tplayers{$target}{hiders}}) {
+               my %args = %args;
+               $args{target} = $target;
+               $args{hidepierce} = 1;
+               doaction($type, \%args);
+         }
+       }
+
+       # Check if the action should be blocked
+       my $strongkill = $type eq ACT_KILL && $args{strong};
+       my $roleblocked = $tplayers{$source}{roleblocked};
+       my $hidden = $tplayers{$target}{hidden};
+       my $hidepierce = $args{hidepierce};
+       if ($source && (( $roleblocked && !$strongkill ) || ($hidden && !$hidepierce) )) {
+         msg MSG_NORESULT, %args if $type ~~ INVESTIGATIVE_ACTIONS;
+         return
+       }
+  }
+
+
+  given ($type) {
+       when(ACT_KILL) {
+         break if $tplayers{$target}{bulletproof} && defined $source;
+         if ($tplayers{$target}{guard_count} && defined $source) {
+               $tplayers{$target}{guard_count}--;
+               # Copy this action to the first guard
+               $args{target} = shift $tplayers{$target}{guards};
+               @_ = ($type, %args);
+               goto &doaction;
+         }
+         if ($tplayers{$target}{protection} && !$args{strong}) {
+               $tplayers{$target}{protection}--;
+               break
+         }
+         msg MSG_DEATH, %args;
+         delete $players{$target}
+       }
+
+       when(ACT_LYNCH){
+         if ($tplayers{$target}{guard_count}) {
+               $tplayers{$target}{guard_count}--;
+               $args{target} = shift $tplayers{$target}{guards};
+               $target=$args{target};
+         }
+         if ($tplayers{$target}{protection}) {
+               $tplayers{$target}{protection}--;
+               break
+         }
+         msg MSG_DEATH, %args, reason => 'lynched';
+         delete $players{$target}
+       }
+
+       when(ACT_PROTECT){
+         my $count = $args{count} // 1;
+         $tplayers{$target}{protection} += $count unless $tplayers{$target}{macho}
+       }
+
+       when(ACT_ROLEBLOCK){
+         $tplayers{$target}{roleblocked} = 1
+       }
+
+       when(ACT_GUNCHECK){
+         my $role = $players{$target}{role};
+         my $hasgun = $role ~~ GUNROLES || ($players{$target}{faction} eq mafia && $role ne doctor);
+         msg MSG_GUNCHECK, %args, result => $hasgun
+       }
+
+       when(ACT_TRACK_RESULT){
+         msg MSG_TRACK, %args, result => [ uniq @{$tplayers{$target}{targets} // []} ];
+       }
+
+       when(ACT_WATCH_RESULT){
+         msg MSG_WATCH, %args, result => [ uniq @{$tplayers{$target}{sources} // []} ];
+       }
+
+       when(ACT_GUARD){
+         $tplayers{$target}{guard_count}++;
+         $tplayers{$target}{guards} //= [];
+         push $tplayers{$target}{guards}, $source;
+       }
+
+       when(ACT_ROLECOP){
+         my $result = $players{$target}{role};
+         $result = vanilla if $result eq goon;
+         msg MSG_ROLECOP, %args, result => ucfirst $result
+       }
+
+       when(ACT_COP){
+         my $result = $players{$target}{faction} eq mafia;
+         $result = 1 if $players{$target}{miller};
+         $result = 0 if $players{$target}{godfather};
+         msg MSG_COP, %args, result => $result
+       }
+
+       when(ACT_HIDE){
+         $tplayers{$source}{hidden} = 1;
+         $tplayers{$target}{hiders} //= [];
+         push $tplayers{$target}{hiders}, $source
+       }
+  }
+}
+
+sub process_phase_change {
+  %tplayers = %{dclone \%players};
+  my $actions = shift @actions;
+  for my $type(@{ACTION_ORDER()}) {
+       doaction $type, $_ for @{$actions->{$type}}
+  }
+}
+
+################################################## User subs
+
+sub player {
+  my ($name, @args) = @_;
+  my %player;
+  for my $trait (@args) {
+       given ($trait) {
+         $player{role} = $trait when ROLE;
+         $player{faction} = $trait when FACTION;
+         $player{$trait} = 1 when FLAG;
+       }
+  }
+
+  $players{$name} = \%player;
+}
+
+sub day {
+  process_phase_change;
+  $isday = 1;
+  msg MSG_DAY, ++$daycnt;
+  msg MSG_PLAYERS_ALIVE, keys %players;
+}
+
+sub night {
+  process_phase_change;
+  $isday = 0;
+  msg MSG_NIGHT, ++$nightcnt;
+  msg MSG_PLAYERS_ALIVE, keys %players;
+}
+
+sub lynch {
+  my ($who) = @_;
+  putaction 0, ACT_LYNCH, target => $who;
+}
+
+sub factionkill {
+  my ($killer, $who, $reason, @args) = @_;
+  putaction 0, ACT_KILL, target => $who, source => $killer, reason => $reason, @args;
+}
+
+sub protect {
+  my ($doctor, $who) = @_;
+  putaction 0, ACT_PROTECT, target => $who, source => $doctor;
+}
+
+sub vig {
+  my ($vig, $who, $reason, @args) = @_;
+  putaction 0, ACT_KILL, target => $who, source => $vig, reason => $reason, @args;
+}
+
+sub roleblock {
+  my ($roleblocker, $who) = @_;
+  putaction 0, ACT_ROLEBLOCK, target => $who, source => $roleblocker;
+}
+
+sub jailkeep {
+  my ($jailkeeper, $who) = @_;
+  putaction 0, ACT_ROLEBLOCK, target => $who, source => $jailkeeper;
+  putaction 0, ACT_PROTECT, target => $who, source => $jailkeeper, count => 1000;
+}
+
+sub guncheck {
+  my ($gunsmith, $who) = @_;
+  putaction 0, ACT_GUNCHECK, target => $who, source => $gunsmith;
+}
+
+sub track {
+  my ($tracker, $who) = @_;
+  putaction 0, ACT_TRACK, target => $who, source => $tracker;
+  putaction 0, ACT_TRACK_RESULT, target => $who, source => $tracker;
+}
+
+sub watch {
+  my ($watcher, $who) = @_;
+  putaction 0, ACT_WATCH, target => $who, source => $watcher;
+  putaction 0, ACT_WATCH_RESULT, target => $who, source => $watcher;
+}
+
+sub guard {
+  my ($guard, $who) = @_;
+  putaction 0, ACT_GUARD, target => $who, source => $guard;
+}
+
+sub rolecopcheck {
+  my ($rolecop, $who) = @_;
+  putaction 0, ACT_ROLECOP, target => $who, source => $rolecop;
+}
+
+sub copcheck {
+  my ($cop, $who) = @_;
+  putaction 0, ACT_COP, target => $who, source => $cop;
+}
+
+sub skill {
+  my ($sk, $who, $reason, @args) = @_;
+  putaction 0, ACT_KILL, target => $who, source => $sk, reason => $reason, @args;
+}
+
+sub hide {
+  my ($hider, $who) = @_;
+  putaction 0, ACT_HIDE, target => $who, source => $hider;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Mafia - easily moderate Mafia games
+
+=head1 SYNOPSIS
+
+  #!/usr/bin/perl -w
+  use Mafia;
+
+  player 'Banana Bob', cop, town;
+  player 'Dragon Phoenix', vanilla, townie;
+  player 'Gammie', mafia, goon;
+  player 'gslamm', vanilla, townie;
+  player 'Untrod Tripod', mafia, goon;
+  player 'Werebear', vanilla, townie;
+  player 'willows_weep', town, doctor;
+
+  day;
+  lynch 'Untrod Tripod';
+
+  night;
+  factionkill 'Gammie', 'willows_weep', 'shot';
+  copcheck 'Banana Bob', 'gslamm';
+
+  day;
+  lynch 'Gammie';
+
+  night;
+
+=head1 DESCRPTION
+
+Mafia.pm is a Perl extension for easily moderating Mafia games. You don't even need to know Perl to use it (see L<"WHAT YOU NEED TO KNOW"> for details).
+
+=head1 WHAT YOU NEED TO KNOW
+
+A typical script starts with the following two lines
+
+  #!/usr/bin/perl -w
+  use Mafia;
+
+The rest of the script is a series of function calls that describe the players and their actions.
+
+A function call looks like this:
+
+  function_name first_argument, second_argument, ...
+
+Each argument is either a number, a string (which is a sequence of characters between single or double quotes, such as C<'badguy'>, C<'qwrf'>) or a constant (such as C<mafia>, C<vanilla>, C<bulletproof>).
+
+Example calls:
+
+  player 'Somebody', mafia, goon; # player is the function, 'Somebody' is a string, mafia and goon are constants.
+  lynch 'Nobody'; # lynch is the function, 'Nobody' is a string.
+  day; # day is the function. There are no arguments.
+
+=head1 FUNCTIONS
+
+=over
+
+=item B<player> I<name>, I<trait>, ...
+
+Defines a new player named I<name> and its traits (role, faction, role modifiers).
+
+Roles: C<vanilla, goon, doctor, vigilante, roleblocker, jailkeeper, gunsmith, tracker, watcher, bodyguard, rolecop, cop, sk, hider>.
+
+Factions: C<mafia, town>. C<townie> is a synonim for C<town>.
+
+Other attributes: C<miller, godfather, weak, macho, bulletproof>
+
+These traits may be specified in any order.
+
+Example usage:
+
+  player 'alice', town, bulletproof, miller, vigilante; # Alice is a NK-Immune Miller Vig
+  player 'bob', town, weak, doctor; # Bob is a Town Weak Doctor
+  player 'eve', mafia, godfather, goon; # Eve is a Mafia Godfather
+
+=item B<day>
+
+Defines the start of a new Day. All actions in the previous Night are now resolved.
+
+=item B<night>
+
+Defines the start of a new Night. All actions in the previous Day are now resolved.
+
+=item B<lynch> I<player>
+
+Notes that I<player> was lynched.
+
+=item B<factionkill> I<killer>, I<player>, I<flavour>, [ strong => 1 ]
+
+Notes that I<killer> killed I<player> with flavour I<flavour>. Append C<< strong => 1 >> if the kill should ignore roleblocks and doctor/jailkeeper protections. Use this for mafia kills.
+
+Example usage:
+
+  factionkill 'eve', 'alice', 'strangled to death';
+  factionkill 'eve', 'bob', 'brutally murdered', strong => 1; # This is a strongman kill
+
+=item B<protect> I<doctor>, I<player>
+
+Notes that I<doctor> protected I<player>.
+
+=item B<vig> I<vigilante>, I<player>, I<flavour>, [ strong => 1 ]
+
+Notes that I<killer> killed I<player> with flavour I<flavour>. Append C<< strong => 1 >> if the kill should ignore roleblocks and doctor/jailkeeper protections. Use this for Vigilante/Juggernaut kills.
+
+Example usage:
+
+  vig 'chuck', 'bob', 'shot';
+  vig 'chuck', 'bob', 'shot seven times', strong => 1; # This is a Juggernaut (Strongman Vigilante) kill
+
+=item B<roleblock> I<roleblocker>, I<player>
+
+Notes that I<roleblocker> roleblocked I<player>.
+
+=item B<jailkeep> I<jailkeeper>, I<player>
+
+Notes that I<jailkeeper> roleblocked and protected I<player>.
+
+=item B<guncheck> I<gunsmith>, I<player>
+
+Notes that I<gunsmith> checked if I<player> has a gun.
+
+=item B<track> I<tracker>, I<player>
+
+Notes that I<tracker> tracked I<player>.
+
+=item B<watch> I<watcher>, I<player>
+
+Notes that I<watcher> watched I<player>.
+
+=item B<guard> I<bodyguard>, I<player>
+
+Notes that I<bodyguard> guarded I<player>
+
+=item B<rolecopcheck> I<rolecop>, I<player>
+
+Notes that I<rolecop> checked the role of I<player>
+
+=item B<copcheck> I<cop>, I<player>
+
+Notes that I<cop> checked whether I<player> is mafia.
+
+=item B<skill> I<SK>, I<player>, I<flavour>, [ strong => 1 ]
+
+Notes that I<SK> killed player with flavour I<flavour>. Append C<< strong => 1 >>> if the kill should ignore roleblocks and doctor/jailkeeper protections. Use this for Serial Killer kills.
+
+=item B<hide> I<hider>, I<player>
+
+Notes that I<hider> hid behind I<player>.
+
+=back
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2013 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.14.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/t/00-use.t b/t/00-use.t
new file mode 100644 (file)
index 0000000..8155abd
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/perl -wT
+use v5.14;
+use warnings;
+
+use Test::More tests => 1;
+BEGIN { use_ok('Mafia') };
diff --git a/t/examples.t b/t/examples.t
new file mode 100644 (file)
index 0000000..b97b8e7
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+use File::Basename qw/fileparse/;
+use File::Slurp qw/read_file/;
+use Mafia;
+
+my @examples;
+BEGIN { @examples = map { s/\.pl//r } glob 't/examples/*.pl' };
+use Test::More tests => scalar @examples;
+
+for my $example (@examples) {
+  my $out;
+  close STDOUT;
+  open STDOUT, '>', \$out;
+  clean;
+
+  my $ok = read_file "$example.out";
+  eval scalar read_file "$example.pl";
+  is $out, $ok, scalar fileparse $example
+}
diff --git a/t/examples/Newbie-0001.out b/t/examples/Newbie-0001.out
new file mode 100644 (file)
index 0000000..4a79ecf
--- /dev/null
@@ -0,0 +1,15 @@
+It is Day 1
+Players alive: MeMe, PrettyPrincess, Stewie, ZONEACE, fgdtdtdtdr, rite, shadyforce
+fgdtdtdtdr (Town Doctor) — lynched Day 1
+
+It is Night 1
+Players alive: MeMe, PrettyPrincess, Stewie, ZONEACE, rite, shadyforce
+ZONEACE: rite is not mafia
+MeMe (Vanilla Townie) — shot Night 1
+
+It is Day 2
+Players alive: PrettyPrincess, Stewie, ZONEACE, rite, shadyforce
+ZONEACE (Town Cop) — lynched Day 2
+
+It is Night 2
+Players alive: PrettyPrincess, Stewie, rite, shadyforce
diff --git a/t/examples/Newbie-0001.pl b/t/examples/Newbie-0001.pl
new file mode 100644 (file)
index 0000000..1886515
--- /dev/null
@@ -0,0 +1,21 @@
+use Mafia;
+
+player fgdtdtdtdr => doctor, town;
+player MeMe => vanilla, townie;
+player PrettyPrincess => mafia, goon;
+player rite => vanilla, townie;
+player shadyforce => vanilla, townie;
+player Stewie => mafia, goon;
+player ZONEACE => town, cop;
+
+day;
+lynch 'fgdtdtdtdr';
+
+night;
+factionkill Stewie => MeMe => 'shot';
+copcheck ZONEACE => 'rite';
+
+day;
+lynch 'ZONEACE';
+
+night;
diff --git a/t/examples/Newbie-0002.out b/t/examples/Newbie-0002.out
new file mode 100644 (file)
index 0000000..927abd6
--- /dev/null
@@ -0,0 +1,15 @@
+It is Day 1
+Players alive: Banana Bob, Dragon Phoenix, Gammie, Untrod Tripod, Werebear, gslamm, willows_weep
+Untrod Tripod (Mafia Goon) — lynched Day 1
+
+It is Night 1
+Players alive: Banana Bob, Dragon Phoenix, Gammie, Werebear, gslamm, willows_weep
+Banana Bob: gslamm is not mafia
+willows_weep (Town Doctor) — shot Night 1
+
+It is Day 2
+Players alive: Banana Bob, Dragon Phoenix, Gammie, Werebear, gslamm
+Gammie (Mafia Goon) — lynched Day 2
+
+It is Night 2
+Players alive: Banana Bob, Dragon Phoenix, Werebear, gslamm
diff --git a/t/examples/Newbie-0002.pl b/t/examples/Newbie-0002.pl
new file mode 100644 (file)
index 0000000..b8ea2e9
--- /dev/null
@@ -0,0 +1,21 @@
+use Mafia;
+
+player 'Banana Bob', cop, town;
+player 'Dragon Phoenix', vanilla, townie;
+player 'Gammie', mafia, goon;
+player 'gslamm', vanilla, townie;
+player 'Untrod Tripod', mafia, goon;
+player 'Werebear', vanilla, townie;
+player 'willows_weep', town, doctor;
+
+day;
+lynch 'Untrod Tripod';
+
+night;
+factionkill 'Gammie', 'willows_weep', 'shot';
+copcheck 'Banana Bob', 'gslamm';
+
+day;
+lynch 'Gammie';
+
+night;
diff --git a/t/examples/Newbie-0003.out b/t/examples/Newbie-0003.out
new file mode 100644 (file)
index 0000000..89cae87
--- /dev/null
@@ -0,0 +1,15 @@
+It is Day 1
+Players alive: Bloojay, Kerplunk, QX, Stimpy, Talitha, max22, nard054
+Stimpy (Vanilla Townie) — lynched Day 1
+
+It is Night 1
+Players alive: Bloojay, Kerplunk, QX, Talitha, max22, nard054
+max22: Kerplunk is not mafia
+Bloojay (Town Doctor) — shot Night 1
+
+It is Day 2
+Players alive: Kerplunk, QX, Talitha, max22, nard054
+nard054 (Vanilla Townie) — lynched Day 2
+
+It is Night 2
+Players alive: Kerplunk, QX, Talitha, max22
diff --git a/t/examples/Newbie-0003.pl b/t/examples/Newbie-0003.pl
new file mode 100644 (file)
index 0000000..ad507bb
--- /dev/null
@@ -0,0 +1,21 @@
+use Mafia;
+
+player Bloojay => town, doctor;
+player Kerplunk => vanilla, townie;
+player max22 => town, cop;
+player nard054 => vanilla, townie;
+player QX => mafia, goon;
+player Stimpy => vanilla, townie;
+player Talitha => mafia, goon;
+
+day;
+lynch 'Stimpy';
+
+night;
+factionkill Talitha => 'Bloojay', 'shot';
+copcheck max22 => 'Kerplunk';
+
+day;
+lynch 'nard054';
+
+night;
diff --git a/t/examples/Newbie-0004.out b/t/examples/Newbie-0004.out
new file mode 100644 (file)
index 0000000..8a5ff81
--- /dev/null
@@ -0,0 +1,24 @@
+It is Day 1
+Players alive: Just_nigel, Phoebus, Smoke_Bandit, Someone, Sugar, Yggdrasil, tehgood
+tehgood (Vanilla Townie) — lynched Day 1
+
+It is Night 1
+Players alive: Just_nigel, Phoebus, Smoke_Bandit, Someone, Sugar, Yggdrasil
+Yggdrasil: Sugar is not mafia
+Sugar (Town Doctor) — shot Night 1
+
+It is Day 2
+Players alive: Just_nigel, Phoebus, Smoke_Bandit, Someone, Yggdrasil
+Phoebus (Mafia Goon) — lynched Day 2
+
+It is Night 2
+Players alive: Just_nigel, Smoke_Bandit, Someone, Yggdrasil
+Yggdrasil: Just_nigel is not mafia
+Yggdrasil (Town Cop) — shot Night 2
+
+It is Day 3
+Players alive: Just_nigel, Smoke_Bandit, Someone
+Smoke_Bandit (Vanilla Townie) — lynched Day 3
+
+It is Night 3
+Players alive: Just_nigel, Someone
diff --git a/t/examples/Newbie-0004.pl b/t/examples/Newbie-0004.pl
new file mode 100644 (file)
index 0000000..c110918
--- /dev/null
@@ -0,0 +1,28 @@
+use Mafia;
+
+player Sugar => town, doctor;
+player tehgood => vanilla, townie;
+player Yggdrasil => town, cop;
+player Smoke_Bandit => vanilla, townie;
+player Someone => mafia, goon;
+player Just_nigel => vanilla, townie;
+player Phoebus => mafia, goon;
+
+day;
+lynch 'tehgood';
+
+night;
+copcheck Yggdrasil => 'Sugar';
+factionkill Someone => 'Sugar', 'shot';
+
+day;
+lynch 'Phoebus';
+
+night;
+copcheck Yggdrasil => 'Just_nigel';
+factionkill Someone => 'Yggdrasil', 'shot';
+
+day;
+lynch 'Smoke_Bandit';
+
+night;
diff --git a/t/examples/Newbie-0005.out b/t/examples/Newbie-0005.out
new file mode 100644 (file)
index 0000000..91071b8
--- /dev/null
@@ -0,0 +1,15 @@
+It is Day 1
+Players alive: EnPaceRequiescat, Fishbulb, Flying Dutchman, Might Raven, Morpheus, Mr_Gnome_It_All, Vraak X
+Flying Dutchman (Vanilla Townie) — lynched Day 1
+
+It is Night 1
+Players alive: EnPaceRequiescat, Fishbulb, Might Raven, Morpheus, Mr_Gnome_It_All, Vraak X
+Vraak X: Fishbulb is not mafia
+Fishbulb (Vanilla Townie) — shot Night 1
+
+It is Day 2
+Players alive: EnPaceRequiescat, Might Raven, Morpheus, Mr_Gnome_It_All, Vraak X
+Mr_Gnome_It_All (Vanilla Townie) — lynched Day 2
+
+It is Night 2
+Players alive: EnPaceRequiescat, Might Raven, Morpheus, Vraak X
diff --git a/t/examples/Newbie-0005.pl b/t/examples/Newbie-0005.pl
new file mode 100644 (file)
index 0000000..6e895ef
--- /dev/null
@@ -0,0 +1,22 @@
+use Mafia;
+
+player EnPaceRequiescat => mafia, goon;
+player Fishbulb => vanilla, townie;
+player 'Flying Dutchman' => vanilla, townie;
+player 'Might Raven' => mafia, goon;
+player Morpheus => doctor, town;
+player Mr_Gnome_It_All => vanilla, townie;
+player 'Vraak X' => town, cop;
+
+day;
+lynch 'Flying Dutchman';
+
+night;
+factionkill EnPaceRequiescat => 'Fishbulb', 'shot';
+copcheck 'Vraak X' => 'Fishbulb';
+protect Morpheus => 'Vraak X';
+
+day;
+lynch 'Mr_Gnome_It_All';
+
+night;
This page took 0.027289 seconds and 4 git commands to generate.