packages feed

werewolf 1.0.1.0 → 1.0.2.0

raw patch · 20 files changed

+318/−115 lines, 20 filesdep −tostringPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: tostring

API changes (from Hackage documentation)

- Game.Werewolf.Game: instance Data.String.ToString.ToString Game.Werewolf.Game.Stage
- Game.Werewolf.Player: filteredBy :: Eq b => Lens' a b -> b -> Traversal' a a
- Game.Werewolf.Player: is :: Getting Any s a -> s -> Bool
- Game.Werewolf.Player: isn't :: Getting All s a -> s -> Bool
- Game.Werewolf.Role: filteredBy :: Eq b => Lens' a b -> b -> Traversal' a a
- Game.Werewolf.Role: instance Data.String.ToString.ToString Game.Werewolf.Role.Allegiance
- Game.Werewolf.Role: is :: Getting Any s a -> s -> Bool
- Game.Werewolf.Role: isn't :: Getting All s a -> s -> Bool
+ Control.Lens.Extra: filteredBy :: Eq b => Lens' a b -> b -> Traversal' a a
+ Control.Lens.Extra: is :: Getting Any s a -> s -> Bool
+ Control.Lens.Extra: isn't :: Getting All s a -> s -> Bool
+ Data.String.Humanise: class Humanise a
+ Data.String.Humanise: humanise :: (Humanise a, IsString b) => a -> b
+ Game.Werewolf.Game: instance Data.String.Humanise.Humanise Game.Werewolf.Game.Stage
+ Game.Werewolf.Player: alphaWolf :: Traversal' Player ()
+ Game.Werewolf.Player: alphaWolves :: Traversable t => Traversal' (t Player) Player
+ Game.Werewolf.Player: beholder :: Traversal' Player ()
+ Game.Werewolf.Player: beholders :: Traversable t => Traversal' (t Player) Player
+ Game.Werewolf.Player: lycan :: Traversal' Player ()
+ Game.Werewolf.Player: lycans :: Traversable t => Traversal' (t Player) Player
+ Game.Werewolf.Role: alphaWolfRole :: Role
+ Game.Werewolf.Role: beholderRole :: Role
+ Game.Werewolf.Role: instance Data.String.Humanise.Humanise Game.Werewolf.Role.Allegiance
+ Game.Werewolf.Role: lycanRole :: Role

Files

CHANGELOG.md view
@@ -2,6 +2,18 @@  ### Upcoming +### v1.0.2.0++*Minor*++* Added the Alpha Wolf role. ([#149](https://github.com/hjwylde/werewolf/issues/149))+* Added the Beholder role. ([#168](https://github.com/hjwylde/werewolf/issues/168))+* Added the Lycan role. ([#169](https://github.com/hjwylde/werewolf/issues/169))++*Revisions*++* Moved Seer's player seen message to Sunrise. ([#184](https://github.com/hjwylde/werewolf/issues/184))+ ### v1.0.1.0  *Minor*
README.md view
@@ -24,7 +24,7 @@ For centuries no-one knew how to fight this scourge, however recently a theory has taken ahold that     mayhaps the Werewolves walk among the Villagers themselves... -Objective of the Game:  +Objective of the game:   For the Loners: complete their own objective.   For the Villagers: lynch all of the Werewolves.   For the Werewolves: devour all of the Villagers.@@ -59,10 +59,12 @@  The Villagers must lynch all of the Werewolves. +* Beholder * Crooked Senator * Druid * Hunter * Jester+* Lycan * Protector * Scapegoat * Seer@@ -76,6 +78,7 @@  The Werewolves must devour all of the Villagers. +* Alpha Wolf * Simple Werewolf  ### Installing
app/Werewolf/Command/Help.hs view
@@ -20,6 +20,7 @@ ) where  import Control.Lens+import Control.Lens.Extra import Control.Monad.Extra import Control.Monad.IO.Class 
+ src/Control/Lens/Extra.hs view
@@ -0,0 +1,41 @@+{-|+Module      : Control.Lens.Extra+Description : Extra utility functions for working with lenses.++Copyright   : (c) Henry J. Wylde, 2016+License     : BSD3+Maintainer  : public@hjwylde.com++Extra utility functions for working with lenses.+-}++{-# LANGUAGE Rank2Types #-}++module Control.Lens.Extra (+    -- * Folds+    is, isn't,++    -- * Traversals+    filteredBy,+) where++import Control.Lens hiding (isn't)++import Data.Monoid++-- | The counter-part to 'isn't', but more general as it takes a 'Getting' instead.+--+--   @'is' = 'has'@+is :: Getting Any s a -> s -> Bool+is = has++-- | A re-write of 'Control.Lens.Prism.isn't' to be more general by taking a 'Getting' instead.+--+--   @'isn't' = 'hasn't'@+isn't :: Getting All s a -> s -> Bool+isn't = hasn't++-- | A companion to 'filtered' that, rather than using a predicate, filters on the given lens for+-- matches.+filteredBy :: Eq b => Lens' a b -> b -> Traversal' a a+filteredBy lens value = filtered ((value ==) . view lens)
+ src/Data/String/Humanise.hs view
@@ -0,0 +1,20 @@+{-|+Module      : Data.String.Humanise+Description : Humanise type class for pretty printing data structures.++Copyright   : (c) Henry J. Wylde, 2016+License     : BSD3+Maintainer  : public@hjwylde.com++Humanise type class for displaying data structures to a human.+-}++module Data.String.Humanise (+    -- * Humanise+    Humanise(..),+) where++import Data.String++class Humanise a where+    humanise :: IsString b => a -> b
src/Game/Werewolf/Engine.hs view
@@ -22,10 +22,11 @@ ) where  import Control.Lens         hiding (cons, isn't)+import Control.Lens.Extra import Control.Monad.Except import Control.Monad.Extra import Control.Monad.Random-import Control.Monad.State  hiding (state)+import Control.Monad.State import Control.Monad.Writer  import           Data.List.Extra@@ -70,9 +71,9 @@ checkStage' = use stage >>= \stage' -> case stage' of     FerinasGrunt -> do         druid       <- findPlayerBy_ role druidRole-        players'    <- getAdjacentAlivePlayers (druid ^. name)+        players'    <- filter (isn't alphaWolf) <$> getAdjacentAlivePlayers (druid ^. name) -        when (has werewolves players') $ tell [ferinaGruntsMessage]+        when (has werewolves players' || has lycans players') $ tell [ferinaGruntsMessage]          advanceStage @@ -113,13 +114,7 @@     SeersTurn -> do         whenM (has (players . seers . dead) <$> get) advanceStage -        whenJustM (use see) $ \targetName -> do-            seer    <- findPlayerBy_ role seerRole-            target  <- findPlayerBy_ name targetName--            tell [playerSeenMessage (seer ^. name) target]--            advanceStage+        whenM (isJust <$> use see) advanceStage      Sunrise -> do         round += 1@@ -130,6 +125,13 @@                  setPlayerAllegiance (fallenAngel ^. name) Villagers +        whenJustM (preuse $ players . seers . alive) $ \seer -> do+            target <- use see >>= findPlayerBy_ name . fromJust++            when (is alive target) $ tell [playerSeenMessage (seer ^. name) target]++        see .= Nothing+         advanceStage      Sunset -> do@@ -221,7 +223,6 @@     stage   .= nextStage     boots   .= Map.empty     passed  .= False-    see     .= Nothing      tell . stageMessages =<< get 
src/Game/Werewolf/Game.hs view
@@ -46,13 +46,15 @@     hasAnyoneWon, hasFallenAngelWon, hasVillagersWon, hasWerewolvesWon, ) where -import Control.Lens hiding (isn't)+import Control.Lens       hiding (isn't)+import Control.Lens.Extra  import           Data.List.Extra import           Data.Map             (Map) import qualified Data.Map             as Map import           Data.Maybe-import           Data.String.ToString+import           Data.String+import           Data.String.Humanise import           Data.Text            (Text)  import Game.Werewolf.Player@@ -114,22 +116,22 @@             | VillagesTurn | WerewolvesTurn | WitchsTurn     deriving (Eq, Read, Show) -instance ToString Stage where-    toString FerinasGrunt       = "Ferina's Grunt"-    toString GameOver           = "Game over"-    toString HuntersTurn1       = "Hunter's turn"-    toString HuntersTurn2       = "Hunter's turn"-    toString Lynching           = "Lynching"-    toString OrphansTurn        = "Orphan's turn"-    toString ProtectorsTurn     = "Protector's turn"-    toString ScapegoatsTurn     = "Scapegoat's turn"-    toString SeersTurn          = "Seer's turn"-    toString Sunrise            = "Sunrise"-    toString Sunset             = "Sunset"-    toString VillageDrunksTurn  = "Village Drunk's turn"-    toString VillagesTurn       = "village's turn"-    toString WerewolvesTurn     = "Werewolves' turn"-    toString WitchsTurn         = "Witch's turn"+instance Humanise Stage where+    humanise FerinasGrunt       = fromString "Ferina's Grunt"+    humanise GameOver           = fromString "Game over"+    humanise HuntersTurn1       = fromString "Hunter's turn"+    humanise HuntersTurn2       = fromString "Hunter's turn"+    humanise Lynching           = fromString "Lynching"+    humanise OrphansTurn        = fromString "Orphan's turn"+    humanise ProtectorsTurn     = fromString "Protector's turn"+    humanise ScapegoatsTurn     = fromString "Scapegoat's turn"+    humanise SeersTurn          = fromString "Seer's turn"+    humanise Sunrise            = fromString "Sunrise"+    humanise Sunset             = fromString "Sunset"+    humanise VillageDrunksTurn  = fromString "Village Drunk's turn"+    humanise VillagesTurn       = fromString "village's turn"+    humanise WerewolvesTurn     = fromString "Werewolves' turn"+    humanise WitchsTurn         = fromString "Witch's turn"  -- TODO (hjw): remove events -- | Events occur /after/ a 'Stage' is advanced. This is automatically handled in
src/Game/Werewolf/Messages.hs view
@@ -94,9 +94,10 @@  import Control.Arrow import Control.Lens+import Control.Lens.Extra  import           Data.List.Extra-import           Data.String.ToString+import           Data.String.Humanise import           Data.Text            (Text) import qualified Data.Text            as T @@ -111,11 +112,15 @@     [ [newPlayersInGameMessage $ players' ^.. names]     , [rolesInGameMessage Nothing $ players' ^.. roles]     , map newPlayerMessage players'+    , beholderMessages     , trueVillagerMessages     , stageMessages game     ]     where         players'                = game ^. players+        beholderMessages        = case (,) <$> players' ^? beholders <*> players' ^? seers of+            Just (beholder, seer)   -> [beholderMessage (beholder ^. name) (seer ^. name)]+            _                       -> []         trueVillagerMessages    = case players' ^? trueVillagers of             Just trueVillager   -> [trueVillagerMessage $ trueVillager ^. name]             _                   -> []@@ -133,6 +138,12 @@     where         playerRole = player ^. role +beholderMessage :: Text -> Text -> Message+beholderMessage to seerName = privateMessage to $ T.concat+    [ "The Seer has always been held in high regard among the Villagers. Few are as lucky as you to"+    , " know the Seer, ", seerName, ", personally."+    ]+ trueVillagerMessage :: Text -> Message trueVillagerMessage name = publicMessage $ T.unwords     [ "Unguarded advice is seldom given, for advice is a dangerous gift, even from the wise to the"@@ -386,7 +397,7 @@ currentStageMessages _ Sunrise      = [] currentStageMessages _ Sunset       = [] currentStageMessages to turn        = [privateMessage to $ T.concat-    [ "It's currently the ", T.pack $ toString turn, "."+    [ "It's currently the ", humanise turn, "."     ]]  rolesInGameMessage :: Maybe Text -> [Role] -> Message@@ -475,10 +486,13 @@  playerSeenMessage :: Text -> Player -> Message playerSeenMessage to target = privateMessage to $ T.concat-    [targetName, " is aligned with ", article, T.pack $ toString allegiance', "."]+    [targetName, " is aligned with ", article, humanise allegiance', "."]     where         targetName  = target ^. name-        allegiance' = target ^. role . allegiance+        allegiance'+            | is alphaWolf target   = Villagers+            | is lycan target       = Werewolves+            | otherwise             = target ^. role . allegiance         article     = if allegiance' == NoOne then "" else "the "  villageDrunkJoinedVillageMessage :: Text -> Message@@ -506,7 +520,8 @@  playerLynchedMessage :: Player -> Message playerLynchedMessage player-    | is simpleWerewolf player  = publicMessage $ T.concat+    | is simpleWerewolf player+        || is alphaWolf player  = publicMessage $ T.concat         [ playerName, " is tied up to a pyre and set alight. As they scream their body starts to "         , "contort and writhe, transforming into ", article playerRole, " "         , playerRole ^. Role.name, ".", " Thankfully they go limp before breaking free of their "
src/Game/Werewolf/Player.hs view
@@ -10,10 +10,9 @@ behaviour is handled in "Game.Werewolf.Command" and "Game.Werewolf.Engine". -} -{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE Rank2Types            #-}-{-# LANGUAGE TemplateHaskell       #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE Rank2Types       #-}+{-# LANGUAGE TemplateHaskell  #-}  module Game.Werewolf.Player (     -- * Player@@ -26,24 +25,23 @@     newPlayer,      -- ** Traversals-    crookedSenator, druid, fallenAngel, hunter, jester, orphan, protector, scapegoat, seer,-    simpleVillager, simpleWerewolf, trueVillager, villageDrunk, witch,+    alphaWolf, beholder, crookedSenator, druid, fallenAngel, hunter, jester, lycan, orphan,+    protector, scapegoat, seer, simpleVillager, simpleWerewolf, trueVillager, villageDrunk, witch,     villager, werewolf,      -- | These are provided just as a bit of sugar to avoid continually writing @'traverse' .@.     names, roles, states,      -- | N.B., these are not legal traversals for the same reason 'filtered' isn't!-    crookedSenators, druids, fallenAngels, hunters, jesters, orphans, protectors, scapegoats,-    seers, simpleVillagers, simpleWerewolves, trueVillagers, villageDrunks, witches,+    alphaWolves, beholders, crookedSenators, druids, fallenAngels, hunters, jesters, lycans,+    orphans, protectors, scapegoats, seers, simpleVillagers, simpleWerewolves, trueVillagers,+    villageDrunks, witches,     villagers, werewolves,     alive, dead,--    -- * Utility functions-    is, isn't, filteredBy, ) where -import Control.Lens hiding (isn't)+import Control.Lens       hiding (isn't)+import Control.Lens.Extra  import Data.Function import Data.Text     (Text)@@ -75,6 +73,22 @@ newPlayer :: Text -> Role -> Player newPlayer name role = Player name role Alive +-- | The traversal of 'Player's with a 'alphaWolfRole'.+--+-- @+-- 'alphaWolf' = 'role' . 'only' 'alphaWolfRole'+-- @+alphaWolf :: Traversal' Player ()+alphaWolf = role . only alphaWolfRole++-- | The traversal of 'Player's with a 'beholderRole'.+--+-- @+-- 'beholder' = 'role' . 'only' 'beholderRole'+-- @+beholder :: Traversal' Player ()+beholder = role . only beholderRole+ -- | The traversal of 'Player's with a 'crookedSenatorRole'. -- -- @@@ -115,6 +129,14 @@ jester :: Traversal' Player () jester = role . only jesterRole +-- | The traversal of 'Player's with a 'lycanRole'.+--+-- @+-- 'lycan' = 'role' . 'only' 'lycanRole'+-- @+lycan :: Traversal' Player ()+lycan = role . only lycanRole+ -- | The traversal of 'Player's with a 'orphanRole'. -- -- @@@ -227,6 +249,22 @@ states :: Traversable t => Traversal' (t Player) State states = traverse . state +-- | This 'Traversal' provides the traversal of 'alphaWolf' 'Player's.+--+-- @+-- 'alphaWolves' = 'traverse' . 'filtered' ('is' 'alphaWolf')+-- @+alphaWolves :: Traversable t => Traversal' (t Player) Player+alphaWolves = traverse . filtered (is alphaWolf)++-- | This 'Traversal' provides the traversal of 'beholder' 'Player's.+--+-- @+-- 'beholders' = 'traverse' . 'filtered' ('is' 'beholder')+-- @+beholders :: Traversable t => Traversal' (t Player) Player+beholders = traverse . filtered (is beholder)+ -- | This 'Traversal' provides the traversal of 'crookedSenator' 'Player's. -- -- @@@ -266,6 +304,14 @@ -- @ jesters :: Traversable t => Traversal' (t Player) Player jesters = traverse . filtered (is jester)++-- | This 'Traversal' provides the traversal of 'lycan' 'Player's.+--+-- @+-- 'lycans' = 'traverse' . 'filtered' ('is' 'lycan')+-- @+lycans :: Traversable t => Traversal' (t Player) Player+lycans = traverse . filtered (is lycan)  -- | This 'Traversal' provides the traversal of 'orphan' 'Player's. --
src/Game/Werewolf/Role.hs view
@@ -47,25 +47,22 @@     --   certain few have learnt some tricks over the years that may turn out rather useful.      --   The Villagers must lynch all of the Werewolves.-    crookedSenatorRole, druidRole, hunterRole, jesterRole, protectorRole, scapegoatRole, seerRole,-    simpleVillagerRole, trueVillagerRole, witchRole,+    beholderRole, crookedSenatorRole, druidRole, hunterRole, jesterRole, lycanRole, protectorRole,+    scapegoatRole, seerRole, simpleVillagerRole, trueVillagerRole, witchRole,      -- *** The Werewolves     -- | Hiding in plain sight, the Werewolves are not a small trifle.      --   The Werewolves must devour all of the Villagers.-    simpleWerewolfRole,--    -- * Utility functions-    is, isn't, filteredBy,+    alphaWolfRole, simpleWerewolfRole, ) where -import Control.Lens hiding (isn't)+import Control.Lens  import           Data.Function import           Data.List-import           Data.Monoid-import           Data.String.ToString+import           Data.String+import           Data.String.Humanise import           Data.Text            (Text) import qualified Data.Text            as T @@ -92,10 +89,10 @@ data Allegiance = NoOne | Villagers | Werewolves     deriving (Eq, Read, Show) -instance ToString Allegiance where-    toString NoOne      = "no-one"-    toString Villagers  = "Villagers"-    toString Werewolves = "Werewolves"+instance Humanise Allegiance where+    humanise NoOne      = fromString "no-one"+    humanise Villagers  = fromString "Villagers"+    humanise Werewolves = fromString "Werewolves"  makeLenses ''Role @@ -107,11 +104,14 @@ -- | A list containing all the roles defined in this file. allRoles :: [Role] allRoles =-    [ crookedSenatorRole+    [ alphaWolfRole+    , beholderRole+    , crookedSenatorRole     , druidRole     , fallenAngelRole     , hunterRole     , jesterRole+    , lycanRole     , orphanRole     , protectorRole     , scapegoatRole@@ -228,12 +228,32 @@         ]     } +-- | /Awareness comes easy to the Beholder. They listen to their senses and trust their hunches./+--   /Over the years the Beholder has grown to know a certain few of the village just by paying/+--   /attention. Little cues here and there, the way someone talks, the way they move - it all/+--   /gives clues as to their true nature and role./+--+--   At the start of the game the Beholder is informed the Seer's identity.+beholderRole :: Role+beholderRole = Role+    { _name         = "Beholder"+    , _allegiance   = Villagers+    , _balance      = 2+    , _description  = T.unwords+        [ "Awareness comes easy to the Beholder. They listen to their senses and trust their"+        , "hunches. Over the years the Beholder has grown to know a certain few of the village just"+        , "by paying attention. Little cues here and there, the way someone talks, the way they"+        , "move - it all gives clues as to their true nature and role."+        ]+    , _rules        = "At the start of the game the Beholder is informed the Seer's identity."+    }+ -- | /Never trust a politician. Nor a Crooked Senator for that matter. The Crooked Senator may seem/ --   /like he has the village's best interests at heart, but let's be honest, when put in a tough/ --   /situation he looks after no-one but himself. Even when safe, the Crooked Senator may decide/ --   /to toy with the Villagers' emotions and try pit them against one another./ -----   The Crooked Senator looks at the Villager votes as they come in.+--   The Crooked Senator looks at the village votes as they come in. crookedSenatorRole :: Role crookedSenatorRole = Role     { _name         = "Crooked Senator"@@ -245,7 +265,7 @@         , "a tough situation he looks after no-one but himself. Even when safe, the Crooked Senator"         , "may decide to toy with the Villagers' emotions and try pit them against one another."         ]-    , _rules        = "The Crooked Senator looks at the Villager votes as they come in."+    , _rules        = "The Crooked Senator looks at the village votes as they come in."     }  -- | /How honoured we are to be in the presence of such a noble leader. The return of the Druid/@@ -297,6 +317,57 @@         ]     } +-- | /Every village needs a Jester; they're so stupid, but provide so much entertainment! The/+--   /Jester may not have any special abilities, but at least no-one in the village wants to hurt/+--   /them./+--+--   If the village votes to lynch the Jester, their identity is revealed. The village realise+--   there's no point in burning them and so they are set free.+--+--   The Jester continues to play but may no longer vote as no-one can take them seriously.+jesterRole :: Role+jesterRole = Role+    { _name         = "Jester"+    , _allegiance   = Villagers+    , _balance      = 0+    , _description  = T.unwords+        [ "Every village needs a Jester; they're so stupid, but provide so much entertainment! The"+        , "Jester may not have any special abilities, but at least no-one in the village wants to"+        , "hurt them."+        ]+    , _rules        = T.intercalate "\n"+        [ T.unwords+            [ "If the village votes to lynch the Jester, their identity is revealed. The village"+            , "realise there's no point in burning them and so they are set free."+            ]+        , "The Jester continues to play but may no longer vote as no-one can take them seriously."+        ]+    }++-- | /Traditionally a Werewolf once transformed loses all memories and personality. Over years of/+--   /transforming, the Lycan has slowly evolved and learnt how to retain themself. Night after/+--   /night of devouring with the other Werewolves took its toll. The screams alone were enough to/+--   /turn the Lycan and make them question their true nature./+--+--   The Lycan is aligned with the Villagers, but appears to nature-seeing roles (e.g., the Seer) as+--   a Werewolf.+lycanRole :: Role+lycanRole = Role+    { _name         = "Lycan"+    , _allegiance   = Villagers+    , _balance      = 0+    , _description  = T.unwords+        [ "Traditionally a Werewolf once transformed loses all memories and personality. Over years"+        , "of transforming, the Lycan has slowly evolved and learnt how to retain themself. Night"+        , "after night of devouring with the other Werewolves took its toll. The screams alone were"+        , "enough to turn the Lycan and make them question their true nature."+        ]+    , _rules        = T.unwords+        [ "The Lycan is aligned with the Villagers, but appears to nature-seeing roles (e.g., the"+        , "Seer) as a Werewolf."+        ]+    }+ -- | /The Protector is one of the few pure of heart and altruistic Villagers; they are forever/ --   /putting others needs above their own. Each night they fight against the Werewolves with/ --   /naught but a sword and shield, potentially saving an innocents life./@@ -396,33 +467,6 @@         ]     } --- | /Every village needs a Jester; they're so stupid, but provide so much entertainment! The/---   /Jester may not have any special abilities, but at least no-one in the village wants to hurt/---   /them./------   If the village votes to lynch the Jester, their identity is revealed. The village realise---   there's no point in burning them and so they are set free.------   The Jester continues to play but may no longer vote as no-one can take them seriously.-jesterRole :: Role-jesterRole = Role-    { _name         = "Jester"-    , _allegiance   = Villagers-    , _balance      = 0-    , _description  = T.unwords-        [ "Every village needs a Jester; they're so stupid, but provide so much entertainment! The"-        , "Jester may not have any special abilities, but at least no-one in the village wants to"-        , "hurt them."-        ]-    , _rules        = T.intercalate "\n"-        [ T.unwords-            [ "If the village votes to lynch the Jester, their identity is revealed. The village"-            , "realise there's no point in burning them and so they are set free."-            ]-        , "The Jester continues to play but may no longer vote as no-one can take them seriously."-        ]-    }- -- | /The True Villager has a heart and soul as clear as day! Their allegiance and devotion to the/ --   /village are beyond reproach. If there is one person whom you should confide in, listen to and/ --   /trust, it is the True Villager./@@ -467,6 +511,27 @@         ]     } +-- | /The Alpha Wolf leads the Werewolves in the raids against Fougères each night and not even the/+--   /Seer can see them coming. If the Werewolves caused the Villagers to question and accuse one/+--   /another beforehand, the Alpha Wolf eliminates any shred of humanity left. No-one can be/+--   /trusted anymore and no-one knows the truth./+--+--   The Alpha Wolf appears to nature-seeing roles (e.g., the Seer) as a Villager.+alphaWolfRole :: Role+alphaWolfRole = Role+    { _name         = "Alpha Wolf"+    , _allegiance   = Werewolves+    , _balance      = -5+    , _description  = T.unwords+        [ "The Alpha Wolf leads the Werewolves in the raids against Fougères each night and not"+        , "even the Seer can see them coming. If the Werewolves caused the Villagers to question"+        , "and accuse one another beforehand, the Alpha Wolf eliminates any shred of humanity left."+        , "No-one can be trusted anymore and no-one knows the truth."+        ]+    , _rules        =+        "The Alpha Wolf appears to nature-seeing roles (e.g., the Seer) as a Villager."+    }+ -- | /The Simple Werewolf is a fearsome lupine, cunning like no other creature that roams the/ --   /forest. Their origin is unknown, but that matters little, for they present a grave threat to/ --   /Fougères. While each day they hide in plain sight as an ordinary Villager, each night they/@@ -487,16 +552,3 @@         ]     , _rules        = "A Werewolf may never devour another Werewolf."     }---- | The counter-part to 'isn't', but more general as it takes a 'Getting' instead.-is :: Getting Any s a -> s -> Bool-is = has---- | A re-write of 'Control.Lens.Prism.isn't' to be more general by taking a 'Getting' instead.-isn't :: Getting All s a -> s -> Bool-isn't = hasn't---- | A companion to 'filtered' that, rather than using a predicate, filters on the given lens for--- matches.-filteredBy :: Eq b => Lens' a b -> b -> Traversal' a a-filteredBy lens value = filtered ((value ==) . view lens)
src/Game/Werewolf/Util.hs view
@@ -38,10 +38,11 @@     isPlayerAlive, isPlayerDead, ) where -import Control.Lens         hiding (cons)+import Control.Lens+import Control.Lens.Extra import Control.Monad.Extra import Control.Monad.Random-import Control.Monad.State  hiding (state)+import Control.Monad.State  import           Data.List import qualified Data.Map   as Map
test/src/Game/Werewolf/Test/Arbitrary.hs view
@@ -36,7 +36,8 @@     arbitraryPlayer, arbitraryWerewolf, ) where -import Control.Lens hiding (elements, isn't)+import Control.Lens       hiding (elements, isn't)+import Control.Lens.Extra  import           Data.List.Extra import           Data.Maybe
test/src/Game/Werewolf/Test/Command/Choose.hs view
@@ -12,7 +12,8 @@     allChooseCommandTests, ) where -import Control.Lens hiding (elements, isn't)+import Control.Lens       hiding (elements, isn't)+import Control.Lens.Extra  import Game.Werewolf import Game.Werewolf.Command.Hunter    as Hunter
test/src/Game/Werewolf/Test/Command/Heal.hs view
@@ -10,7 +10,8 @@     allHealCommandTests, ) where -import Control.Lens hiding (isn't)+import Control.Lens       hiding (isn't)+import Control.Lens.Extra  import Game.Werewolf import Game.Werewolf.Command.Witch
test/src/Game/Werewolf/Test/Command/Poison.hs view
@@ -10,7 +10,8 @@     allPoisonCommandTests, ) where -import Control.Lens hiding (isn't)+import Control.Lens       hiding (isn't)+import Control.Lens.Extra  import Game.Werewolf import Game.Werewolf.Command.Witch
test/src/Game/Werewolf/Test/Command/Protect.hs view
@@ -10,7 +10,8 @@     allProtectCommandTests, ) where -import Control.Lens hiding (isn't)+import Control.Lens       hiding (isn't)+import Control.Lens.Extra  import Data.Maybe 
test/src/Game/Werewolf/Test/Command/See.hs view
@@ -10,7 +10,8 @@     allSeeCommandTests, ) where -import Control.Lens hiding (isn't)+import Control.Lens       hiding (isn't)+import Control.Lens.Extra  import Game.Werewolf import Game.Werewolf.Command.Seer
test/src/Game/Werewolf/Test/Command/Vote.hs view
@@ -10,7 +10,8 @@     allVoteCommandTests, ) where -import Control.Lens hiding (isn't)+import Control.Lens       hiding (isn't)+import Control.Lens.Extra  import Game.Werewolf import Game.Werewolf.Command.Villager as Villager
test/src/Game/Werewolf/Test/Engine.hs view
@@ -13,6 +13,7 @@ ) where  import Control.Lens         hiding (elements)+import Control.Lens.Extra import Control.Monad.Except import Control.Monad.Writer @@ -40,7 +41,7 @@         players' = game ^. players  prop_startGameErrorsWhenLessThan7Players :: [Player] -> Property-prop_startGameErrorsWhenLessThan7Players players =+prop_startGameErrorsWhenLessThan7Players players = once $     length players < 7     ==> isLeft . runExcept . runWriterT $ startGame "" players 
werewolf.cabal view
@@ -1,5 +1,5 @@ name:           werewolf-version:        1.0.1.0+version:        1.0.2.0  author:         Henry J. Wylde maintainer:     public@hjwylde.com@@ -75,6 +75,8 @@ library     hs-source-dirs: src/     exposed-modules:+        Control.Lens.Extra+        Data.String.Humanise         Game.Werewolf         Game.Werewolf.Command         Game.Werewolf.Command.Global@@ -116,7 +118,6 @@         MonadRandom == 0.4.*,         mtl == 2.2.*,         text == 1.2.*,-        tostring == 0.2.*,         transformers == 0.4.*  test-suite werewolf-test