packages feed

werewolf 1.4.0.1 → 1.5.0.0

raw patch · 32 files changed

+321/−138 lines, 32 files

Files

CHANGELOG.md view
@@ -7,6 +7,22 @@  ### Upcoming +### v1.5.0.0++*Major*++* Changed name of Spiteful Villagers variant to Spiteful village. ([#242](https://github.com/hjwylde/werewolf/issues/242))++*Minor*++* Added in a `variants` help subcommand. ([#227](https://github.com/hjwylde/werewolf/issues/227))++*Revisions*++* Fixed Jester lynched message to be gender neutral. ([#248](https://github.com/hjwylde/werewolf/issues/248))+* Fixed Medusa description to be gender neutral. ([#247](https://github.com/hjwylde/werewolf/issues/247))+* Pulled variant information out into external text files. ([#242](https://github.com/hjwylde/werewolf/issues/242))+ ### v1.4.0.1  *Revisions*
README.md view
@@ -94,7 +94,7 @@ * Standard * No role knowledge (players are not informed of the roles in play at the start of a game) * No role reveal (player roles are not revealed upon death)-* Spiteful Villagers (the default Villager role becomes the Spiteful Villager)+* Spiteful village (the default Villager role becomes the Spiteful Villager)  ### Installing 
app/Game/Werewolf/Message/Command.hs view
@@ -31,7 +31,7 @@     necromancerCommandsMessage, oracleCommandsMessage, orphanCommandsMessage,     protectorCommandsMessage, roleMessage, rulesMessage, scapegoatCommandsMessage,     seerCommandsMessage, stagesMessage, standardCommandsMessage, statusCommandsMessage,-    witchCommandsMessage,+    variantMessage, witchCommandsMessage,      -- * Ping     pingDiurnalRoleMessage, pingNocturnalRoleMessage, pingPlayerMessage, pingVillageMessage,@@ -64,14 +64,15 @@ import Game.Werewolf.Player import Game.Werewolf.Response import Game.Werewolf.Role                            hiding (name)+import Game.Werewolf.Variant                         hiding (name) import Game.Werewolf.Variant.NoRoleKnowledge.Command as NoRoleKnowledge import Game.Werewolf.Variant.NoRoleReveal.Command    as NoRoleReveal import Game.Werewolf.Variant.Standard.Command        as Standard  playerQuitMessage :: Player -> Game -> Message playerQuitMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.callerQuitText player-    | otherwise                             = publicMessage $ Standard.callerQuitText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.callerQuitText player+    | otherwise                         = publicMessage $ Standard.callerQuitText player  playerVotedToBootMessage :: Player -> Player -> Message playerVotedToBootMessage caller = publicMessage . callerVotedBootText caller@@ -81,8 +82,8 @@  playerShotMessage :: Player -> Game -> Message playerShotMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.playerShotText player-    | otherwise                             = publicMessage $ Standard.playerShotText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerShotText player+    | otherwise                         = publicMessage $ Standard.playerShotText player  gameEndedMessage :: Text -> Message gameEndedMessage = publicMessage . gameEndedText@@ -161,6 +162,9 @@ statusCommandsMessage :: Text -> Message statusCommandsMessage to = privateMessage to statusCommandsText +variantMessage :: Text -> Variant -> Message+variantMessage to = privateMessage to . variantDescriptionText+ witchCommandsMessage :: Text -> Message witchCommandsMessage to = privateMessage to witchCommandsText @@ -169,8 +173,8 @@  pingNocturnalRoleMessage :: Role -> Game -> Message pingNocturnalRoleMessage role game-    | has (variant . _NoRoleKnowledge) game = publicMessage $ NoRoleKnowledge.nocturnalRolePingedText role-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.nocturnalRolePingedText role+    | has (variant . noRoleKnowledge) game  = publicMessage $ NoRoleKnowledge.nocturnalRolePingedText role+    | has (variant . noRoleReveal) game     = publicMessage $ NoRoleReveal.nocturnalRolePingedText role     | otherwise                             = publicMessage $ Standard.nocturnalRolePingedText role  pingPlayerMessage :: Text -> Message@@ -181,8 +185,8 @@  pingWerewolvesMessage :: Game -> Message pingWerewolvesMessage game-    | has (variant . _NoRoleKnowledge) game = publicMessage NoRoleKnowledge.werewolvesPingedText-    | has (variant . _NoRoleReveal) game    = publicMessage NoRoleReveal.werewolvesPingedText+    | has (variant . noRoleKnowledge) game  = publicMessage NoRoleKnowledge.werewolvesPingedText+    | has (variant . noRoleReveal) game     = publicMessage NoRoleReveal.werewolvesPingedText     | otherwise                             = publicMessage Standard.werewolvesPingedText  deadRaisedMessages :: Game -> [Message]@@ -203,8 +207,8 @@  currentNocturnalTurnMessage :: Text -> Game -> Message currentNocturnalTurnMessage to game-    | has (variant . _NoRoleKnowledge) game = privateMessage to $ NoRoleKnowledge.currentNocturnalTurnText game-    | has (variant . _NoRoleReveal) game    = privateMessage to $ NoRoleReveal.currentNocturnalTurnText game+    | has (variant . noRoleKnowledge) game  = privateMessage to $ NoRoleKnowledge.currentNocturnalTurnText game+    | has (variant . noRoleReveal) game     = privateMessage to $ NoRoleReveal.currentNocturnalTurnText game     | otherwise                             = privateMessage to $ Standard.currentNocturnalTurnText game  gameIsOverMessage :: Text -> Message@@ -219,7 +223,7 @@         alivePlayersText' = alivePlayersText game         deadPlayersText'             | hasn't (players . traverse . dead) game   = T.empty-            | has (variant . _NoRoleReveal) game        = NoRoleReveal.deadPlayersText game+            | has (variant . noRoleReveal) game         = NoRoleReveal.deadPlayersText game             | otherwise                                 = Standard.deadPlayersText game  playerRescindedVoteMessage :: Text -> Player -> Message
app/Game/Werewolf/Message/Engine.hs view
@@ -35,14 +35,15 @@ import Game.Werewolf.Player import Game.Werewolf.Response import Game.Werewolf.Role                           hiding (name)+import Game.Werewolf.Variant                        hiding (name) import Game.Werewolf.Variant.NoRoleKnowledge.Engine as NoRoleKnowledge import Game.Werewolf.Variant.NoRoleReveal.Engine    as NoRoleReveal import Game.Werewolf.Variant.Standard.Engine        as Standard  playerBootedMessage :: Player -> Game -> Message playerBootedMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.playerBootedText player-    | otherwise                             = publicMessage $ Standard.playerBootedText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerBootedText player+    | otherwise                         = publicMessage $ Standard.playerBootedText player  gameOverMessages :: Game -> [Message] gameOverMessages game@@ -127,7 +128,7 @@         players'                = game ^. players         gameVariantMessages     =             [ gameVariantMessage game-            | hasn't (variant . _Standard) game+            | hasn't (variant . standard) game             ]         beholderMessages        =             [ beholderMessage beholderName game@@ -153,7 +154,7 @@  rolesInGameMessage :: Maybe Text -> Game -> Message rolesInGameMessage mTo game-    | has (variant . _NoRoleKnowledge) game = Message mTo $ NoRoleKnowledge.rolesInGameText game+    | has (variant . noRoleKnowledge) game  = Message mTo $ NoRoleKnowledge.rolesInGameText game     | otherwise                             = Message mTo $ Standard.rolesInGameText game  newPlayerMessage :: Player -> Message@@ -167,8 +168,8 @@  spitefulVillagerKilledMessage :: Text -> Game -> Message spitefulVillagerKilledMessage to game-    | has (variant . _NoRoleReveal) game    = privateMessage to $ NoRoleReveal.spitefulVillagerKilledText game-    | otherwise                             = privateMessage to $ Standard.spitefulVillagerKilledText game+    | has (variant . noRoleReveal) game = privateMessage to $ NoRoleReveal.spitefulVillagerKilledText game+    | otherwise                         = privateMessage to $ Standard.spitefulVillagerKilledText game  trueVillagerMessage :: Game -> Message trueVillagerMessage = publicMessage . trueVillagerText@@ -213,9 +214,9 @@  necromancersTurnMessages :: Text -> Game -> [Message] necromancersTurnMessages to game-    | has (variant . _NoRoleKnowledge) game =+    | has (variant . noRoleKnowledge) game  =         [ privateMessage to necromancersTurnPrivateText ]-    | has (variant . _NoRoleReveal) game    =+    | has (variant . noRoleReveal) game     =         [ privateMessage to necromancersTurnPrivateText ]     | otherwise                             =         [ publicMessage necromancersTurnPublicText@@ -224,9 +225,9 @@  oraclesTurnMessages :: Text -> Game -> [Message] oraclesTurnMessages to game-    | has (variant . _NoRoleKnowledge) game =+    | has (variant . noRoleKnowledge) game  =         [ privateMessage to oraclesTurnPrivateText ]-    | has (variant . _NoRoleReveal) game    =+    | has (variant . noRoleReveal) game     =         [ privateMessage to oraclesTurnPrivateText ]     | otherwise                             =         [ publicMessage oraclesTurnPublicText@@ -235,9 +236,9 @@  orphansTurnMessages :: Text -> Game -> [Message] orphansTurnMessages to game-    | has (variant . _NoRoleKnowledge) game =+    | has (variant . noRoleKnowledge) game  =         [ privateMessage to orphansTurnPrivateText ]-    | has (variant . _NoRoleReveal) game    =+    | has (variant . noRoleReveal) game     =         [ privateMessage to orphansTurnPrivateText ]     | otherwise                             =         [ publicMessage orphansTurnPublicText@@ -246,9 +247,9 @@  protectorsTurnMessages :: Text -> Game -> [Message] protectorsTurnMessages to game-    | has (variant . _NoRoleKnowledge) game =+    | has (variant . noRoleKnowledge) game  =         [ privateMessage to protectorsTurnPrivateText ]-    | has (variant . _NoRoleReveal) game    =+    | has (variant . noRoleReveal) game     =         [ privateMessage to protectorsTurnPrivateText ]     | otherwise                             =         [ publicMessage protectorsTurnPublicText@@ -260,9 +261,9 @@  seersTurnMessages :: Text -> Game -> [Message] seersTurnMessages to game-    | has (variant . _NoRoleKnowledge) game =+    | has (variant . noRoleKnowledge) game  =         [ privateMessage to seersTurnPrivateText ]-    | has (variant . _NoRoleReveal) game    =+    | has (variant . noRoleReveal) game     =         [ privateMessage to seersTurnPrivateText ]     | otherwise                             =         [ publicMessage seersTurnPublicText@@ -271,8 +272,8 @@  villageDrunksTurnMessages :: Game -> [Message] villageDrunksTurnMessages game-    | has (variant . _NoRoleKnowledge) game = []-    | has (variant . _NoRoleReveal) game    = []+    | has (variant . noRoleKnowledge) game  = []+    | has (variant . noRoleReveal) game     = []     | otherwise                             = [publicMessage villageDrunksTurnText]  sunriseMessage :: Message@@ -294,9 +295,9 @@  werewolvesTurnMessages :: [Text] -> Game -> [Message] werewolvesTurnMessages tos game-    | has (variant . _NoRoleKnowledge) game =+    | has (variant . noRoleKnowledge) game  =         groupMessages tos werewolvesTurnPrivateText-    | has (variant . _NoRoleReveal) game    =+    | has (variant . noRoleReveal) game     =         groupMessages tos werewolvesTurnPrivateText     | otherwise                             =         publicMessage werewolvesTurnPublicText@@ -312,8 +313,8 @@     where         to              = game ^?! players . witches . name         wakeUpMessages-            | has (variant . _NoRoleKnowledge) game = []-            | has (variant . _NoRoleReveal) game    = []+            | has (variant . noRoleKnowledge) game  = []+            | has (variant . noRoleReveal) game     = []             | otherwise                             = [publicMessage witchsTurnText]         passMessage     = privateMessage to passText         healMessages@@ -355,18 +356,18 @@  werewolfLynchedMessage :: Player -> Game -> Message werewolfLynchedMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.playerLynchedText player-    | otherwise                             = publicMessage $ Standard.werewolfLynchedText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerLynchedText player+    | otherwise                         = publicMessage $ Standard.werewolfLynchedText player  playerLynchedMessage :: Player -> Game -> Message playerLynchedMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.playerLynchedText player-    | otherwise                             = publicMessage $ Standard.playerLynchedText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerLynchedText player+    | otherwise                         = publicMessage $ Standard.playerLynchedText player  saintLynchedMessage :: [Player] -> Game -> Message saintLynchedMessage voters game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.saintLynchedText voters-    | otherwise                             = publicMessage $ Standard.saintLynchedText voters+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.saintLynchedText voters+    | otherwise                         = publicMessage $ Standard.saintLynchedText voters  scapegoatLynchedMessage :: Game -> Message scapegoatLynchedMessage = publicMessage . scapegoatLynchedText@@ -379,16 +380,16 @@  playerDevouredMessage :: Player -> Game -> Message playerDevouredMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.playerDevouredText player-    | otherwise                             = publicMessage $ Standard.playerDevouredText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerDevouredText player+    | otherwise                         = publicMessage $ Standard.playerDevouredText player  playerDivinedMessage :: Text -> Player -> Message playerDivinedMessage to = privateMessage to . playerDivinedText  playerPoisonedMessage :: Player -> Game -> Message playerPoisonedMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.playerPoisonedText player-    | otherwise                             = publicMessage $ Standard.playerPoisonedText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerPoisonedText player+    | otherwise                         = publicMessage $ Standard.playerPoisonedText player  playerSeenMessage :: Text -> Player -> Message playerSeenMessage to player@@ -398,8 +399,8 @@  playerTurnedToStoneMessage :: Player -> Game -> Message playerTurnedToStoneMessage player game-    | has (variant . _NoRoleReveal) game    = publicMessage $ NoRoleReveal.playerTurnedToStoneText player-    | otherwise                             = publicMessage $ Standard.playerTurnedToStoneText player+    | has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerTurnedToStoneText player+    | otherwise                         = publicMessage $ Standard.playerTurnedToStoneText player  villageDrunkJoinedVillageMessage :: Text -> Message villageDrunkJoinedVillageMessage to = privateMessage to villageDrunkJoinedVillageText
app/Game/Werewolf/Message/Error.hs view
@@ -35,7 +35,7 @@      -- ** Start     gameAlreadyRunningMessage, mustHaveAtLeast7PlayersMessage, playerNamesMustBeUniqueMessage,-    roleCountRestrictedMessage, roleDoesNotExistMessage,+    roleCountRestrictedMessage, roleDoesNotExistMessage, variantDoesNotExistMessage,      -- ** Unvote     playerHasNotVotedMessage,@@ -107,6 +107,9 @@  roleDoesNotExistMessage :: Text -> Text -> Message roleDoesNotExistMessage to = privateMessage to . roleDoesNotExistText++variantDoesNotExistMessage :: Text -> Text -> Message+variantDoesNotExistMessage to = privateMessage to . variantDoesNotExistText  playerHasNotVotedMessage :: Text -> Message playerHasNotVotedMessage to = privateMessage to callerNotVotedText
app/Game/Werewolf/Variant/Standard/Command.hs view
@@ -32,8 +32,8 @@     oracleCommandsText, oraclesTurnText, orphanCommandsText, orphansTurnText, protectorCommandsText,     protectorsTurnText, roleDescriptionText, scapegoatCommandsText, scapegoatsTurnText,     seerCommandsText, seersTurnText, standardCommandsText, standardCycleText, statusCommandsText,-    sunriseText, sunsetText, villageDrunksTurnText, villagesTurnText, werewolvesTurnText,-    winConditionText, witchCommandsText, witchsTurnText,+    sunriseText, sunsetText, variantDescriptionText, villageDrunksTurnText, villagesTurnText,+    werewolvesTurnText, winConditionText, witchCommandsText, witchsTurnText,      -- * Ping     diurnalRolePingedText, nocturnalRolePingedText, playerPingedText, villagePingedText,@@ -67,8 +67,9 @@ import qualified Data.Text                     as T import           Data.Version -import Game.Werewolf-import Game.Werewolf.Message+import           Game.Werewolf+import           Game.Werewolf.Message+import qualified Game.Werewolf.Variant as Variant  import Werewolf.Version @@ -158,6 +159,9 @@  sunsetText :: Text sunsetText = [iFile|variant/standard/command/help/sunset.txt|]++variantDescriptionText :: Variant -> Text+variantDescriptionText variant = [iFile|variant/standard/command/help/variant.txt|]  villageDrunksTurnText :: Text villageDrunksTurnText = [iFile|variant/standard/command/help/village-drunks-turn.txt|]
app/Game/Werewolf/Variant/Standard/Error.hs view
@@ -37,7 +37,7 @@      -- ** Start     gameAlreadyRunningText, playerCountTooLowText, playerNamesNotUniqueText,-    roleCountRestrictedText, roleDoesNotExistText,+    roleCountRestrictedText, roleDoesNotExistText, variantDoesNotExistText,      -- ** Unvote     callerNotVotedText,@@ -108,6 +108,9 @@  roleDoesNotExistText :: Text -> Text roleDoesNotExistText roleName = [iFile|variant/standard/error/command/start/role-does-not-exist.txt|]++variantDoesNotExistText :: Text -> Text+variantDoesNotExistText variantName = [iFile|variant/standard/error/command/start/variant-does-not-exist.txt|]  callerNotVotedText :: Text callerNotVotedText = [iFile|variant/standard/error/command/unvote/caller-not-voted.txt|]
app/Werewolf/Command/Help.hs view
@@ -42,6 +42,8 @@     { optAll :: Bool     } | Roles     { optAll :: Bool+    } | Variants+    { optAll :: Bool     } deriving (Eq, Show)  handle :: MonadIO m => Text -> Text -> Options -> m ()@@ -53,9 +55,9 @@         } handle callerName tag (Options (Just (Roles optAll))) = do     mGame       <- getGame tag optAll-    let mGame'  = mGame >>= \game -> case game ^. variant of-            NoRoleKnowledge -> Nothing-            _               -> Just game+    let mGame'  = mGame >>= \game -> if has (variant . noRoleKnowledge) game+            then Nothing+            else Just game      let roles' = sortBy (compare `on` humanise) . nub $ maybe allRoles (toListOf $ players . roles) mGame' @@ -64,9 +66,9 @@         } handle callerName tag (Options (Just (Rules optAll))) = do     mGame       <- getGame tag optAll-    let mGame'  = mGame >>= \game -> case game ^. variant of-            NoRoleKnowledge -> Nothing-            _               -> Just game+    let mGame'  = mGame >>= \game -> if has (variant . noRoleKnowledge) game+            then Nothing+            else Just game      exitWith success         { messages = rulesMessages callerName mGame'@@ -74,6 +76,16 @@ handle callerName _ (Options Nothing) = exitWith success     { messages = helpMessages callerName     }+handle callerName tag (Options (Just (Variants optAll))) = do+    mGame <- getGame tag optAll++    let variants = sortBy (compare `on` humanise) $ case mGame of+            Just game   -> [game ^. variant]+            Nothing     -> allVariants++    exitWith success+        { messages = map (variantMessage callerName) variants+        }  commandsMessages :: Text -> Maybe Game -> [Message] commandsMessages callerName mGame =
app/Werewolf/Command/Start.hs view
@@ -29,9 +29,10 @@  import Data.Text (Text) -import Game.Werewolf-import Game.Werewolf.Engine-import Game.Werewolf.Message.Error+import           Game.Werewolf+import           Game.Werewolf.Engine+import           Game.Werewolf.Message.Error+import qualified Game.Werewolf.Variant       as Variant  import System.Random.Shuffle @@ -39,7 +40,7 @@  data Options = Options     { optExtraRoles :: ExtraRoles-    , optVariant    :: Variant+    , optVariant    :: Text     , argPlayers    :: [Text]     } deriving (Eq, Show) @@ -58,12 +59,14 @@             Random          -> randomExtraRoles $ length playerNames             Use roleNames   -> useExtraRoles callerName roleNames -        let defaultVillagerRole = if variant == SpitefulVillagers then spitefulVillagerRole else simpleVillagerRole+        variant' <- useVariant callerName variant++        let defaultVillagerRole = if is spitefulVillage variant' then spitefulVillagerRole else simpleVillagerRole         let roles = padRoles extraRoles' (length playerNames + 1) defaultVillagerRole          players <- createPlayers (callerName:playerNames) <$> shuffleM roles -        runWriterT $ startGame callerName variant players >>= execStateT checkStage+        runWriterT $ startGame callerName variant' players >>= execStateT checkStage      case result of         Left errorMessages      -> exitWith failure { messages = errorMessages }@@ -79,12 +82,20 @@     take count <$> shuffleM restrictedRoles  useExtraRoles :: MonadError [Message] m => Text -> [Text] -> m [Role]-useExtraRoles callerName roleNames = forM roleNames $ \roleName -> case findByTag roleName of+useExtraRoles callerName roleNames = forM roleNames $ \roleName -> case findRoleByTag roleName of     Just role   -> return role     Nothing     -> throwError [roleDoesNotExistMessage callerName roleName] -findByTag :: Text -> Maybe Role-findByTag tag' = restrictedRoles ^? traverse . filteredBy tag tag'+findRoleByTag :: Text -> Maybe Role+findRoleByTag tag' = restrictedRoles ^? traverse . filteredBy tag tag'++useVariant :: MonadError [Message] m => Text -> Text -> m Variant+useVariant callerName variantName = case findVariantByTag variantName of+    Just variant   -> return variant+    Nothing         -> throwError [variantDoesNotExistMessage callerName variantName]++findVariantByTag :: Text -> Maybe Variant+findVariantByTag tag' = allVariants ^? traverse . filteredBy Variant.tag tag'  padRoles :: [Role] -> Int -> Role -> [Role] padRoles roles n defaultVillagerRole = roles ++ villagerRoles ++ simpleWerewolfRoles
app/Werewolf/Options.hs view
@@ -19,14 +19,15 @@     werewolfPrefs, werewolfInfo, werewolf, ) where +import Control.Lens+ import           Data.Text    (Text) import qualified Data.Text    as T import           Data.Version (showVersion) -import Game.Werewolf (Variant (..))+import Game.Werewolf.Variant  import Options.Applicative-import Options.Applicative.Types  import qualified Werewolf.Command.Boot      as Boot import qualified Werewolf.Command.Choose    as Choose@@ -149,6 +150,7 @@         [ command "commands"    $ info (Help.Commands <$> allOption)    (fullDesc <> progDesc "Print the in-game commands")         , command "roles"       $ info (Help.Roles <$> allOption)       (fullDesc <> progDesc "Print the roles and their descriptions")         , command "rules"       $ info (Help.Rules <$> allOption)       (fullDesc <> progDesc "Print the game rules")+        , command "variants"    $ info (Help.Variants <$> allOption)    (fullDesc <> progDesc "Print the variants and their descriptions")         ])     where         allOption = switch $ long "all" <> short 'a'@@ -181,20 +183,13 @@ start :: Parser Command start = fmap Start $ Start.Options     <$> (extraRolesOption <|> randomExtraRolesOption)-    <*> variantOption (mconcat [+    <*> fmap T.pack (strOption $ mconcat [         long "variant", short 'v', metavar "VARIANT",-        value Standard, showDefaultWith $ const "standard",+        value standardVariantTag, showDefaultWith $ const standardVariantTag,         help "Specify the game variant"         ])     <*> some (T.pack <$> strArgument (metavar "PLAYER..."))     where-        variantOption = option $ readerAsk >>= \opt -> case opt of-            "standard"              -> return Standard-            "no-role-knowledge"     -> return NoRoleKnowledge-            "no-role-reveal"        -> return NoRoleReveal-            "spiteful-villagers"    -> return SpitefulVillagers-            _                       -> readerError $ "unrecognised variant `" ++ opt ++ "'"-         extraRolesOption = fmap (Start.Use . filter (/= T.empty) . T.splitOn "," . T.pack) (strOption $ mconcat             [ long "extra-roles", short 'e', metavar "ROLE,..."             , value []@@ -205,6 +200,8 @@             [ long "random-extra-roles", short 'r'             , help "Use random extra roles"             ]++        standardVariantTag = T.unpack $ standardVariant ^. tag  status :: Parser Command status = pure Status
src/Game/Werewolf.hs view
@@ -12,9 +12,10 @@ * "Game.Werewolf.Player" * "Game.Werewolf.Response" * "Game.Werewolf.Role"+* "Game.Werewolf.Variant" -N.B., where clashes are found between "Game.Werewolf.Player" and "Game.Werewolf.Role", the-"Game.Werewolf.Player" functions are preferred.+N.B., where clashes are found between "Game.Werewolf.Player", "Game.Werewolf.Role" and+"Game.Werewolf.Variant", the "Game.Werewolf.Player" functions are preferred. -}  module Game.Werewolf (@@ -25,3 +26,4 @@ import Game.Werewolf.Player   as Werewolf import Game.Werewolf.Response as Werewolf import Game.Werewolf.Role     as Werewolf hiding (activity, name)+import Game.Werewolf.Variant  as Werewolf hiding (description, name, tag)
src/Game/Werewolf/Game.hs view
@@ -22,9 +22,6 @@     healUsed, hunterRetaliated, jesterRevealed, marks, passed, poison, poisonUsed, priorProtect,     protect, roleModel, scapegoatBlamed, see, votes, -    Variant(..),-    _Standard, _NoRoleKnowledge, _NoRoleReveal,-     Stage(..),     _DruidsTurn, _GameOver, _HuntersTurn1, _HuntersTurn2, _Lynching, _NecromancersTurn,     _OraclesTurn, _OrphansTurn, _ProtectorsTurn, _ScapegoatsTurn, _SeersTurn, _Sunrise, _Sunset,@@ -60,7 +57,8 @@ import           Data.Text            (Text)  import Game.Werewolf.Player-import Game.Werewolf.Role   hiding (activity, name)+import Game.Werewolf.Role    hiding (activity, name)+import Game.Werewolf.Variant hiding (name)  import Prelude hiding (round) @@ -98,15 +96,6 @@     , _votes              :: Map Text Text    -- ^ Villagers and Werewolves     } deriving (Eq, Read, Show) -data Variant = Standard | NoRoleKnowledge | NoRoleReveal | SpitefulVillagers-    deriving (Eq, Read, Show)--instance Humanise Variant where-    humanise Standard           = "standard"-    humanise NoRoleKnowledge    = "no role knowledge"-    humanise NoRoleReveal       = "no role reveal"-    humanise SpitefulVillagers  = "spiteful villagers"- -- | Most of these are fairly self-explainable (the turn stages). 'Sunrise' and 'Sunset' are --   provided as meaningful breaks between the day and night as, for example, a 'VillagesTurn' may --   not always be available (curse that retched Scapegoat).@@ -138,8 +127,6 @@     humanise WitchsTurn         = "Witch's turn"  makeLenses ''Game--makePrisms ''Variant  makePrisms ''Stage 
src/Game/Werewolf/Player.hs view
@@ -295,7 +295,7 @@ werewolf :: Traversal' Player () werewolf = role . allegiance . _Werewolves --- | This 'Traversal' provides the traversal of 'Player' names.+-- | The traversal of 'Player' names. -- -- @ -- 'names' = 'traverse' . 'name'@@ -303,7 +303,7 @@ names :: Traversable t => Traversal' (t Player) Text names = traverse . name --- | This 'Traversal' provides the traversal of 'Player' roles.+-- | The traversal of 'Player' roles. -- -- @ -- 'roles' = 'traverse' . 'role'@@ -311,7 +311,7 @@ roles :: Traversable t => Traversal' (t Player) Role roles = traverse . role --- | This 'Traversal' provides the traversal of 'Player' states.+-- | The traversal of 'Player' states. -- -- @ -- 'states' = 'traverse' . 'state'@@ -319,7 +319,7 @@ states :: Traversable t => Traversal' (t Player) State states = traverse . state --- | This 'Traversal' provides the traversal of 'Player's with the given name.+-- | The traversal of 'Player's with the given name. -- -- @ -- 'named' name' = 'filteredBy' . 'name' name'@@ -327,7 +327,7 @@ named :: Text -> Traversal' Player Player named name' = filteredBy name name' --- | This 'Traversal' provides the traversal of 'alphaWolf' 'Player's.+-- | The traversal of 'alphaWolf' 'Player's. -- -- @ -- 'alphaWolves' = 'traverse' . 'filtered' ('is' 'alphaWolf')@@ -335,7 +335,7 @@ alphaWolves :: Traversable t => Traversal' (t Player) Player alphaWolves = traverse . filtered (is alphaWolf) --- | This 'Traversal' provides the traversal of 'beholder' 'Player's.+-- | The traversal of 'beholder' 'Player's. -- -- @ -- 'beholders' = 'traverse' . 'filtered' ('is' 'beholder')@@ -343,7 +343,7 @@ beholders :: Traversable t => Traversal' (t Player) Player beholders = traverse . filtered (is beholder) --- | This 'Traversal' provides the traversal of 'crookedSenator' 'Player's.+-- | The traversal of 'crookedSenator' 'Player's. -- -- @ -- 'crookedSenators' = 'traverse' . 'filtered' ('is' 'crookedSenator')@@ -351,7 +351,7 @@ crookedSenators :: Traversable t => Traversal' (t Player) Player crookedSenators = traverse . filtered (is crookedSenator) --- | This 'Traversal' provides the traversal of 'dullahan' 'Player's.+-- | The traversal of 'dullahan' 'Player's. -- -- @ -- 'dullahans' = 'traverse' . 'filtered' ('is' 'dullahan')@@ -359,7 +359,7 @@ dullahans :: Traversable t => Traversal' (t Player) Player dullahans = traverse . filtered (is dullahan) --- | This 'Traversal' provides the traversal of 'druid' 'Player's.+-- | The traversal of 'druid' 'Player's. -- -- @ -- 'druids' = 'traverse' . 'filtered' ('is' 'druid')@@ -367,7 +367,7 @@ druids :: Traversable t => Traversal' (t Player) Player druids = traverse . filtered (is druid) --- | This 'Traversal' provides the traversal of 'fallenAngel' 'Player's.+-- | The traversal of 'fallenAngel' 'Player's. -- -- @ -- 'fallenAngels' = 'traverse' . 'filtered' ('is' 'fallenAngel')@@ -375,7 +375,7 @@ fallenAngels :: Traversable t => Traversal' (t Player) Player fallenAngels = traverse . filtered (is fallenAngel) --- | This 'Traversal' provides the traversal of 'hunter' 'Player's.+-- | The traversal of 'hunter' 'Player's. -- -- @ -- 'hunters' = 'traverse' . 'filtered' ('is' 'hunter')@@ -383,7 +383,7 @@ hunters :: Traversable t => Traversal' (t Player) Player hunters = traverse . filtered (is hunter) --- | This 'Traversal' provides the traversal of 'jester' 'Player's.+-- | The traversal of 'jester' 'Player's. -- -- @ -- 'jesters' = 'traverse' . 'filtered' ('is' 'jester')@@ -391,7 +391,7 @@ jesters :: Traversable t => Traversal' (t Player) Player jesters = traverse . filtered (is jester) --- | This 'Traversal' provides the traversal of 'lycan' 'Player's.+-- | The traversal of 'lycan' 'Player's. -- -- @ -- 'lycans' = 'traverse' . 'filtered' ('is' 'lycan')@@ -399,7 +399,7 @@ lycans :: Traversable t => Traversal' (t Player) Player lycans = traverse . filtered (is lycan) --- | This 'Traversal' provides the traversal of 'medusa' 'Player's.+-- | The traversal of 'medusa' 'Player's. -- -- @ -- 'medusas' = 'traverse' . 'filtered' ('is' 'medusa')@@ -407,7 +407,7 @@ medusas :: Traversable t => Traversal' (t Player) Player medusas = traverse . filtered (is medusa) --- | This 'Traversal' provides the traversal of 'necromancer' 'Player's.+-- | The traversal of 'necromancer' 'Player's. -- -- @ -- 'necromancers' = 'traverse' . 'filtered' ('is' 'necromancer')@@ -415,7 +415,7 @@ necromancers :: Traversable t => Traversal' (t Player) Player necromancers = traverse . filtered (is necromancer) --- | This 'Traversal' provides the traversal of 'oracle' 'Player's.+-- | The traversal of 'oracle' 'Player's. -- -- @ -- 'oracles' = 'traverse' . 'filtered' ('is' 'oracle')@@ -423,7 +423,7 @@ oracles :: Traversable t => Traversal' (t Player) Player oracles = traverse . filtered (is oracle) --- | This 'Traversal' provides the traversal of 'orphan' 'Player's.+-- | The traversal of 'orphan' 'Player's. -- -- @ -- 'orphans' = 'traverse' . 'filtered' ('is' 'orphan')@@ -431,7 +431,7 @@ orphans :: Traversable t => Traversal' (t Player) Player orphans = traverse . filtered (is orphan) --- | This 'Traversal' provides the traversal of 'protector' 'Player's.+-- | The traversal of 'protector' 'Player's. -- -- @ -- 'protectors' = 'traverse' . 'filtered' ('is' 'protector')@@ -439,7 +439,7 @@ protectors :: Traversable t => Traversal' (t Player) Player protectors = traverse . filtered (is protector) --- | This 'Traversal' provides the traversal of 'saint' 'Player's.+-- | The traversal of 'saint' 'Player's. -- -- @ -- 'saints' = 'traverse' . 'filtered' ('is' 'saint')@@ -447,7 +447,7 @@ saints :: Traversable t => Traversal' (t Player) Player saints = traverse . filtered (is saint) --- | This 'Traversal' provides the traversal of 'scapegoat' 'Player's.+-- | The traversal of 'scapegoat' 'Player's. -- -- @ -- 'scapegoats' = 'traverse' . 'filtered' ('is' 'scapegoat')@@ -455,7 +455,7 @@ scapegoats :: Traversable t => Traversal' (t Player) Player scapegoats = traverse . filtered (is scapegoat) --- | This 'Traversal' provides the traversal of 'seer' 'Player's.+-- | The traversal of 'seer' 'Player's. -- -- @ -- 'seers' = 'traverse' . 'filtered' ('is' 'seer')@@ -463,7 +463,7 @@ seers :: Traversable t => Traversal' (t Player) Player seers = traverse . filtered (is seer) --- | This 'Traversal' provides the traversal of 'simpleVillager' 'Player's.+-- | The traversal of 'simpleVillager' 'Player's. -- -- @ -- 'simpleVillagers' = 'traverse' . 'filtered' ('is' 'simpleVillager')@@ -471,7 +471,7 @@ simpleVillagers :: Traversable t => Traversal' (t Player) Player simpleVillagers = traverse . filtered (is simpleVillager) --- | This 'Traversal' provides the traversal of 'simpleWerewolf' 'Player's.+-- | The traversal of 'simpleWerewolf' 'Player's. -- -- @ -- 'simpleWerewolves' = 'traverse' . 'filtered' ('is' 'simpleWerewolf')@@ -479,7 +479,7 @@ simpleWerewolves :: Traversable t => Traversal' (t Player) Player simpleWerewolves = traverse . filtered (is simpleWerewolf) --- | This 'Traversal' provides the traversal of 'spitefulVillager' 'Player's.+-- | The traversal of 'spitefulVillager' 'Player's. -- -- @ -- 'spitefulVillagers' = 'traverse' . 'filtered' ('is' 'spitefulVillager')@@ -487,7 +487,7 @@ spitefulVillagers :: Traversable t => Traversal' (t Player) Player spitefulVillagers = traverse . filtered (is spitefulVillager) --- | This 'Traversal' provides the traversal of 'trueVillager' 'Player's.+-- | The traversal of 'trueVillager' 'Player's. -- -- @ -- 'trueVillagers' = 'traverse' . 'filtered' ('is' 'trueVillager')@@ -495,7 +495,7 @@ trueVillagers :: Traversable t => Traversal' (t Player) Player trueVillagers = traverse . filtered (is trueVillager) --- | This 'Traversal' provides the traversal of 'villageDrunk' 'Player's.+-- | The traversal of 'villageDrunk' 'Player's. -- -- @ -- 'villageDrunks' = 'traverse' . 'filtered' ('is' 'villageDrunk')@@ -503,7 +503,7 @@ villageDrunks :: Traversable t => Traversal' (t Player) Player villageDrunks = traverse . filtered (is villageDrunk) --- | This 'Traversal' provides the traversal of 'witch' 'Player's.+-- | The traversal of 'witch' 'Player's. -- -- @ -- 'witches' = 'traverse' . 'filtered' ('is' 'witch')@@ -511,7 +511,7 @@ witches :: Traversable t => Traversal' (t Player) Player witches = traverse . filtered (is witch) --- | This 'Traversal' provides the traversal of 'zombie' 'Player's.+-- | The traversal of 'zombie' 'Player's. -- -- @ -- 'zombies' = 'traverse' . 'filtered' ('is' 'zombie')@@ -519,7 +519,7 @@ zombies :: Traversable t => Traversal' (t Player) Player zombies = traverse . filtered (is zombie) --- | This 'Traversal' provides the traversal of 'loner' 'Player's.+-- | The traversal of 'loner' 'Player's. -- -- @ -- 'loners' = 'traverse' . 'filtered' . ('is' 'loner')@@ -527,7 +527,7 @@ loners :: Traversable t => Traversal' (t Player) Player loners = traverse . filtered (is loner) --- | This 'Traversal' provides the traversal of 'villager' 'Player's.+-- | The traversal of 'villager' 'Player's. -- -- @ -- 'villagers' = 'traverse' . 'filtered' ('is' 'villager')@@ -535,7 +535,7 @@ villagers :: Traversable t => Traversal' (t Player) Player villagers = traverse . filtered (is villager) --- | This 'Traversal' provides the traversal of 'werewolf' 'Player's.+-- | The traversal of 'werewolf' 'Player's. -- -- @ -- 'werewolves' = 'traverse' . 'filtered' ('is' 'werewolf')@@ -543,7 +543,7 @@ werewolves :: Traversable t => Traversal' (t Player) Player werewolves = traverse . filtered (is werewolf) --- | This 'Traversal' provides the traversal of 'Alive' 'Player's.+-- | The traversal of 'Alive' 'Player's. -- -- @ -- 'alive' = 'filtered' ('has' $ 'state' . '_Alive')@@ -551,7 +551,7 @@ alive :: Traversal' Player Player alive = filtered (has $ state . _Alive) --- | This 'Traversal' provides the traversal of 'Dead' 'Player's.+-- | The traversal of 'Dead' 'Player's. -- -- @ -- 'dead' = 'filtered' ('has' $ 'state' . '_Dead')
+ src/Game/Werewolf/Variant.hs view
@@ -0,0 +1,121 @@+{-|+Module      : Game.Werewolf.Variant+Description : Simplistic variant data structure with lenses and instances.++Copyright   : (c) Henry J. Wylde, 2016+License     : BSD3+Maintainer  : public@hjwylde.com++Variants alter how a game plays out. Either by changing the messages returned, or by changing the+game logic.+-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE TemplateHaskell   #-}++module Game.Werewolf.Variant (+    -- * Variant+    Variant,+    tag, name, description,++    -- ** Instances+    allVariants,++    standardVariant, noRoleKnowledgeVariant, noRoleRevealVariant, spitefulVillageVariant,++    -- ** Traversals+    standard, noRoleKnowledge, noRoleReveal, spitefulVillage,+) where++import Control.Lens++import Data.String.Humanise+import Data.String.Interpolate.Extra+import Data.Text                     as T++import Game.Werewolf.Role hiding (description, name, tag)++-- | Variant definitions require only a few pieces of information.+data Variant = Variant+    { _tag         :: Text+    , _name        :: Text+    , _description :: Text+    } deriving (Eq, Read, Show)++makeLenses ''Variant++instance Humanise Variant where+    humanise = view name++-- | A list containing all the variants defined in this file.+allVariants :: [Variant]+allVariants =+    [ standardVariant+    , noRoleKnowledgeVariant+    , noRoleRevealVariant+    , spitefulVillageVariant+    ]++standardVariant :: Variant+standardVariant = Variant+    { _tag          = "standard"+    , _name         = T.strip [iFile|variant/standard/name.txt|]+    , _description  = T.strip [iFile|variant/standard/description.txt|]+    }++noRoleKnowledgeVariant :: Variant+noRoleKnowledgeVariant = Variant+    { _tag          = "no-role-knowledge"+    , _name         = T.strip [iFile|variant/no-role-knowledge/name.txt|]+    , _description  = T.strip [iFile|variant/no-role-knowledge/description.txt|]+    }++noRoleRevealVariant :: Variant+noRoleRevealVariant = Variant+    { _tag          = "no-role-reveal"+    , _name         = T.strip [iFile|variant/no-role-reveal/name.txt|]+    , _description  = T.strip [iFile|variant/no-role-reveal/description.txt|]+    }++spitefulVillageVariant :: Variant+spitefulVillageVariant = Variant+    { _tag          = "spiteful-village"+    , _name         = T.strip [iFile|variant/spiteful-village/name.txt|]+    , _description  = T.strip [iFile|variant/spiteful-village/description.txt|]+    }++-- | The traversal of 'standard' 'Variant's.+--+-- @+-- 'standard' = 'only' 'standardVariant'+-- @+standard :: Traversal' Variant ()+standard = only standardVariant+++-- | The traversal of 'noRoleKnowledge' 'Variant's.+--+-- @+-- 'noRoleKnowledge' = 'only' 'noRoleKnowledgeVariant'+-- @+noRoleKnowledge :: Traversal' Variant ()+noRoleKnowledge = only noRoleKnowledgeVariant+++-- | The traversal of 'noRoleReveal' 'Variant's.+--+-- @+-- 'noRoleReveal' = 'only' 'noRoleRevealVariant'+-- @+noRoleReveal :: Traversal' Variant ()+noRoleReveal = only noRoleRevealVariant+++-- | The traversal of 'spitefulVillage' 'Variant's.+--+-- @+-- 'spitefulVillage' = 'only' 'spitefulVillageVariant'+-- @+spitefulVillage :: Traversal' Variant ()+spitefulVillage = only spitefulVillageVariant
+ variant/no-role-knowledge/description.txt view
@@ -0,0 +1,1 @@+In "No role knowledge", players are not informed of the roles in play at the start of a game. Further, nocturnal player turns are obscured.
+ variant/no-role-knowledge/name.txt view
@@ -0,0 +1,1 @@+No role knowledge
+ variant/no-role-reveal/description.txt view
@@ -0,0 +1,1 @@+In "No role reveal", players are not informed of each others roles upon death. Further, nocturnal player turns are obscured.
+ variant/no-role-reveal/name.txt view
@@ -0,0 +1,1 @@+No role reveal
+ variant/spiteful-village/description.txt view
@@ -0,0 +1,1 @@+In "Spiteful village", the default Villager role becomes the #{humanise spitefulVillagerRole}.
+ variant/spiteful-village/name.txt view
@@ -0,0 +1,1 @@+Spiteful village
variant/standard/command/help/help-commands.txt view
@@ -2,3 +2,4 @@ - `help commands [-a | --all]` - `help roles [-a | --all]` - `help rules [-a | --all]`+- `help variants [-a | --all]`
+ variant/standard/command/help/variant.txt view
@@ -0,0 +1,2 @@+#{humanise variant} (#{variant ^. Variant.tag}):+#{variant ^. Variant.description}
+ variant/standard/description.txt view
@@ -0,0 +1,1 @@+The Standard variant; everything plays out as normal.
variant/standard/engine/lynching/jester-lynched.txt view
@@ -1,1 +1,1 @@-Just as the townsfolk tie #{humanise jester} up to the pyre, a voice in the crowd yells out. "We can't burn #{humanise jester}! He's the joke of the town!" #{humanise jester} the #{humanise jesterRole} is quickly untied and apologised to.+Just as the townsfolk tie #{humanise jester} up to the pyre, a voice in the crowd yells out. "We can't burn #{humanise jester}! They're the joke of the town!" #{humanise jester} the #{humanise jesterRole} is quickly untied and apologised to.
+ variant/standard/error/command/start/variant-does-not-exist.txt view
@@ -0,0 +1,1 @@+Variant #{variantName} does not exist.
+ variant/standard/name.txt view
@@ -0,0 +1,1 @@+Standard
variant/standard/role/medusa/description.txt view
@@ -1,1 +1,1 @@-A beautiful flirt, the Medusa is aligned with the Villagers but harbours a terrifying secret. During the day they are well known in the village of Fougères for their stunning appearance which captures the eye and love of all the townsfolk. However when their secret takes ahold at sundown, their true self is revealed. Any who gaze upon her true form would see live snakes for hair and the few that further look into her eyes are turned to stone.+A beautiful flirt, the Medusa is aligned with the Villagers but harbours a terrifying secret. During the day they are well known in the village of Fougères for their stunning appearance which captures the eye and love of all the townsfolk. However when their secret takes ahold at sundown, their true self is revealed. Any who gaze upon their true form would see live snakes for hair and the few that further look into their eyes are turned to stone.
variant/standard/role/necromancer/description.txt view
@@ -1,1 +1,1 @@-The dead are feared among the living; the dead outnumber the living. In most villages the dead remain that way, but not when the Necromancer is present. The Necromancer devoted their life to learning black magic and methods of bringing people back to life. Unfortunately this art is hard to perfect and all they can manage to bring back are soulless Zombies.+The dead are feared among the living; the dead outnumber the living. In most villages the dead remain that way, but not when the Necromancer is present. The Necromancer devoted their life to learning black magic and methods of bringing people back to life. Unfortunately this art is hard to perfect and all they can manage to bring back are soulless #{humanise zombieRole}s.
variant/standard/role/necromancer/rules.txt view
@@ -1,3 +1,2 @@-Once per game the Necromancer can choose to resurrect all dead players as Zombies. The Zombies are aligned with the Necromancer and they cannot be lynched or devoured.-If the Necromancer is killed, all Zombies die with them.-The Necromancer and Zombies win if they are the last ones alive.+Once per game the Necromancer can choose to resurrect all dead players as #{humanise zombieRole}s. The #{humanise zombieRole}s are aligned with the Necromancer and they cannot be lynched or devoured. If the Necromancer is killed, all #{humanise zombieRole}s die with them.+The Necromancer and #{humanise zombieRole}s win if they are the last ones alive.
variant/standard/role/zombie/description.txt view
@@ -1,1 +1,1 @@-A loyal follower of the Necromancer. A Zombie has no mind of its own and blindly obeys every command of their master.+A loyal follower of the #{humanise necromancerRole}. A Zombie has no mind of its own and blindly obeys every command of their master.
variant/standard/role/zombie/rules.txt view
@@ -1,1 +1,1 @@-A Zombie wins with the Necromancer. They cannot be killed, however they die when the Necromancer dies.+A Zombie wins with the #{humanise necromancerRole}. They cannot be killed, however they die when the #{humanise necromancerRole} dies.
werewolf.cabal view
@@ -1,5 +1,5 @@ name:           werewolf-version:        1.4.0.1+version:        1.5.0.0  author:         Henry J. Wylde maintainer:     public@hjwylde.com@@ -21,10 +21,14 @@ extra-source-files:     CHANGELOG.md     README.md+    variant/no-role-knowledge/description.txt+    variant/no-role-knowledge/name.txt     variant/no-role-knowledge/command/ping/nocturnal-role-pinged.txt     variant/no-role-knowledge/command/ping/werewolves-pinged.txt     variant/no-role-knowledge/command/status/current-nocturnal-turn.txt     variant/no-role-knowledge/engine/new-game/roles-in-game.txt+    variant/no-role-reveal/description.txt+    variant/no-role-reveal/name.txt     variant/no-role-reveal/command/choose/player-shot.txt     variant/no-role-reveal/command/ping/nocturnal-role-pinged.txt     variant/no-role-reveal/command/ping/werewolves-pinged.txt@@ -39,6 +43,10 @@     variant/no-role-reveal/engine/sunrise/player-devoured.txt     variant/no-role-reveal/engine/sunrise/player-poisoned.txt     variant/no-role-reveal/engine/sunrise/player-turned-to-stone.txt+    variant/spiteful-village/description.txt+    variant/spiteful-village/name.txt+    variant/standard/description.txt+    variant/standard/name.txt     variant/standard/command/boot/player-voted-boot.txt     variant/standard/command/choose/player-shot.txt     variant/standard/command/circle/game-circle.txt@@ -68,6 +76,7 @@     variant/standard/command/help/status-commands.txt     variant/standard/command/help/sunrise.txt     variant/standard/command/help/sunset.txt+    variant/standard/command/help/variant.txt     variant/standard/command/help/village-drunks-turn.txt     variant/standard/command/help/villages-turn.txt     variant/standard/command/help/werewolves-turn.txt@@ -176,6 +185,7 @@     variant/standard/error/command/start/player-names-not-unique.txt     variant/standard/error/command/start/role-count-restricted.txt     variant/standard/error/command/start/role-does-not-exist.txt+    variant/standard/error/command/start/variant-does-not-exist.txt     variant/standard/error/command/unvote/caller-not-voted.txt     variant/standard/error/command/vote/caller-already-voted.txt     variant/standard/error/command/vote/caller-cannot-devour-werewolf.txt@@ -346,6 +356,7 @@         Game.Werewolf.Player         Game.Werewolf.Response         Game.Werewolf.Role+        Game.Werewolf.Variant      default-language: Haskell2010     other-extensions: