use Math::Random;
$| = 1;
my $PrintForumCode = 0;
my $PrintCSV = 0;
my $PrintLegible = 1;
my @PlayersList =
(
'Org',
'ToonyMan',
'JanusTwoFace',
'Mr.Person',
'Duke 2.0',
'Rysith',
'Pandarsenic',
'Cheeetar',
'EchoP',
'R1ck',
'chaoticjosh',
'Twiggie',
'SniHjen',
'Servant Corps',
'Archangel',
'A_Fey_Dwarf',
'Frelock',
'webadict',
'Alexhans',
'Kashyyk',
'Beacon80',
'NUKE9.13',
'inaluct'
);
&ScrambleArray(\@PlayersList);
my $PlayersNum = @PlayersList;
#$PlayersNum = 20;
my $MinDoppNum = 2;
my $MinHostile = &Round(($PlayersNum / 4));
### May not use this right now...
my %Races;
$Races{'Human'} = .5;
$Races{'Doppelganger'} = .25;
$Races{'Alien'} = .25;
## Abilities
%TownAbilities;
%DoppAbilities;
%AlienAbilities;
%CultAbilites;
## Town-aligned roles
%TownRoles;
## Dopp aligned
%DoppRoles;
my $DoppInvestigator = 0;
## Aliens
%AlienRoles;
## Cult Aligned roles
%CultRoles;
my $CultInvestigator = 0;
my $RoleFile = 'C:\Documents and Settings\dsevier\My Documents\ParanormalRoles.csv';
#$RoleFile = 'C:\Documents and Settings\dsevier\My Documents\ParanormalRoles_simple.csv';
open RIN, "< $RoleFile" or die "Cannot open $RoleFile";
while(<RIN>)
{
my $line = $_;
chomp $line;
## 0=Name 1=Type 2=Faction 3=Max 4=Weight 5=Psychic 6=Goal
my @Data = split(",", $line);
if ($Data[0] eq "name") { next(); }
if ($Data[1] eq "ability")
{
if ($Data[2] eq "town")
{
$TownAbilities{$Data[0]}{'Max'} = $Data[3];
$TownAbilities{$Data[0]}{'Current'} = 0;
$TownAbilities{$Data[0]}{'Weight'} = $Data[4];
}
elsif ($Data[2] eq "dopp")
{
$DoppAbilities{$Data[0]}{'Max'} = $Data[3];
$DoppAbilities{$Data[0]}{'Current'} = 0;
$DoppAbilities{$Data[0]}{'Weight'} = $Data[4];
}
elsif ($Data[2] eq "alien")
{
$AlienAbilities{$Data[0]}{'Max'} = $Data[3];
$AlienAbilities{$Data[0]}{'Current'} = 0;
$AlienAbilities{$Data[0]}{'Weight'} = $Data[4];
}
elsif ($Data[2] eq "cult")
{
$CultAbilites{$Data[0]}{'Max'} = $Data[3];
$CultAbilites{$Data[0]}{'Current'} = 0;
$CultAbilites{$Data[0]}{'Weight'} = $Data[4];
}
else
{
warn "Unknown Faction $Data[2]\n";
}
}
elsif ($Data[1] eq "role")
{
if ($Data[2] eq "town")
{
$TownRoles{$Data[0]}{'Max'} = $Data[3];
$TownRoles{$Data[0]}{'Current'} = 0;
$TownRoles{$Data[0]}{'Weight'} = $Data[4];
$TownRoles{$Data[0]}{'Psychic'} = $Data[5];
$TownRoles{$Data[0]}{'Goal'} = $Data[6];
$TownRoles{$Data[0]}{'Requires'} = $Data[7];
$TownRoles{$Data[0]}{'Restricted'} = $Data[8];
}
elsif ($Data[2] eq "dopp")
{
$DoppRoles{$Data[0]}{'Max'} = $Data[3];
$DoppRoles{$Data[0]}{'Current'} = 0;
$DoppRoles{$Data[0]}{'Weight'} = $Data[4];
$DoppRoles{$Data[0]}{'Psychic'} = $Data[5];
$DoppRoles{$Data[0]}{'Goal'} = $Data[6];
$DoppRoles{$Data[0]}{'Requires'} = $Data[7];
$DoppRoles{$Data[0]}{'Restricted'} = $Data[8];
}
elsif ($Data[2] eq "alien")
{
$AlienRoles{$Data[0]}{'Max'} = $Data[3];
$AlienRoles{$Data[0]}{'Current'} = 0;
$AlienRoles{$Data[0]}{'Weight'} = $Data[4];
$AlienRoles{$Data[0]}{'Psychic'} = $Data[5];
$AlienRoles{$Data[0]}{'Goal'} = $Data[6];
$AlienRoles{$Data[0]}{'Requires'} = $Data[7];
$AlienRoles{$Data[0]}{'Restricted'} = $Data[8];
}
elsif ($Data[2] eq "cult")
{
$CultRoles{$Data[0]}{'Max'} = $Data[3];
$CultRoles{$Data[0]}{'Current'} = 0;
$CultRoles{$Data[0]}{'Weight'} = $Data[4];
$CultRoles{$Data[0]}{'Psychic'} = $Data[5];
$CultRoles{$Data[0]}{'Goal'} = $Data[6];
$CultRoles{$Data[0]}{'Requires'} = $Data[7];
$CultRoles{$Data[0]}{'Restricted'} = $Data[8];
}
else
{
warn "Unknown Faction $Data[2]\n";
}
}
else
{
warn "Unknown type $Data[1]\n";
}
}
close RIN;
## Determine number of Aliens and townsfolk
my $AlienPct = int(rand(20) + 1) / 100;
my $AlienNum = int($PlayersNum * $AlienPct);
if ($AlienNum > keys(%AlienRoles)) { $AlienNum = keys(%AlienRoles); }
my $HumansNum = $PlayersNum - $MinHostile - $AlienNum;
## Choose Dopps or Cult or both
$DoppNum = 0;
$CultNum = 0;
my $HostileChoice = int(rand(6 + 1));
if ( $HostileChoice <= 3 ) { $DoppNum = $MinHostile; }
elsif ( $HostileChoice >= 4 and $HostileChoice < 6 )
{
$DoppNum = int($MinHostile / 2);
$CultNum = int($MinHostile / 2);
if (($DoppNum + $CultNum) < $MinHostile) { $DoppNum += ($MinHostile - ($DoppNum + $CultNum)) ;}
}
else
{
$CultNum = $MinHostile;
}
my $FactionAdj = 0;
if ( $DoppNum and $CultNum) { $FactionAdj = 1; }
print "There are $PlayersNum players, $DoppNum of which are Doppelgangers and $CultNum are Cultists, and at most $AlienNum are aliens ($AlienPct)\n";
# $PlayerInfo{Player}
# $PlayerInfo{Player}{Race}
# $PlayerInfo{Player}{Role}
# $PlayerInfo{Player}{Goal}
# $PlayerInfo{Player}{Ability}
my %PlayerInfo;
## Track dopp stuff
$Dopps = 0;
## Track alien stuff
$Aliens = 0;
## Track Human stuff
$Humans = 0;
## Track Cultist stuff
$Cultists = 0;
## First run, set roles for everyone. Tries to keep balance, but the last few may not
$GameBalance = $FactionAdj;
for (my $p = 0; $p < $PlayersNum; $p++)
{
my $Race = GetRace();
print "$p Race = $Race\n";
my $Role = GetRole($Race);
print "$p Role = $Role\n";
my $Goal = GetGoal($Race,$Role);
print "$p Goal = $Goal\n";
print " Game Balance is now: $GameBalance\n";
$PlayerInfo{$PlayersList[$p]}{'Race'} = $Race;
$PlayerInfo{$PlayersList[$p]}{'Role'} = $Role;
$PlayerInfo{$PlayersList[$p]}{'Goal'} = $Goal;
$PlayerInfo{$PlayersList[$p]}{'Ability'} = 'None';
sleep(1);
}
## Second run, balance things out
print "----------------------------------------------\n";
## First, we'll try adding in a Mind Shield (or other ability) to one side or another (or to aliens)
for (my $p = 0; $p < $PlayersNum; $p++)
{
if ( int($GameBalance) == 0) { print "Abilities: Balance is close enough to 0\n"; last(); }
my $Race = $PlayerInfo{$PlayersList[$p]}{'Race'};
my $Role = $PlayerInfo{$PlayersList[$p]}{'Role'};
$PlayerInfo{$PlayersList[$p]}{'Ability'} = &GetAbility($Race, $Role);
}
print "Abilities: Game Balance is now: $GameBalance\n";
## Now we'll try rebalancing roles
my $BalanceOk = 0;
my $BalanceLoop = 0;
while ($BalanceOk == 0)
{
$BalanceLoop++;
for (my $p = 0; $p < $PlayersNum; $p++)
{
$Race = $PlayerInfo{$PlayersList[$p]}{'Race'};
my $Ability = $PlayerInfo{$PlayersList[$p]}{'Ability'};
if ( int($GameBalance) == 0) { print "Second Pass: Balance is close enough to 0\n"; last(); }
if ( $PlayerInfo{$PlayersList[$p]}{'Race'} ne "Alien" )
{
my $CurrentRole = $PlayerInfo{$PlayersList[$p]}{'Role'};
my $NewRole = &GetNewRole($CurrentRole, $Race, $Ability);
$PlayerInfo{$PlayersList[$p]}{'Role'} = $NewRole;
print "$p OldRole = $CurrentRole NewRole = $NewRole ($Race)\n";
print " Game Balance is now: $GameBalance\n";
}
}
if ( int($GameBalance) == 0 or $BalanceLoop == 30 ) { $BalanceOk = 1; }
}
###### Print Output ########
if ( $PrintForumCode )
{
print "\n";
print '[table]' . "\n";
print '[tr]' . "\n";
print '[td][b]Player[/b][/td]';
print '[td][b]Race[/b][/td]';
print '[td][b]Role[/b][/td]';
print '[td][b]Goal[/b][/td]' . "\n";
print '[td][b]Ability[/b][/td]' . "\n";
print '[/tr]' . "\n";
foreach my $Player ( sort keys %PlayerInfo )
{
#print "$Player,$PlayerInfo{$Player}{'Race'},$PlayerInfo{$Player}{'Role'},$PlayerInfo{$Player}{'Goal'}\n";
print '[tr]' . "\n";
print '[td]' . $Player . '[/td]';
print '[td]' . $PlayerInfo{$Player}{'Race'} . '[/td]';
print '[td]' . $PlayerInfo{$Player}{'Role'} . '[/td]';
print '[td]' . $PlayerInfo{$Player}{'Goal'} . '[/td]' . "\n";
print '[td]' . $PlayerInfo{$Player}{'Ability'} . '[/td]' . "\n";
print '[/tr]' . "\n";
}
print "[/table]\n";
}
if ($PrintCSV)
{
print "\n";
print "Player,Race,Role,Goal,Ability\n";
foreach my $Player ( sort keys %PlayerInfo )
{
print "$Player,$PlayerInfo{$Player}{'Race'},$PlayerInfo{$Player}{'Role'},$PlayerInfo{$Player}{'Goal'},$PlayerInfo{$Player}{'Ability'}\n";
}
}
if ( $PrintLegible )
{
print "There are $PlayersNum players, $DoppNum of which are Doppelgangers and $CultNum are Cultists, and at most $AlienNum are aliens ($AlienPct)\n";
print "\n";
foreach my $Player ( sort keys %PlayerInfo )
{
print "$Player ($PlayerInfo{$Player}{'Race'})\n";
if ($PlayerInfo{$Player}{'Role'} ne "None" ) { print " $PlayerInfo{$Player}{'Role'}\n"; }
if ($PlayerInfo{$Player}{'Race'} eq "Alien" ) { print " $PlayerInfo{$Player}{'Goal'}\n"; }
if ($PlayerInfo{$Player}{'Ability'} ne 'None') { print " $PlayerInfo{$Player}{'Ability'}\n"; }
}
}
exit();
########################################################################
sub GetRace
{
my $RaceOk = 0;
my $Race;
while (! $RaceOk)
{
my $RaceRoll = int(&random_uniform(8, 0, 8) + 1); #int(&random_uniform(8) + 1);
print " Race Roll: $RaceRoll\n";
if ($RaceRoll == 1)
{
$Race = 'Human Cultist';
if ( ($Cultists +1) <= $CultNum)
{
$Cultists++;
$RaceOk = 1;
}
}
elsif ($RaceRoll == 2)
{
$Race = 'Doppelganger';
if ( ($Dopps +1) <= $DoppNum)
{
$Dopps++;
$RaceOk = 1;
}
}
elsif ($RaceRoll == 3)
{
$Race = 'Alien';
if ( ($Aliens +1) <= $AlienNum)
{
$Aliens++;
$RaceOk = 1;
}
}
else
{
$Race = 'Human';
if ( ($Humans +1) <= $HumansNum)
{
$Humans++;
$RaceOk = 1;
}
}
}
return $Race;
}
## ---------------------------
sub GetRole
{
my $Race = shift;
my $Role = "None";
if ($Race eq "Doppelganger")
{
my $RoleOk = 0;
my $Checks = 0;
$Role = 'Doppelganger';
my $LastOkRole = 'Doppelganger';
while ($RoleOk == 0)
{
$Checks++;
my @Roles = keys(%DoppRoles);
my $CheckRole = &random_permutation(@Roles);
if ($DoppRoles{$CheckRole}{'Current'} < $DoppRoles{$CheckRole}{'Max'})
{
my $Goal = $DoppRoles{$CheckRole}{'Goal'};
## Check for investigative roles
if ($DoppInvestigator and $Goal =~ m/find/i) { print "Debug: Already have a dopp investigator: $CheckRole $Goal\n"; next(); }
elsif (! $DoppInvestigator and $Goal =~ m/find/i) { $DoppInvestigator = 1; }
## Check for required roles
if ($DoppRoles{$CheckRole}{'Requires'})
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $DoppRoles{$CheckRole}{'Requires'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} == 0) { next(); }
}
if ($DoppRoles{$CheckRole}{'Restricted'})
{
## If we have the restricted race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $DoppRoles{$CheckRole}{'Restricted'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} > 0) { next(); }
}
$Role = $CheckRole;
$GameBalance+=$DoppRoles{$Role}{'Weight'};
$RoleOk = 1;
$DoppRoles{$CheckRole}{'Current'}++;
}
if ( $Checks > 10 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$DoppRoles{$Role}{'Weight'};
print "DEBUG: Checks got to $Checks\n";
}
}
}
}
elsif ($Race eq "Human Cultist")
{
my $RoleOk = 0;
my $Checks = 0;
$Role = 'Cultist';
my $LastOkRole = 'Cultist';
while ($RoleOk == 0)
{
$Checks++;
my @Roles = keys(%CultRoles);
my $CheckRole = &random_permutation(@Roles);
if ($CultRoles{$CheckRole}{'Current'} < $CultRoles{$CheckRole}{'Max'})
{
my $Goal = $CultRoles{$CheckRole}{'Goal'};
## Check for investigative roles
if ($CultInvestigator and $Goal =~ m/find/i) { print "Debug: Already have a cult investigator: $CheckRole $Goal\n"; next(); }
elsif (! $CultInvestigator and $Goal =~ m/find/i) { $CultInvestigator = 1; }
## Check for required roles
if ($CultRoles{$CheckRole}{'Requires'})
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $CultRoles{$CheckRole}{'Requires'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} == 0) { next(); }
}
if ($CultRoles{$CheckRole}{'Restricted'})
{
## If we have the restricted race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $CultRoles{$CheckRole}{'Restricted'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} > 0) { next(); }
}
$Role = $CheckRole;
$GameBalance+=$CultRoles{$Role}{'Weight'};
$RoleOk = 1;
$CultRoles{$CheckRole}{'Current'}++;
}
if ( $Checks > 10 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$CultRoles{$Role}{'Weight'};
print "DEBUG: Checks got to $Checks\n";
}
}
}
}
elsif ($Race eq "Alien")
{
my $RoleOk = 0;
while ($RoleOk == 0)
{
my @Roles = keys(%AlienRoles);
my $CheckRole = &random_permutation(@Roles);
if ($AlienRoles{$CheckRole}{'Current'} < $AlienRoles{$CheckRole}{'Max'})
{
## Check for required roles
if ($AlienRoles{$CheckRole}{'Requires'})
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $AlienRoles{$CheckRole}{'Requires'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} == 0) { next(); }
}
if ($AlienRoles{$CheckRole}{'Restricted'})
{
## If we have the restricted race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $AlienRoles{$CheckRole}{'Restricted'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} > 0) { next(); }
}
$RoleOk = 1;
$AlienRoles{$CheckRole}{'Current'}++;
$Role = $CheckRole;
$GameBalance+=$AlienRoles{$Role}{'Weight'};
}
}
}
else
{
my $RoleOk = 0;
$Role = 'Townsperson';
my $LastOkRole = 'Townsperson';
my $Checks = 0;
while ($RoleOk == 0)
{
$Checks++;
my @Roles = keys(%TownRoles);
my $CheckRole = &random_permutation(@Roles);
if ($TownRoles{$CheckRole}{'Current'} < $TownRoles{$CheckRole}{'Max'})
{
if ($TownRoles{$CheckRole}{'Requires'})
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $TownRoles{$CheckRole}{'Requires'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} == 0) { next(); }
}
if ($TownRoles{$CheckRole}{'Restricted'})
{
## If we have the restricted race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $TownRoles{$CheckRole}{'Restricted'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} > 0) { next(); }
}
$TownRoles{$CheckRole}{'Current'}++;
$Role = $CheckRole;
$GameBalance+=$TownRoles{$Role}{'Weight'};
$RoleOk = 1;
}
if ( $Checks > 10 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$TownRoles{$Role}{'Weight'};
print "DEBUG: Checks got to $Checks\n";
}
}
}
}
return $Role;
}
##-------------------------
sub GetNewRole
{
my $OldRole = shift;
my $Race = shift;
my $Ability = shift;
my $Role = $OldRole;
if ($Race eq "Doppelganger")
{
my $RoleOk = 0;
my $Checks = 0;
my $LastOkRole = $OldRole;
$GameBalance-=$DoppRoles{$OldRole}{'Weight'};
$DoppRoles{$OldRole}{'Current'}--;
while ($RoleOk == 0)
{
$Checks++;
my @Roles = keys(%DoppRoles);
my $CheckRole = &random_permutation(@Roles);
my $Psychic = $DoppRoles{$CheckRole}{'Psychic'};
my $Goal = $DoppRoles{$CheckRole}{'Goal'};
if ($Ability eq 'Mind Shield' and $Psychic) { print " debug: $CheckRole is psychic and Ability is $Ability\n"; next(); }
if ($DoppInvestigator and $Goal =~ m/find/i) { print "Debug: Already have a dopp investigator: $CheckRole $Goal\n"; next(); }
print " debug: CR = $CheckRole\n";
if ($DoppRoles{$CheckRole}{'Current'} < $DoppRoles{$CheckRole}{'Max'})
{
## Check for required roles
if ($DoppRoles{$CheckRole}{'Requires'})
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $DoppRoles{$CheckRole}{'Requires'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} == 0) { next(); }
}
if ($DoppRoles{$CheckRole}{'Restricted'})
{
## If we have the restricted race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $DoppRoles{$CheckRole}{'Restricted'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} > 0) { next(); }
}
if ( &BalancesPower($DoppRoles{$CheckRole}{'Weight'},$DoppRoles{$LastOkRole}{'Weight'}) )
{
$RoleOk = 1;
$DoppRoles{$CheckRole}{'Current'}++;
if ( $DoppRoles{$Role}{'Goal'} =~ m/find/i and $DoppRoles{$CheckRole}{'Goal'} !~ m/find/i ) { $DoppInvestigator = 0; }
$Role = $CheckRole;
$GameBalance+=$DoppRoles{$Role}{'Weight'};
if (! $DoppInvestigator and $Goal =~ m/find/i) { $DoppInvestigator = 1; }
}
}
if ( $Checks > 30 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$DoppRoles{$Role}{'Weight'};
$DoppRoles{$Role}{'Current'}++;
print "DEBUG: Checks got to $Checks\n";
}
}
}
}
elsif ($Race eq "Human Cultist")
{
my $RoleOk = 0;
my $Checks = 0;
my $LastOkRole = $OldRole;
$GameBalance-=$CultRoles{$OldRole}{'Weight'};
$CultRoles{$OldRole}{'Current'}--;
while ($RoleOk == 0)
{
$Checks++;
my @Roles = keys(%CultRoles);
my $CheckRole = &random_permutation(@Roles);
my $Psychic = $CultRoles{$CheckRole}{'Psychic'};
my $Goal = $CultRoles{$CheckRole}{'Goal'};
if ($Ability eq 'Mind Shield' and $Psychic) { print " debug: $CheckRole is psychic and Ability is $Ability\n"; next(); }
if ($CultInvestigator and $Goal =~ m/find/i) { print "Debug: Already have a cult investigator: $CheckRole $Goal\n"; next(); }
print " debug: CR = $CheckRole\n";
if ($CultRoles{$CheckRole}{'Current'} < $CultRoles{$CheckRole}{'Max'})
{
## Check for required roles
if ($CultRoles{$CheckRole}{'Requires'})
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $CultRoles{$CheckRole}{'Requires'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} == 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} == 0) { next(); }
}
if ($CultRoles{$CheckRole}{'Restricted'})
{
## If we have the restricted race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $CultRoles{$CheckRole}{'Restricted'});
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} > 0) { next(); }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} > 0) { next(); }
}
if ( &BalancesPower($CultRoles{$CheckRole}{'Weight'},$CultRoles{$LastOkRole}{'Weight'}) )
{
$RoleOk = 1;
$CultRoles{$CheckRole}{'Current'}++;
if ( $CultRoles{$Role}{'Goal'} =~ m/find/i and $CultRoles{$CheckRole}{'Goal'} !~ m/find/i ) { $CultInvestigator = 0; }
$Role = $CheckRole;
$GameBalance+=$CultRoles{$Role}{'Weight'};
if (! $CultInvestigator and $Goal =~ m/find/i) { $CultInvestigator = 1; }
}
}
if ( $Checks > 30 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$CultRoles{$Role}{'Weight'};
$CultRoles{$Role}{'Current'}++;
print "DEBUG: Checks got to $Checks\n";
}
}
}
}
else
{
my $RoleOk = 0;
my $LastOkRole = $OldRole;
$GameBalance-=$TownRoles{$OldRole}{'Weight'};
$TownRoles{$OldRole}{'Current'}--;
my $Checks = 0;
while ($RoleOk == 0)
{
$Checks++;
my @Roles = keys(%TownRoles);
my $CheckRole = &random_permutation(@Roles);
my $Psychic = $TownRoles{$CheckRole}{'Psychic'};
if ($Ability eq 'Mind Shield' and $Psychic) { print " debug: $CheckRole is psychic and Ability is $Ability\n"; next(); }
print " debug: CR = $CheckRole\n";
if ($TownRoles{$CheckRole}{'Current'} < $TownRoles{$CheckRole}{'Max'})
{
if ( &BalancesPower($TownRoles{$CheckRole}{'Weight'},$TownRoles{$LastOkRole}{'Weight'}) )
{
$RoleOk = 1;
$TownRoles{$CheckRole}{'Current'}++;
$Role = $CheckRole;
$GameBalance+=$TownRoles{$Role}{'Weight'};
}
}
if ( $Checks > 30 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$TownRoles{$Role}{'Weight'};
$TownRoles{$Role}{'Current'}++;
print "DEBUG: Checks got to $Checks\n";
}
}
}
}
return $Role;
}
##----------------------------
sub GetGoal
{
my $Race = shift;
my $Role = shift;
if ($Race eq "Doppelganger" or $Race eq "Human Cultist")
{
$Goal = "Town Loses";
}
elsif ($Race eq "Alien")
{
$Goal = $AlienRoles{$Role}{'Goal'};
}
else
{
$Goal = "Town Wins";
}
return $Goal;
}
#-----------------------
sub GetAbility
{
my $Race = shift;
my $Role = shift;
my $Psychic;
my $NewBalance;
my $Ability = 'None';
if ($Race eq "Human")
{
$Psychic = $TownRoles{$Role}{'Psychic'};
print " debug: $Role is psychic ( $Psychic )\n";
if ($Psychic) { return $Ability; }
else
{
my @Abilities = keys(%TownAbilities);
my $AbilityNum = @Abilities;
my $CheckAbility = $Abilities[rand $AbilityNum];
if ( $TownAbilities{$CheckAbility}{'Current'} < $TownAbilities{$CheckAbility}{'Max'} )
{
if ( &BalancesPower($TownAbilities{$CheckAbility}{'Weight'}, 0) )
{
$TownAbilities{$CheckAbility}{'Current'}++;
$Ability = $CheckAbility;
$GameBalance+=$TownAbilities{$CheckAbility}{'Weight'};
}
}
}
}
elsif($Race eq "Doppelganger")
{
$Psychic = $DoppRoles{$Role}{'Psychic'};
print " debug: $Role is psychic ( $Psychic )\n";
if ($Psychic) { return $Ability; }
else
{
my @Abilities = keys(%DoppAbilities);
my $AbilityNum = @Abilities;
my $CheckAbility = $Abilities[rand $AbilityNum];
if ( $DoppAbilities{$CheckAbility}{'Current'} < $DoppAbilities{$CheckAbility}{'Max'} )
{
if ( &BalancesPower($DoppAbilities{$CheckAbility}{'Weight'}, 0) )
{
$DoppAbilities{$CheckAbility}{'Current'}++;
$Ability = $CheckAbility;
$GameBalance+=$DoppAbilities{$CheckAbility}{'Weight'};
}
}
}
}
elsif($Race eq "Human Cultist")
{
$Psychic = $CultRoles{$Role}{'Psychic'};
print " debug: $Role is psychic ( $Psychic )\n";
if ($Psychic) { return $Ability; }
else
{
my @Abilities = keys(%CultAbilities);
my $AbilityNum = @Abilities;
my $CheckAbility = $Abilities[rand $AbilityNum];
if ( $CultAbilities{$CheckAbility}{'Current'} < $CultAbilities{$CheckAbility}{'Max'} )
{
if ( &BalancesPower($CultAbilities{$CheckAbility}{'Weight'}, 0) )
{
$CultAbilities{$CheckAbility}{'Current'}++;
$Ability = $CheckAbility;
$GameBalance+=$CultAbilities{$CheckAbility}{'Weight'};
}
}
}
}
else
{
$Psychic = $AlienRoles{$Role}{'Psychic'};
print " debug: $Role is psychic ( $Psychic )\n";
if ($Psychic) { return $Ability; }
else
{
my @Abilities = keys(%AlienAbilities);
my $AbilityNum = @Abilities;
my $CheckAbility = $Abilities[rand $AbilityNum];
if ( $AlienAbilities{$CheckAbility}{'Current'} < $AlienAbilities{$CheckAbility}{'Max'} )
{
if ( &BalancesPower($AlienRoles{$Role}{'Weight'}, 0) )
{
$AlienAbilities{$CheckAbility}{'Current'}++;
$Ability = $CheckAbility;
$GameBalance+=$AlienRoles{$Role}{'Weight'};
}
}
}
}
return $Ability;
}
#-----------------------
sub Round
{
my $Number = shift;
return int($Number + .5);
}
#-----------------------
sub BalancesPower
{
my $PowerOne = shift;
my $PowerTwo = shift;
my $ChangeOne = $GameBalance + $PowerOne;
my $ChangeTwo = $GameBalance + $PowerTwo;
if ( abs($ChangeOne) <= abs($ChangeTwo) )
{
return 1;
}
else
{
return 0;
}
}
#-------------------------
sub ScrambleArray
{
my $Array_ref = shift;
my @TempArray;
my $ArrayNum = @{$Array_ref};
while(@{$Array_ref})
{
my $Spot = pop(@{$Array_ref});
my $Ok = 0;
until ($Ok)
{
my $NewSpot = int(&random_uniform($ArrayNum, 0, $ArrayNum));
if (! defined $TempArray[$NewSpot])
{
#print "Placing $Spot in $NewSpot\n";
$TempArray[$NewSpot] = $Spot;
$Ok = 1;
}
}
}
@{$Array_ref} = @TempArray;
}
name,type,faction,max,weight,psychic,goal,requires,restricted
Mind Shield,ability,town,2,1,1,,,
Mind Shield,ability,dopp,2,-3,1,,,
Mind Shield,ability,alien,2,1,1,,,
Mind Shield,ability,cult,2,-3,1,,,
Townsperson,role,town,100,0,0,survive,,
Agent,role,town,2,4,0,find,,
Detective,role,town,2,3,0,find,,
Telepath,role,town,2,3,1,find,,
Guardian,role,town,2,4,0,protect,,
War Vet,role,town,2,1,0,kill,,
Bodyguard,role,town,2,1,0,protect,,
Mad Scientist,role,town,2,2,0,survive,,
Medium,role,town,2,2,1,find,,
Enchanter,role,town,2,2,1,survive,,
Warlock,role,town,2,2,1,survive,,
Psychic Warden,role,town,2,2,1,protect
Vigilante,role,town,2,3,0,kill
Reporter,role,town,2,3,0,find
Kook,role,town,2,-1,0,survive
Disciple of Truth,role,town,2,1,1,find
Watcher,role,town,2,3,0,find
Doppelganger,role,dopp,100,-1,0,kill
Agent,role,dopp,2,-4,0,find
Detective,role,dopp,2,-6,0,find
Telepath,role,dopp,2,-5,1,find
Guardian,role,dopp,2,-6,0,protect
Bodyguard,role,dopp,2,-4,0,protect
Mad Scientist,role,dopp,2,-4,0,kill
Psychic Warden,role,dopp,2,-4,1,protect
Enchanter,role,dopp,2,-3,1,kill
Reporter,role,dopp,2,-3,0,find
Leader,role,dopp,1,-4,1,kill,,
Advanced Doppelganger,role,dopp,1,-7,1,kill,,
Controlled Doppelganger,role,dopp,1,-1,0,kill,alien::Exterminator,alien::Operative
Disciple of Truth,role,dopp,2,-2,1,find,,
Watcher,role,dopp,2,-4,1,find,,
Vigilante,role,dopp,2,-8,1,kill,,
War Vet,role,dopp,2,-7,1,kill,,
Medium,role,dopp,2,-3,1,find,,
Warlock,role,dopp,2,-3,1,kill,,
Exterminator,role,alien,1,-1,0,kill,,
Agent Seeker,role,alien,1,0,0,find,town::Agent,
Doppelganger Hunter,role,alien,1,1,0,find,,
Survivor,role,alien,1,0,0,survive,,
Operative,role,alien,1,-1,0,protect,alien::Exterminator,dopp::Controlled Doppelganger
Scientist,role,alien,1,0,0,find,,
Cult Leader,role,cult,1,-4,0,kill,,
Cultist,role,cult,100,-1,0,kill
Agent,role,cult,2,-4,0,find
Detective,role,cult,2,-5,0,find
Telepath,role,cult,2,-5,1,find
Guardian,role,cult,2,-6,0,protect
Bodyguard,role,cult,2,-4,0,protect
Mad Scientist,role,cult,2,-4,0,kill
Psychic Warden,role,cult,2,-4,1,protect
Enchanter,role,cult,2,-3,1,kill
Reporter,role,cult,2,-3,0,find
Disciple of Truth,role,cult,2,-2,1,find
Watcher,role,cult,2,-4,1,find
Vigilante,role,cult,2,-8,1,kill
War Vet,role,cult,2,-7,1,kill
Medium,role,cult,2,-3,1,find
Warlock,role,cult,2,-3,1,kill