use Math::Random;
$| = 1;
my $PrintForumCode = 0;
my $PrintCSV = 0;
my $PrintLegible = 1;
my @PlayersList =
(
'Player1',
'Player2',
'Player3',
'Player4',
'Player5',
'Player6',
'Player7',
'Player8',
'Player9',
'Playera',
'Playerb',
'Playerc',
'Playerd',
);
&ScrambleArray(\@PlayersList);
my $PlayersNum = @PlayersList;
#$PlayersNum = 20;
my $MinDoppNum = 2;
my $HostilePct = .25;
### 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;
## Aliens
%AlienRoles;
## Cult Aligned roles
%CultRoles;
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];
$TownAbilities{$Data[0]}{'Psychic'} = $Data[5];
$TownAbilities{$Data[0]}{'Requires'} = $Data[7];
$TownAbilities{$Data[0]}{'Restricted'} = $Data[8];
$TownAbilities{$Data[0]}{'HasVarients'} = $Data[9];
$TownAbilities{$Data[0]}{'IsVarientOf'} = $Data[10];
}
elsif ($Data[2] eq "dopp")
{
$DoppAbilities{$Data[0]}{'Max'} = $Data[3];
$DoppAbilities{$Data[0]}{'Current'} = 0;
$DoppAbilities{$Data[0]}{'Weight'} = $Data[4];
$DoppAbilities{$Data[0]}{'Psychic'} = $Data[5];
$DoppAbilities{$Data[0]}{'Requires'} = $Data[7];
$DoppAbilities{$Data[0]}{'Restricted'} = $Data[8];
$DoppAbilities{$Data[0]}{'HasVarients'} = $Data[9];
$DoppAbilities{$Data[0]}{'IsVarientOf'} = $Data[10];
}
elsif ($Data[2] eq "alien")
{
$AlienAbilities{$Data[0]}{'Max'} = $Data[3];
$AlienAbilities{$Data[0]}{'Current'} = 0;
$AlienAbilities{$Data[0]}{'Weight'} = $Data[4];
$AlienAbilities{$Data[0]}{'Psychic'} = $Data[5];
$AlienAbilities{$Data[0]}{'Requires'} = $Data[7];
$AlienAbilities{$Data[0]}{'Restricted'} = $Data[8];
$AlienAbilities{$Data[0]}{'HasVarients'} = $Data[9];
$AlienAbilities{$Data[0]}{'IsVarientOf'} = $Data[10];
}
elsif ($Data[2] eq "cult")
{
$CultAbilites{$Data[0]}{'Max'} = $Data[3];
$CultAbilites{$Data[0]}{'Current'} = 0;
$CultAbilites{$Data[0]}{'Weight'} = $Data[4];
$CultAbilites{$Data[0]}{'Psychic'} = $Data[5];
$CultAbilites{$Data[0]}{'Requires'} = $Data[7];
$CultAbilites{$Data[0]}{'Restricted'} = $Data[8];
$CultAbilites{$Data[0]}{'HasVarients'} = $Data[9];
$CultAbilites{$Data[0]}{'IsVarientOf'} = $Data[10];
}
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];
$TownRoles{$Data[0]}{'HasVarients'} = $Data[9];
$TownRoles{$Data[0]}{'IsVarientOf'} = $Data[10];
}
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];
$DoppRoles{$Data[0]}{'HasVarients'} = $Data[9];
$DoppRoles{$Data[0]}{'IsVarientOf'} = $Data[10];
}
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];
$AlienRoles{$Data[0]}{'HasVarients'} = $Data[9];
$AlienRoles{$Data[0]}{'IsVarientOf'} = $Data[10];
}
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];
$CultRoles{$Data[0]}{'HasVarients'} = $Data[9];
$CultRoles{$Data[0]}{'IsVarientOf'} = $Data[10];
}
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); }
## Choose Dopps or Cult or both
my $FactionAdj = 0;
$DoppNum = 0;
$CultNum = 0;
my $HostileChoice = 1;
my $MinHostile = &Round(($PlayersNum * $HostilePct));
if ( $HostileChoice <= 3 ) { $DoppNum = $MinHostile; }
elsif ( $HostileChoice >= 4 and $HostileChoice < 6 ) { $CultNum = $MinHostile; }
else
{
## Numbers change if there are two mafia groups
$HostilePct = .35;
$MinHostile = &Round(($PlayersNum * $HostilePct));
$AlienPct = int(rand(10) + 1) / 100;
$AlienNum = int($PlayersNum * $AlienPct);
if ($AlienNum > keys(%AlienRoles)) { $AlienNum = keys(%AlienRoles); }
$DoppNum = int($MinHostile / 2);
$CultNum = int($MinHostile / 2);
$FactionAdj = 4;
if (($DoppNum + $CultNum) < $MinHostile) { $DoppNum += ($MinHostile - ($DoppNum + $CultNum)) ;}
}
my $HumansNum = $PlayersNum - $MinHostile - $AlienNum;
print "There are $PlayersNum players, $DoppNum of which are Doppelgangers and $CultNum are Cultists, and $AlienNum are aliens ($AlienPct)\n";
print "HostileChoice was $HostileChoice\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
$DoppBalance = 0;
$CultBalance = 0;
$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 and $DoppBalance == $CultBalance) { 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 ( !$DoppNum ) { $DoppBalance = $CultBalance; }
elsif ( !$CultNum ) { $CultBalance = $DoppBalance; }
if ( (int($GameBalance) == 0 and $DoppBalance == $CultBalance) or $BalanceLoop == 30 ) { $BalanceOk = 1; }
}
## Print final Balances
print "Game balance is $GameBalance. Dopps: $DoppBalance Cult: $CultBalance\n";
print "\n";
###### 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 $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'})
{
## Skip roles that have varients, since they're not used by themselves
if ( $DoppRoles{$CheckRole}{'HasVarients'} =~ m/yes/i ) { next(); }
## If our role is a varient, we need to make sure we don't have too many varients already
if ( $DoppRoles{$CheckRole}{'IsVarientOf'} )
{
my $BaseRole = $DoppRoles{$CheckRole}{'IsVarientOf'};
if ( $DoppRoles{$BaseRole}{'Current'} >= $DoppRoles{$BaseRole}{'Max'} )
{
next();
}
}
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 ( &CheckRequire(\%DoppRoles, $CheckRole) == 0) { next(); }
if ( &CheckRestrict(\%DoppRoles, $CheckRole) == 0) { next(); }
$Role = $CheckRole;
$GameBalance+=$DoppRoles{$Role}{'Weight'};
$DoppBalance+=$DoppRoles{$Role}{'Weight'};
$RoleOk = 1;
$DoppRoles{$Role}{'Current'}++;
if ( $DoppRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $DoppRoles{$Role}{'IsVarientOf'};
$DoppRoles{$BaseRole}{'Current'}++;
}
}
if ( $Checks > 10 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$DoppRoles{$Role}{'Weight'};
$DoppBalance+=$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'})
{
## Skip roles that have varients, since they're not used by themselves
if ( $CultRoles{$CheckRole}{'HasVarients'} =~ m/yes/i ) { next(); }
## If our role is a varient, we need to make sure we don't have too many varients already
if ( $CultRoles{$CheckRole}{'IsVarientOf'} )
{
my $BaseRole = $CultRoles{$CheckRole}{'IsVarientOf'};
if ( $CultRoles{$BaseRole}{'Current'} >= $CultRoles{$BaseRole}{'Max'} )
{
next();
}
}
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 (&CheckRequire(\%CultRoles, $CheckRole) == 0) { next(); }
if (&CheckRestrict(\%CultRoles, $CheckRole) == 0) { next(); }
$Role = $CheckRole;
$GameBalance+=$CultRoles{$Role}{'Weight'};
$CultBalance+=$CultRoles{$Role}{'Weight'};
$RoleOk = 1;
$CultRoles{$CheckRole}{'Current'}++;
if ( $CultRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $CultRoles{$Role}{'IsVarientOf'};
$CultRoles{$BaseRole}{'Current'}++;
}
}
if ( $Checks > 10 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$CultRoles{$Role}{'Weight'};
$CultBalance+=$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'})
{
## Skip roles that have varients, since they're not used by themselves
if ( $AlienRoles{$CheckRole}{'HasVarients'} =~ m/yes/i ) { next(); }
## If our role is a varient, we need to make sure we don't have too many varients already
if ( $AlienRoles{$CheckRole}{'IsVarientOf'} )
{
my $BaseRole = $AlienRoles{$CheckRole}{'IsVarientOf'};
if ( $AlienRoles{$BaseRole}{'Current'} >= $AlienRoles{$BaseRole}{'Max'} )
{
next();
}
}
## Check for required roles
if (&CheckRequire(\%AlienRoles, $CheckRole) == 0) { next(); }
if (&CheckRestrict(\%AlienRoles, $CheckRole) == 0) { next(); }
$RoleOk = 1;
$AlienRoles{$CheckRole}{'Current'}++;
$Role = $CheckRole;
$GameBalance+=$AlienRoles{$Role}{'Weight'};
if ( $AlienRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $AlienRoles{$Role}{'IsVarientOf'};
$AlienRoles{$BaseRole}{'Current'}++;
}
}
}
}
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'})
{
## Skip roles that have varients, since they're not used by themselves
if ( $TownRoles{$CheckRole}{'HasVarients'} =~ m/yes/i ) { next(); }
## If our role is a varient, we need to make sure we don't have too many varients already
if ( $TownRoles{$CheckRole}{'IsVarientOf'} )
{
my $BaseRole = $TownRoles{$CheckRole}{'IsVarientOf'};
if ( $TownRoles{$BaseRole}{'Current'} >= $TownRoles{$BaseRole}{'Max'} )
{
next();
}
}
if (&CheckRequire(\%TownRoles, $CheckRole) == 0) { next(); }
if (&CheckRestrict(\%TownRoles, $CheckRole) == 0) { next(); }
$TownRoles{$CheckRole}{'Current'}++;
$Role = $CheckRole;
$GameBalance+=$TownRoles{$Role}{'Weight'};
$RoleOk = 1;
if ( $TownRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $TownRoles{$Role}{'IsVarientOf'};
$TownRoles{$BaseRole}{'Current'}++;
}
}
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'};
$DoppBalance-=$DoppRoles{$Role}{'Weight'};
$DoppRoles{$OldRole}{'Current'}--;
if ( $DoppRoles{$OldRole}{'IsVarientOf'} )
{
my $BaseRole = $DoppRoles{$OldRole}{'IsVarientOf'};
$DoppRoles{$BaseRole}{'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'})
{
## Skip roles that have varients, since they're not used by themselves
if ( $DoppRoles{$CheckRole}{'HasVarients'} =~ m/yes/i ) { next(); }
## If our role is a varient, we need to make sure we don't have too many varients already
if ( $DoppRoles{$CheckRole}{'IsVarientOf'} )
{
my $BaseRole = $DoppRoles{$CheckRole}{'IsVarientOf'};
if ( $DoppRoles{$BaseRole}{'Current'} >= $DoppRoles{$BaseRole}{'Max'} )
{
next();
}
}
## Check for required roles
if (&CheckRequire(\%DoppRoles, $CheckRole) == 0) { next(); }
if (&CheckRestrict(\%DoppRoles, $CheckRole) == 0) { next(); }
print " debug: keeping $CheckRole (Has varients=$DoppRoles{$CheckRole}{'HasVarients'})\n";
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'};
$DoppBalance+=$DoppRoles{$Role}{'Weight'};
#if (! $DoppInvestigator and $Goal =~ m/find/i) { $DoppInvestigator = 1; }
if ( $DoppRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $DoppRoles{$Role}{'IsVarientOf'};
$DoppRoles{$BaseRole}{'Current'}++;
}
}
}
if ( $Checks > 30 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$DoppRoles{$Role}{'Weight'};
$DoppBalance+=$DoppRoles{$Role}{'Weight'};
$DoppRoles{$Role}{'Current'}++;
if ( $DoppRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $DoppRoles{$Role}{'IsVarientOf'};
$DoppRoles{$BaseRole}{'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'};
$CultBalance-=$CultRoles{$Role}{'Weight'};
$CultRoles{$OldRole}{'Current'}--;
if ( $CultRoles{$OldRole}{'IsVarientOf'} )
{
my $BaseRole = $CultRoles{$OldRole}{'IsVarientOf'};
$CultRoles{$BaseRole}{'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'})
{
## Skip roles that have varients, since they're not used by themselves
if ( $CultRoles{$CheckRole}{'HasVarients'} =~ m/yes/i ) { next(); }
## If our role is a varient, we need to make sure we don't have too many varients already
if ( $CultRoles{$CheckRole}{'IsVarientOf'} )
{
my $BaseRole = $CultRoles{$CheckRole}{'IsVarientOf'};
if ( $CultRoles{$BaseRole}{'Current'} >= $CultRoles{$BaseRole}{'Max'} )
{
next();
}
}
## Check for required roles
if (&CheckRequire(\%CultRoles, $CheckRole) == 0) { next(); }
if (&CheckRestrict(\%CultRoles, $CheckRole) == 0) { next(); }
print " debug: keeping $CheckRole (Has varients=$CultRoles{$CheckRole}{'HasVarients'})\n";
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'};
$CultBalance+=$CultRoles{$Role}{'Weight'};
#if (! $CultInvestigator and $Goal =~ m/find/i) { $CultInvestigator = 1; }
if ( $CultRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $CultRoles{$Role}{'IsVarientOf'};
$CultRoles{$BaseRole}{'Current'}++;
}
}
}
if ( $Checks > 30 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$CultRoles{$Role}{'Weight'};
$CultBalance+=$CultRoles{$Role}{'Weight'};
$CultRoles{$Role}{'Current'}++;
print "DEBUG: Checks got to $Checks\n";
if ( $CultRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $CultRoles{$Role}{'IsVarientOf'};
$CultRoles{$BaseRole}{'Current'}++;
}
}
}
}
}
else
{
my $RoleOk = 0;
my $LastOkRole = $OldRole;
$GameBalance-=$TownRoles{$OldRole}{'Weight'};
$TownRoles{$OldRole}{'Current'}--;
if ( $TownRoles{$OldRole}{'IsVarientOf'} )
{
my $BaseRole = $TownRoles{$OldRole}{'IsVarientOf'};
$TownRoles{$BaseRole}{'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'})
{
## Skip roles that have varients, since they're not used by themselves
if ( $TownRoles{$CheckRole}{'HasVarients'} =~ m/yes/i ) { next(); }
## If our role is a varient, we need to make sure we don't have too many varients already
if ( $TownRoles{$CheckRole}{'IsVarientOf'} )
{
my $BaseRole = $TownRoles{$CheckRole}{'IsVarientOf'};
if ( $TownRoles{$BaseRole}{'Current'} >= $TownRoles{$BaseRole}{'Max'} )
{
next();
}
}
if (&CheckRequire(\%TownRoles, $CheckRole) == 0) { next(); }
if (&CheckRestrict(\%TownRoles, $CheckRole) == 0) { next(); }
print " debug: keeping $CheckRole (Has varients=$TownRoles{$CheckRole}{'HasVarients'})\n";
if ( &BalancesPower($TownRoles{$CheckRole}{'Weight'},$TownRoles{$LastOkRole}{'Weight'}) )
{
$RoleOk = 1;
$TownRoles{$CheckRole}{'Current'}++;
$Role = $CheckRole;
$GameBalance+=$TownRoles{$Role}{'Weight'};
if ( $TownRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $TownRoles{$Role}{'IsVarientOf'};
$TownRoles{$BaseRole}{'Current'}++;
}
}
}
if ( $Checks > 30 )
{
if ( $RoleOk != 1 )
{
$RoleOk = 1;
$GameBalance+=$TownRoles{$Role}{'Weight'};
$TownRoles{$Role}{'Current'}++;
print "DEBUG: Checks got to $Checks\n";
if ( $TownRoles{$Role}{'IsVarientOf'} )
{
my $BaseRole = $TownRoles{$Role}{'IsVarientOf'};
$TownRoles{$BaseRole}{'Current'}++;
}
}
}
}
}
return $Role;
}
##----------------------------
sub GetGoal
{
my $Race = shift;
my $Role = shift;
if ($Race eq "Doppelganger" or $Race eq "Human Cultist")
{
$Goal = "${Race}s Win";
}
elsif ($Race eq "Alien")
{
$Goal = "Personal Victory";
}
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 (&CheckRequire(\%TownAbilities, $CheckAbility) == 0) { return $Ability; }
if (&CheckRestrict(\%TownAbilities, $CheckAbility) == 0) { return $Ability; }
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 (&CheckRequire(\%DoppAbilities, $CheckAbility) == 0) { return $Ability; }
if (&CheckRestrict(\%DoppAbilities, $CheckAbility) == 0) { return $Ability; }
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 (&CheckRequire(\%CultAbilities, $CheckAbility) == 0) { return $Ability; }
if (&CheckRestrict(\%CultAbilities, $CheckAbility) == 0) { return $Ability; }
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 (&CheckRequire(\%AlienAbilities, $CheckAbility) == 0) { return $Ability; }
if (&CheckRestrict(\%AlienAbilities, $CheckAbility) == 0) { return $Ability; }
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 $Race = shift;
my $ChangeOne = $GameBalance + $PowerOne;
my $ChangeTwo = $GameBalance + $PowerTwo;
my $ScumBalance = 1;
if ($DoppNum and $CultNum)
{
if ($Race eq 'Doppelganger')
{
my $OldDopp = $DoppBalance + $PowerOne;
my $NewDopp = $DoppBalance + $PowerTwo;
if ( ($CultBalance - $OldDopp) <= ($CultBalance - $NewDopp) )
{
$ScumBalance = 0;
}
}
elsif ($Race eq 'Human Cultist')
{
$OldCult = $CultBalance + $PowerOne;
$NewCult = $CultBalance + $PowerTwo;
if ( ($DoppBalance - $OldCult) <= ($DoppBalance - $NewCult) )
{
$ScumBalance = 0;
}
}
}
if ( abs($ChangeOne) <= abs($ChangeTwo) and $ScumBalance )
{
return 1;
}
else
{
return 0;
}
}
#-----------------------
sub CheckRequire
{
my $RoleHash_ref = shift;
my $Role = shift;
my $CheckOk = 1;
#print "DEBUG: $Role Req: $RoleHash_ref->{$Role}{'Requires'}\n";
if ($RoleHash_ref->{$Role}{'Requires'})
{
## Split on "," to get multiple requirements
my @Requires = split(",", $RoleHash_ref->{$Role}{'Requires'});
for (my $r = 0; $r < @Requires; $r++)
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $Requires[$r]);
if ($ReqRole =~ m/any/i)
{
if ($ReqRace =~ m/dopp/i and $DoppNum == 0) { $CheckOk = 0; }
## Any Alien needs to assume that the asker is alien right now, so make sure there are at least 2
## maybe bad logic, but even if there was another race looking, it'd be mean to have to restrict them to 1 player
elsif ($ReqRace =~ m/alien/i and $AlienNum < 2) { $CheckOk = 0; }
elsif ($ReqRace =~ m/cult/i and $CultNum == 0) { $CheckOk = 0; }
}
else
{
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} == 0) { $CheckOk = 0; }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} == 0) { $CheckOk = 0; }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} == 0) { $CheckOk = 0; }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} == 0) { $CheckOk = 0; }
}
}
}
return $CheckOk;
}
#-----------------------
sub CheckRestrict
{
my $RoleHash_ref = shift;
my $Role = shift;
my $CheckOk = 1;
#print "DEBUG: $Role Res: $RoleHash_ref->{$Role}{'Requires'}\n";
if ($RoleHash_ref->{$Role}{'Restricted'})
{
## Split on "," to get multiple requirements
my @Requires = split(",", $RoleHash_ref->{$Role}{'Restricted'});
for (my $r = 0; $r < @Requires; $r++)
{
## If we don't have the required race/role combo already, we find another role to use
my ($ReqRace, $ReqRole) = split("::", $Requires[$r]);
if ($ReqRole =~ m/any/i)
{
if ($ReqRace =~ m/dopp/i and $DoppNum > 0) { $CheckOk = 0; }
## Any Alien needs to assume that the asker is alien right now, so make sure there are at least 2
## maybe bad logic, but even if there was another race looking, it'd be mean to have to restrict them to 1 player
elsif ($ReqRace =~ m/alien/i and $AlienNum > 1) { $CheckOk = 0; }
elsif ($ReqRace =~ m/cult/i and $CultNum > 0) { $CheckOk = 0; }
}
else
{
if ($ReqRace =~ m/dopp/i and $DoppRoles{$ReqRole}{'Current'} > 0) { $CheckOk = 0; }
elsif ($ReqRace =~ m/town/i and $TownRoles{$ReqRole}{'Current'} > 0) { $CheckOk = 0; }
elsif ($ReqRace =~ m/alien/i and $AlienRoles{$ReqRole}{'Current'} > 0) { $CheckOk = 0; }
elsif ($ReqRace =~ m/cult/i and $CultRoles{$ReqRole}{'Current'} > 0) { $CheckOk = 0; }
}
}
}
return $CheckOk;
}
#-------------------------
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;
}