werewolf-1.5.1.0: app/Game/Werewolf/Message/Engine.hs
{-|
Module : Game.Werewolf.Message.Engine
Description : Suite of engine messages used throughout the game.
Copyright : (c) Henry J. Wylde, 2016
License : BSD3
Maintainer : public@hjwylde.com
A 'Message' is used to relay information back to either all players or a single player. This module
defines suite of engine messages used throughout the werewolf game.
-}
-- TODO (hjw): sort this file
module Game.Werewolf.Message.Engine (
playerRolesMessage, playerBootedMessage, villageDrunkJoinedPackMessages, villageDrunkJoinedVillageMessage,
playerTurnedToStoneMessage, playerSeenMessage, playerDivinedMessage, playerDevouredMessage,
noPlayerDevouredMessage, scapegoatChoseAllowedVotersMessage, playerPoisonedMessage,
scapegoatLynchedMessage, saintLynchedMessage, playerLynchedMessage, noPlayerLynchedMessage, jesterLynchedMessage,
ferinaGruntsMessage, orphanJoinedPackMessages, playerKilledMessage, playerLostMessage,
playerContributedMessage, playerWonMessage, witchsTurnMessages, firstWerewolvesTurnMessages,
villagesTurnMessage, nightFallsMessage, sunriseMessage, villageDrunksTurnMessages, spitefulVillagerKilledMessage,
seersTurnMessages, scapegoatsTurnMessage, protectorsTurnMessages, orphansTurnMessages,
oraclesTurnMessages, huntersTurnMessages, stageMessages,
trueVillagerMessage, beholderMessage, newPlayerMessage, rolesInGameMessage,
newPlayersInGameMessage, newGameMessages, gameOverMessages, fallenAngelWonMessage,
werewolfLynchedMessage, zombiesReturnedToGraveMessage,
) where
import Control.Lens.Extra
import Data.List.Extra
import Data.Text (Text)
import Game.Werewolf.Game
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.NoRoleKnowledgeOrReveal.Engine as NoRoleKnowledgeOrReveal
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 . noRoleKnowledgeOrReveal) game = publicMessage $ NoRoleKnowledgeOrReveal.playerBootedText player
| has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerBootedText player
| otherwise = publicMessage $ Standard.playerBootedText player
gameOverMessages :: Game -> [Message]
gameOverMessages game
| hasDullahanWon game = concat
[ [dullahanWonMessage game]
, [playerRolesMessage game]
, [playerWonMessage dullahansName]
, map playerLostMessage (game ^.. players . names \\ [dullahansName])
]
| hasFallenAngelWon game = concat
[ [fallenAngelWonMessage]
, [playerRolesMessage game]
, [playerWonMessage fallenAngelsName]
, map playerLostMessage (game ^.. players . names \\ [fallenAngelsName])
]
| hasNecromancerWon game = concat
[ [necromancerWonMessage]
, [playerRolesMessage game]
, map playerWonMessage (necromancersName:zombieNames)
, map playerLostMessage (game ^.. players . names \\ (necromancersName:zombieNames))
]
| hasEveryoneLost game = concat
[ [everyoneLostMessage]
, [playerRolesMessage game]
, map playerLostMessage (game ^.. players . names)
]
| otherwise = concat
[ [allegianceWonMessage winningAllegiance]
, [playerRolesMessage game]
, playerWonMessages
, playerContributedMessages
, playerLostMessages
]
where
winningAllegiance
| hasVillagersWon game = Villagers
| hasWerewolvesWon game = Werewolves
| otherwise = undefined
winningPlayers = game ^.. players . traverse . filteredBy (role . allegiance) winningAllegiance
losingPlayers = game ^. players \\ winningPlayers
playerWonMessages = map playerWonMessage (winningPlayers ^.. traverse . alive . name)
playerContributedMessages = map playerContributedMessage (winningPlayers ^.. traverse . dead . name)
playerLostMessages = map playerLostMessage (losingPlayers ^.. names)
dullahansName = game ^?! players . dullahans . name
fallenAngelsName = game ^?! players . fallenAngels . name
necromancersName = game ^?! players . necromancers . name
zombieNames = game ^.. players . zombies . name
dullahanWonMessage :: Game -> Message
dullahanWonMessage = publicMessage . dullahanWonText
everyoneLostMessage :: Message
everyoneLostMessage = publicMessage everyoneLostText
fallenAngelWonMessage :: Message
fallenAngelWonMessage = publicMessage fallenAngelWonText
necromancerWonMessage :: Message
necromancerWonMessage = publicMessage necromancerWonText
allegianceWonMessage :: Allegiance -> Message
allegianceWonMessage = publicMessage . allegianceWonText
playerRolesMessage :: Game -> Message
playerRolesMessage = publicMessage . playerRolesText
newGameMessages :: Game -> [Message]
newGameMessages game = concat
[ [newPlayersInGameMessage game]
, gameVariantMessages
, [rolesInGameMessage Nothing game]
, map newPlayerMessage players'
, beholderMessages
, dullahanMessages
, trueVillagerMessages
, stageMessages game
]
where
players' = game ^. players
gameVariantMessages =
[ gameVariantMessage game
| hasn't (variant . standard) game
]
beholderMessages =
[ beholderMessage beholderName game
| has beholders players'
, has seers players'
, beholderName <- players' ^.. beholders . name
]
dullahanMessages =
[ dullahanMessage dullahanName game
| has dullahans players'
, dullahanName <- players' ^.. dullahans . name
]
trueVillagerMessages =
[ trueVillagerMessage game
| has trueVillagers players'
]
newPlayersInGameMessage :: Game -> Message
newPlayersInGameMessage = publicMessage . playersInGameText
gameVariantMessage :: Game -> Message
gameVariantMessage = publicMessage . gameVariantText
rolesInGameMessage :: Maybe Text -> Game -> Message
rolesInGameMessage mTo game
| has (variant . noRoleKnowledge) game = Message mTo $ NoRoleKnowledge.rolesInGameText game
| has (variant . noRoleKnowledgeOrReveal) game = Message mTo $ NoRoleKnowledgeOrReveal.rolesInGameText game
| otherwise = Message mTo $ Standard.rolesInGameText game
newPlayerMessage :: Player -> Message
newPlayerMessage player = privateMessage (player ^. name) $ newPlayerText player
beholderMessage :: Text -> Game -> Message
beholderMessage to = privateMessage to . beholderText
dullahanMessage :: Text -> Game -> Message
dullahanMessage to = privateMessage to . dullahanText
spitefulVillagerKilledMessage :: Text -> Game -> Message
spitefulVillagerKilledMessage to game
| has (variant . noRoleKnowledgeOrReveal) game = privateMessage to $ NoRoleKnowledgeOrReveal.spitefulVillagerKilledText game
| has (variant . noRoleReveal) game = privateMessage to $ NoRoleReveal.spitefulVillagerKilledText game
| otherwise = privateMessage to $ Standard.spitefulVillagerKilledText game
trueVillagerMessage :: Game -> Message
trueVillagerMessage = publicMessage . trueVillagerText
stageMessages :: Game -> [Message]
stageMessages game = case game ^. stage of
DruidsTurn -> []
GameOver -> []
HuntersTurn1 -> huntersTurnMessages game
HuntersTurn2 -> huntersTurnMessages game
Lynching -> []
NecromancersTurn -> necromancersTurnMessages necromancersName game
OraclesTurn -> oraclesTurnMessages oraclesName game
OrphansTurn -> orphansTurnMessages orphansName game
ProtectorsTurn -> protectorsTurnMessages protectorsName game
ScapegoatsTurn -> [scapegoatsTurnMessage game]
SeersTurn -> seersTurnMessages seersName game
Sunrise -> [sunriseMessage]
Sunset -> [nightFallsMessage]
VillageDrunksTurn -> villageDrunksTurnMessages game
VillagesTurn -> [villagesTurnMessage]
WerewolvesTurn -> if is firstRound game
then firstWerewolvesTurnMessages game
else werewolvesTurnMessages aliveWerewolfNames game
WitchsTurn -> witchsTurnMessages game
where
players' = game ^. players
necromancersName = players' ^?! necromancers . name
oraclesName = players' ^?! oracles . name
orphansName = players' ^?! orphans . name
protectorsName = players' ^?! protectors . name
seersName = players' ^?! seers . name
aliveWerewolfNames = players' ^.. werewolves . alive . name
huntersTurnMessages :: Game -> [Message]
huntersTurnMessages game =
[ publicMessage $ huntersTurnPublicText game
, privateMessage hunterName huntersTurnPrivateText
]
where
hunterName = game ^?! players . hunters . name
necromancersTurnMessages :: Text -> Game -> [Message]
necromancersTurnMessages to game
| has (variant . noRoleKnowledge) game =
[ privateMessage to necromancersTurnPrivateText ]
| has (variant . noRoleKnowledgeOrReveal) game =
[ privateMessage to necromancersTurnPrivateText ]
| has (variant . noRoleReveal) game =
[ privateMessage to necromancersTurnPrivateText ]
| otherwise =
[ publicMessage necromancersTurnPublicText
, privateMessage to necromancersTurnPrivateText
]
oraclesTurnMessages :: Text -> Game -> [Message]
oraclesTurnMessages to game
| has (variant . noRoleKnowledge) game =
[ privateMessage to oraclesTurnPrivateText ]
| has (variant . noRoleKnowledgeOrReveal) game =
[ privateMessage to oraclesTurnPrivateText ]
| has (variant . noRoleReveal) game =
[ privateMessage to oraclesTurnPrivateText ]
| otherwise =
[ publicMessage oraclesTurnPublicText
, privateMessage to oraclesTurnPrivateText
]
orphansTurnMessages :: Text -> Game -> [Message]
orphansTurnMessages to game
| has (variant . noRoleKnowledge) game =
[ privateMessage to orphansTurnPrivateText ]
| has (variant . noRoleKnowledgeOrReveal) game =
[ privateMessage to orphansTurnPrivateText ]
| has (variant . noRoleReveal) game =
[ privateMessage to orphansTurnPrivateText ]
| otherwise =
[ publicMessage orphansTurnPublicText
, privateMessage to orphansTurnPrivateText
]
protectorsTurnMessages :: Text -> Game -> [Message]
protectorsTurnMessages to game
| has (variant . noRoleKnowledge) game =
[ privateMessage to protectorsTurnPrivateText ]
| has (variant . noRoleKnowledgeOrReveal) game =
[ privateMessage to protectorsTurnPrivateText ]
| has (variant . noRoleReveal) game =
[ privateMessage to protectorsTurnPrivateText ]
| otherwise =
[ publicMessage protectorsTurnPublicText
, privateMessage to protectorsTurnPrivateText
]
scapegoatsTurnMessage :: Game -> Message
scapegoatsTurnMessage = publicMessage . scapegoatsTurnText
seersTurnMessages :: Text -> Game -> [Message]
seersTurnMessages to game
| has (variant . noRoleKnowledge) game =
[ privateMessage to seersTurnPrivateText ]
| has (variant . noRoleKnowledgeOrReveal) game =
[ privateMessage to seersTurnPrivateText ]
| has (variant . noRoleReveal) game =
[ privateMessage to seersTurnPrivateText ]
| otherwise =
[ publicMessage seersTurnPublicText
, privateMessage to seersTurnPrivateText
]
villageDrunksTurnMessages :: Game -> [Message]
villageDrunksTurnMessages game
| has (variant . noRoleKnowledge) game = []
| has (variant . noRoleKnowledgeOrReveal) game = []
| has (variant . noRoleReveal) game = []
| otherwise = [publicMessage villageDrunksTurnText]
sunriseMessage :: Message
sunriseMessage = publicMessage sunriseText
nightFallsMessage :: Message
nightFallsMessage = publicMessage sunsetText
villagesTurnMessage :: Message
villagesTurnMessage = publicMessage villagesTurnText
firstWerewolvesTurnMessages :: Game -> [Message]
firstWerewolvesTurnMessages game =
[privateMessage (player ^. name) (firstWerewolvesTurnText player game)
| length werewolves > 1, player <- werewolves]
++ werewolvesTurnMessages (map (view name) werewolves) game
where
werewolves = game ^.. players . traverse . alive . filtered (is werewolf)
werewolvesTurnMessages :: [Text] -> Game -> [Message]
werewolvesTurnMessages tos game
| has (variant . noRoleKnowledge) game =
groupMessages tos werewolvesTurnPrivateText
| has (variant . noRoleKnowledgeOrReveal) game =
groupMessages tos werewolvesTurnPrivateText
| has (variant . noRoleReveal) game =
groupMessages tos werewolvesTurnPrivateText
| otherwise =
publicMessage werewolvesTurnPublicText
: groupMessages tos werewolvesTurnPrivateText
witchsTurnMessages :: Game -> [Message]
witchsTurnMessages game = concat
[ wakeUpMessages
, healMessages
, poisonMessages
, [passMessage]
]
where
to = game ^?! players . witches . name
wakeUpMessages
| has (variant . noRoleKnowledge) game = []
| has (variant . noRoleKnowledgeOrReveal) game = []
| has (variant . noRoleReveal) game = []
| otherwise = [publicMessage witchsTurnText]
passMessage = privateMessage to passText
healMessages
| game ^. healUsed = []
| hasn't votee game = []
| otherwise = [privateMessage to $ healText game]
poisonMessages
| game ^. poisonUsed = []
| otherwise = [privateMessage to poisonText]
playerWonMessage :: Text -> Message
playerWonMessage to = privateMessage to playerWonText
playerContributedMessage :: Text -> Message
playerContributedMessage to = privateMessage to playerContributedText
playerLostMessage :: Text -> Message
playerLostMessage to = privateMessage to playerLostText
playerKilledMessage :: Text -> Message
playerKilledMessage to = privateMessage to playerKilledText
orphanJoinedPackMessages :: Text -> Game -> [Message]
orphanJoinedPackMessages to game =
privateMessage to (orphanJoinedWerewolvesPrivateText game)
: groupMessages (map (view name) werewolves) (orphanJoinedWerewolvesGroupText game)
where
orphan = game ^?! players . villageDrunks
werewolves = game ^.. players . traverse . alive . filtered (is werewolf) \\ [orphan]
ferinaGruntsMessage :: Message
ferinaGruntsMessage = publicMessage druidsTurnText
jesterLynchedMessage :: Game -> Message
jesterLynchedMessage = publicMessage . jesterLynchedText
noPlayerLynchedMessage :: Message
noPlayerLynchedMessage = publicMessage noPlayerLynchedText
werewolfLynchedMessage :: Player -> Game -> Message
werewolfLynchedMessage player game
| has (variant . noRoleKnowledgeOrReveal) game = publicMessage $ NoRoleKnowledgeOrReveal.playerLynchedText player
| has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerLynchedText player
| otherwise = publicMessage $ Standard.werewolfLynchedText player
playerLynchedMessage :: Player -> Game -> Message
playerLynchedMessage player game
| has (variant . noRoleKnowledgeOrReveal) game = publicMessage $ NoRoleKnowledgeOrReveal.playerLynchedText player
| has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerLynchedText player
| otherwise = publicMessage $ Standard.playerLynchedText player
saintLynchedMessage :: [Player] -> Game -> Message
saintLynchedMessage voters game
| has (variant . noRoleKnowledgeOrReveal) game = publicMessage $ NoRoleKnowledgeOrReveal.saintLynchedText voters
| has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.saintLynchedText voters
| otherwise = publicMessage $ Standard.saintLynchedText voters
scapegoatLynchedMessage :: Game -> Message
scapegoatLynchedMessage = publicMessage . scapegoatLynchedText
scapegoatChoseAllowedVotersMessage :: Game -> Message
scapegoatChoseAllowedVotersMessage = publicMessage . scapegoatsTurnEndedText
noPlayerDevouredMessage :: Message
noPlayerDevouredMessage = publicMessage noPlayerDevouredText
playerDevouredMessage :: Player -> Game -> Message
playerDevouredMessage player game
| has (variant . noRoleKnowledgeOrReveal) game = publicMessage $ NoRoleKnowledgeOrReveal.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 . noRoleKnowledgeOrReveal) game = publicMessage $ NoRoleKnowledgeOrReveal.playerPoisonedText player
| has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerPoisonedText player
| otherwise = publicMessage $ Standard.playerPoisonedText player
playerSeenMessage :: Text -> Player -> Message
playerSeenMessage to player
| is alphaWolf player = privateMessage to $ alphaWolfSeenText player
| is lycan player = privateMessage to $ lycanSeenText player
| otherwise = privateMessage to $ playerSeenText player
playerTurnedToStoneMessage :: Player -> Game -> Message
playerTurnedToStoneMessage player game
| has (variant . noRoleKnowledgeOrReveal) game = publicMessage $ NoRoleKnowledgeOrReveal.playerTurnedToStoneText player
| has (variant . noRoleReveal) game = publicMessage $ NoRoleReveal.playerTurnedToStoneText player
| otherwise = publicMessage $ Standard.playerTurnedToStoneText player
villageDrunkJoinedVillageMessage :: Text -> Message
villageDrunkJoinedVillageMessage to = privateMessage to villageDrunkJoinedVillageText
villageDrunkJoinedPackMessages :: Text -> Game -> [Message]
villageDrunkJoinedPackMessages to game =
privateMessage to (villageDrunkJoinedWerewolvesPrivateText game)
: groupMessages (map (view name) werewolves) (villageDrunkJoinedWerewolvesGroupText game)
where
villageDrunk = game ^?! players . villageDrunks
werewolves = game ^.. players . traverse . alive . filtered (is werewolf) \\ [villageDrunk]
zombiesReturnedToGraveMessage :: Game -> Message
zombiesReturnedToGraveMessage = publicMessage . zombiesReturnedToGraveText