{-# LANGUAGE DeriveGeneric #-}
-- | Factions taking part in the game, e.g., a hero faction, a monster faction
-- and an animal faction.
module Game.LambdaHack.Common.Faction
  ( FactionDict, Faction(..), Diplomacy(..)
  , Status(..), Challenge(..)
  , gleader, isHorrorFact, noRunWithMulti, isAIFact, autoDungeonLevel
  , automatePlayer, isFoe, isFriend
  , difficultyBound, difficultyDefault, difficultyCoeff, difficultyInverse
  , defaultChallenge, possibleActorFactions
#ifdef EXPOSE_INTERNAL
    -- * Internal operations
  , Dipl
#endif
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude

import           Data.Binary
import qualified Data.EnumMap.Strict as EM
import qualified Data.IntMap.Strict as IM
import           GHC.Generics (Generic)

import           Game.LambdaHack.Common.Item
import           Game.LambdaHack.Common.Types
import           Game.LambdaHack.Content.ItemKind (ItemKind)
import qualified Game.LambdaHack.Content.ItemKind as IK
import           Game.LambdaHack.Content.ModeKind
import qualified Game.LambdaHack.Definition.Ability as Ability
import qualified Game.LambdaHack.Definition.Color as Color
import           Game.LambdaHack.Definition.Defs

-- | All factions in the game, indexed by faction identifier.
type FactionDict = EM.EnumMap FactionId Faction

-- | The faction datatype.
data Faction = Faction
  { Faction -> Text
gname     :: Text            -- ^ individual name
  , Faction -> Color
gcolor    :: Color.Color     -- ^ color of actors or their frames
  , Faction -> Player
gplayer   :: Player          -- ^ the player spec for this faction
  , Faction -> [(Int, Int, GroupName ItemKind)]
ginitial  :: [(Int, Int, GroupName ItemKind)]  -- ^ initial actors
  , Faction -> Dipl
gdipl     :: Dipl            -- ^ diplomatic standing
  , Faction -> Maybe Status
gquit     :: Maybe Status    -- ^ cause of game end/exit
  , Faction -> Maybe ActorId
_gleader  :: Maybe ActorId   -- ^ the leader of the faction; don't use
                                 --   in place of sleader on clients
  , Faction -> ItemBag
gsha      :: ItemBag         -- ^ faction's shared inventory
  , Faction -> EnumMap (ContentId ItemKind) Int
gvictims  :: EM.EnumMap (ContentId ItemKind) Int  -- ^ members killed
  , Faction
-> EnumMap
     (ContentId ModeKind) (IntMap (EnumMap (ContentId ItemKind) Int))
gvictimsD :: EM.EnumMap (ContentId ModeKind)
                            (IM.IntMap (EM.EnumMap (ContentId ItemKind) Int))
      -- ^ members killed in the past, by game mode and difficulty level
  }
  deriving (Int -> Faction -> ShowS
[Faction] -> ShowS
Faction -> String
(Int -> Faction -> ShowS)
-> (Faction -> String) -> ([Faction] -> ShowS) -> Show Faction
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Faction] -> ShowS
$cshowList :: [Faction] -> ShowS
show :: Faction -> String
$cshow :: Faction -> String
showsPrec :: Int -> Faction -> ShowS
$cshowsPrec :: Int -> Faction -> ShowS
Show, Faction -> Faction -> Bool
(Faction -> Faction -> Bool)
-> (Faction -> Faction -> Bool) -> Eq Faction
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Faction -> Faction -> Bool
$c/= :: Faction -> Faction -> Bool
== :: Faction -> Faction -> Bool
$c== :: Faction -> Faction -> Bool
Eq, (forall x. Faction -> Rep Faction x)
-> (forall x. Rep Faction x -> Faction) -> Generic Faction
forall x. Rep Faction x -> Faction
forall x. Faction -> Rep Faction x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Faction x -> Faction
$cfrom :: forall x. Faction -> Rep Faction x
Generic)

instance Binary Faction

-- | Diplomacy states. Higher overwrite lower in case of asymmetric content.
data Diplomacy =
    Unknown
  | Neutral
  | Alliance
  | War
  deriving (Int -> Diplomacy -> ShowS
[Diplomacy] -> ShowS
Diplomacy -> String
(Int -> Diplomacy -> ShowS)
-> (Diplomacy -> String)
-> ([Diplomacy] -> ShowS)
-> Show Diplomacy
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Diplomacy] -> ShowS
$cshowList :: [Diplomacy] -> ShowS
show :: Diplomacy -> String
$cshow :: Diplomacy -> String
showsPrec :: Int -> Diplomacy -> ShowS
$cshowsPrec :: Int -> Diplomacy -> ShowS
Show, Diplomacy -> Diplomacy -> Bool
(Diplomacy -> Diplomacy -> Bool)
-> (Diplomacy -> Diplomacy -> Bool) -> Eq Diplomacy
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Diplomacy -> Diplomacy -> Bool
$c/= :: Diplomacy -> Diplomacy -> Bool
== :: Diplomacy -> Diplomacy -> Bool
$c== :: Diplomacy -> Diplomacy -> Bool
Eq, Eq Diplomacy
Eq Diplomacy =>
(Diplomacy -> Diplomacy -> Ordering)
-> (Diplomacy -> Diplomacy -> Bool)
-> (Diplomacy -> Diplomacy -> Bool)
-> (Diplomacy -> Diplomacy -> Bool)
-> (Diplomacy -> Diplomacy -> Bool)
-> (Diplomacy -> Diplomacy -> Diplomacy)
-> (Diplomacy -> Diplomacy -> Diplomacy)
-> Ord Diplomacy
Diplomacy -> Diplomacy -> Bool
Diplomacy -> Diplomacy -> Ordering
Diplomacy -> Diplomacy -> Diplomacy
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Diplomacy -> Diplomacy -> Diplomacy
$cmin :: Diplomacy -> Diplomacy -> Diplomacy
max :: Diplomacy -> Diplomacy -> Diplomacy
$cmax :: Diplomacy -> Diplomacy -> Diplomacy
>= :: Diplomacy -> Diplomacy -> Bool
$c>= :: Diplomacy -> Diplomacy -> Bool
> :: Diplomacy -> Diplomacy -> Bool
$c> :: Diplomacy -> Diplomacy -> Bool
<= :: Diplomacy -> Diplomacy -> Bool
$c<= :: Diplomacy -> Diplomacy -> Bool
< :: Diplomacy -> Diplomacy -> Bool
$c< :: Diplomacy -> Diplomacy -> Bool
compare :: Diplomacy -> Diplomacy -> Ordering
$ccompare :: Diplomacy -> Diplomacy -> Ordering
$cp1Ord :: Eq Diplomacy
Ord, Int -> Diplomacy
Diplomacy -> Int
Diplomacy -> [Diplomacy]
Diplomacy -> Diplomacy
Diplomacy -> Diplomacy -> [Diplomacy]
Diplomacy -> Diplomacy -> Diplomacy -> [Diplomacy]
(Diplomacy -> Diplomacy)
-> (Diplomacy -> Diplomacy)
-> (Int -> Diplomacy)
-> (Diplomacy -> Int)
-> (Diplomacy -> [Diplomacy])
-> (Diplomacy -> Diplomacy -> [Diplomacy])
-> (Diplomacy -> Diplomacy -> [Diplomacy])
-> (Diplomacy -> Diplomacy -> Diplomacy -> [Diplomacy])
-> Enum Diplomacy
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Diplomacy -> Diplomacy -> Diplomacy -> [Diplomacy]
$cenumFromThenTo :: Diplomacy -> Diplomacy -> Diplomacy -> [Diplomacy]
enumFromTo :: Diplomacy -> Diplomacy -> [Diplomacy]
$cenumFromTo :: Diplomacy -> Diplomacy -> [Diplomacy]
enumFromThen :: Diplomacy -> Diplomacy -> [Diplomacy]
$cenumFromThen :: Diplomacy -> Diplomacy -> [Diplomacy]
enumFrom :: Diplomacy -> [Diplomacy]
$cenumFrom :: Diplomacy -> [Diplomacy]
fromEnum :: Diplomacy -> Int
$cfromEnum :: Diplomacy -> Int
toEnum :: Int -> Diplomacy
$ctoEnum :: Int -> Diplomacy
pred :: Diplomacy -> Diplomacy
$cpred :: Diplomacy -> Diplomacy
succ :: Diplomacy -> Diplomacy
$csucc :: Diplomacy -> Diplomacy
Enum, (forall x. Diplomacy -> Rep Diplomacy x)
-> (forall x. Rep Diplomacy x -> Diplomacy) -> Generic Diplomacy
forall x. Rep Diplomacy x -> Diplomacy
forall x. Diplomacy -> Rep Diplomacy x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Diplomacy x -> Diplomacy
$cfrom :: forall x. Diplomacy -> Rep Diplomacy x
Generic)

instance Binary Diplomacy

type Dipl = EM.EnumMap FactionId Diplomacy

-- | Current game status.
data Status = Status
  { Status -> Outcome
stOutcome :: Outcome  -- ^ current game outcome
  , Status -> Int
stDepth   :: Int      -- ^ depth of the final encounter
  , Status -> Maybe (GroupName ModeKind)
stNewGame :: Maybe (GroupName ModeKind)
                          -- ^ new game group to start, if any
  }
  deriving (Int -> Status -> ShowS
[Status] -> ShowS
Status -> String
(Int -> Status -> ShowS)
-> (Status -> String) -> ([Status] -> ShowS) -> Show Status
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Status] -> ShowS
$cshowList :: [Status] -> ShowS
show :: Status -> String
$cshow :: Status -> String
showsPrec :: Int -> Status -> ShowS
$cshowsPrec :: Int -> Status -> ShowS
Show, Status -> Status -> Bool
(Status -> Status -> Bool)
-> (Status -> Status -> Bool) -> Eq Status
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Status -> Status -> Bool
$c/= :: Status -> Status -> Bool
== :: Status -> Status -> Bool
$c== :: Status -> Status -> Bool
Eq, Eq Status
Eq Status =>
(Status -> Status -> Ordering)
-> (Status -> Status -> Bool)
-> (Status -> Status -> Bool)
-> (Status -> Status -> Bool)
-> (Status -> Status -> Bool)
-> (Status -> Status -> Status)
-> (Status -> Status -> Status)
-> Ord Status
Status -> Status -> Bool
Status -> Status -> Ordering
Status -> Status -> Status
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Status -> Status -> Status
$cmin :: Status -> Status -> Status
max :: Status -> Status -> Status
$cmax :: Status -> Status -> Status
>= :: Status -> Status -> Bool
$c>= :: Status -> Status -> Bool
> :: Status -> Status -> Bool
$c> :: Status -> Status -> Bool
<= :: Status -> Status -> Bool
$c<= :: Status -> Status -> Bool
< :: Status -> Status -> Bool
$c< :: Status -> Status -> Bool
compare :: Status -> Status -> Ordering
$ccompare :: Status -> Status -> Ordering
$cp1Ord :: Eq Status
Ord, (forall x. Status -> Rep Status x)
-> (forall x. Rep Status x -> Status) -> Generic Status
forall x. Rep Status x -> Status
forall x. Status -> Rep Status x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Status x -> Status
$cfrom :: forall x. Status -> Rep Status x
Generic)

instance Binary Status

data Challenge = Challenge
  { Challenge -> Int
cdiff :: Int   -- ^ game difficulty level (HP bonus or malus)
  , Challenge -> Bool
cwolf :: Bool  -- ^ lone wolf challenge (only one starting character)
  , Challenge -> Bool
cfish :: Bool  -- ^ cold fish challenge (no healing from enemies)
  }
  deriving (Int -> Challenge -> ShowS
[Challenge] -> ShowS
Challenge -> String
(Int -> Challenge -> ShowS)
-> (Challenge -> String)
-> ([Challenge] -> ShowS)
-> Show Challenge
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Challenge] -> ShowS
$cshowList :: [Challenge] -> ShowS
show :: Challenge -> String
$cshow :: Challenge -> String
showsPrec :: Int -> Challenge -> ShowS
$cshowsPrec :: Int -> Challenge -> ShowS
Show, Challenge -> Challenge -> Bool
(Challenge -> Challenge -> Bool)
-> (Challenge -> Challenge -> Bool) -> Eq Challenge
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Challenge -> Challenge -> Bool
$c/= :: Challenge -> Challenge -> Bool
== :: Challenge -> Challenge -> Bool
$c== :: Challenge -> Challenge -> Bool
Eq, Eq Challenge
Eq Challenge =>
(Challenge -> Challenge -> Ordering)
-> (Challenge -> Challenge -> Bool)
-> (Challenge -> Challenge -> Bool)
-> (Challenge -> Challenge -> Bool)
-> (Challenge -> Challenge -> Bool)
-> (Challenge -> Challenge -> Challenge)
-> (Challenge -> Challenge -> Challenge)
-> Ord Challenge
Challenge -> Challenge -> Bool
Challenge -> Challenge -> Ordering
Challenge -> Challenge -> Challenge
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Challenge -> Challenge -> Challenge
$cmin :: Challenge -> Challenge -> Challenge
max :: Challenge -> Challenge -> Challenge
$cmax :: Challenge -> Challenge -> Challenge
>= :: Challenge -> Challenge -> Bool
$c>= :: Challenge -> Challenge -> Bool
> :: Challenge -> Challenge -> Bool
$c> :: Challenge -> Challenge -> Bool
<= :: Challenge -> Challenge -> Bool
$c<= :: Challenge -> Challenge -> Bool
< :: Challenge -> Challenge -> Bool
$c< :: Challenge -> Challenge -> Bool
compare :: Challenge -> Challenge -> Ordering
$ccompare :: Challenge -> Challenge -> Ordering
$cp1Ord :: Eq Challenge
Ord, (forall x. Challenge -> Rep Challenge x)
-> (forall x. Rep Challenge x -> Challenge) -> Generic Challenge
forall x. Rep Challenge x -> Challenge
forall x. Challenge -> Rep Challenge x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Challenge x -> Challenge
$cfrom :: forall x. Challenge -> Rep Challenge x
Generic)

instance Binary Challenge

gleader :: Faction -> Maybe ActorId
gleader :: Faction -> Maybe ActorId
gleader = Faction -> Maybe ActorId
_gleader

-- | Tell whether the faction consists of summoned horrors only.
--
-- Horror player is special, for summoned actors that don't belong to any
-- of the main players of a given game. E.g., animals summoned during
-- a skirmish game between two hero factions land in the horror faction.
-- In every game, either all factions for which summoning items exist
-- should be present or a horror player should be added to host them.
isHorrorFact :: Faction -> Bool
isHorrorFact :: Faction -> Bool
isHorrorFact fact :: Faction
fact = GroupName ItemKind
horrorGroup GroupName ItemKind -> [GroupName ItemKind] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Player -> [GroupName ItemKind]
fgroups (Faction -> Player
gplayer Faction
fact)

-- A faction where other actors move at once or where some of leader change
-- is automatic can't run with multiple actors at once. That would be
-- overpowered or too complex to keep correct.
--
-- Note that this doesn't take into account individual actor skills,
-- so this is overly restrictive and, OTOH, sometimes running will fail
-- or behave wierdly regardless. But it's simple and easy to understand
-- by the UI user.
noRunWithMulti :: Faction -> Bool
noRunWithMulti :: Faction -> Bool
noRunWithMulti fact :: Faction
fact =
  let skillsOther :: Skills
skillsOther = Player -> Skills
fskillsOther (Player -> Skills) -> Player -> Skills
forall a b. (a -> b) -> a -> b
$ Faction -> Player
gplayer Faction
fact
  in Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkMove Skills
skillsOther Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= 0
     Bool -> Bool -> Bool
|| case Player -> LeaderMode
fleaderMode (Faction -> Player
gplayer Faction
fact) of
          LeaderNull -> Bool
True
          LeaderAI AutoLeader{} -> Bool
True
          LeaderUI AutoLeader{..} -> Bool
autoDungeon Bool -> Bool -> Bool
|| Bool
autoLevel

isAIFact :: Faction -> Bool
isAIFact :: Faction -> Bool
isAIFact fact :: Faction
fact =
  case Player -> LeaderMode
fleaderMode (Faction -> Player
gplayer Faction
fact) of
    LeaderNull -> Bool
True
    LeaderAI _ -> Bool
True
    LeaderUI _ -> Bool
False

autoDungeonLevel :: Faction -> (Bool, Bool)
autoDungeonLevel :: Faction -> (Bool, Bool)
autoDungeonLevel fact :: Faction
fact = case Player -> LeaderMode
fleaderMode (Faction -> Player
gplayer Faction
fact) of
                          LeaderNull -> (Bool
False, Bool
False)
                          LeaderAI AutoLeader{..} -> (Bool
autoDungeon, Bool
autoLevel)
                          LeaderUI AutoLeader{..} -> (Bool
autoDungeon, Bool
autoLevel)

automatePlayer :: Bool -> Player -> Player
automatePlayer :: Bool -> Player -> Player
automatePlayer st :: Bool
st pl :: Player
pl =
  let autoLeader :: Bool -> Player -> LeaderMode
autoLeader False Player{fleaderMode :: Player -> LeaderMode
fleaderMode=LeaderAI auto :: AutoLeader
auto} = AutoLeader -> LeaderMode
LeaderUI AutoLeader
auto
      autoLeader True Player{fleaderMode :: Player -> LeaderMode
fleaderMode=LeaderUI auto :: AutoLeader
auto} = AutoLeader -> LeaderMode
LeaderAI AutoLeader
auto
      autoLeader _ Player{LeaderMode
fleaderMode :: LeaderMode
fleaderMode :: Player -> LeaderMode
fleaderMode} = LeaderMode
fleaderMode
  in Player
pl {fleaderMode :: LeaderMode
fleaderMode = Bool -> Player -> LeaderMode
autoLeader Bool
st Player
pl}

-- | Check if factions are at war. Assumes symmetry.
isFoe :: FactionId -> Faction -> FactionId -> Bool
isFoe :: FactionId -> Faction -> FactionId -> Bool
isFoe fid1 :: FactionId
fid1 fact1 :: Faction
fact1 fid2 :: FactionId
fid2 =
  FactionId
fid1 FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
/= FactionId
fid2  -- shortcut
  Bool -> Bool -> Bool
&& Diplomacy
War Diplomacy -> Diplomacy -> Bool
forall a. Eq a => a -> a -> Bool
== Diplomacy -> FactionId -> Dipl -> Diplomacy
forall k a. Enum k => a -> k -> EnumMap k a -> a
EM.findWithDefault Diplomacy
Unknown FactionId
fid2 (Faction -> Dipl
gdipl Faction
fact1)

-- | Check if factions are allied. Assumes symmetry.
isAlly :: Faction -> FactionId -> Bool
{-# INLINE isAlly #-}
isAlly :: Faction -> FactionId -> Bool
isAlly fact1 :: Faction
fact1 fid2 :: FactionId
fid2 = Diplomacy
Alliance Diplomacy -> Diplomacy -> Bool
forall a. Eq a => a -> a -> Bool
== Diplomacy -> FactionId -> Dipl -> Diplomacy
forall k a. Enum k => a -> k -> EnumMap k a -> a
EM.findWithDefault Diplomacy
Unknown FactionId
fid2 (Faction -> Dipl
gdipl Faction
fact1)

-- | Check if factions are allied or are the same faction. Assumes symmetry.
isFriend :: FactionId -> Faction -> FactionId -> Bool
isFriend :: FactionId -> Faction -> FactionId -> Bool
isFriend fid1 :: FactionId
fid1 fact1 :: Faction
fact1 fid2 :: FactionId
fid2 = FactionId
fid1 FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
fid2 Bool -> Bool -> Bool
|| Faction -> FactionId -> Bool
isAlly Faction
fact1 FactionId
fid2

difficultyBound :: Int
difficultyBound :: Int
difficultyBound = 9

difficultyDefault :: Int
difficultyDefault :: Int
difficultyDefault = (1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
difficultyBound) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 2

-- The function is its own inverse.
difficultyCoeff :: Int -> Int
difficultyCoeff :: Int -> Int
difficultyCoeff n :: Int
n = Int
difficultyDefault Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n

-- The function is its own inverse.
difficultyInverse :: Int -> Int
difficultyInverse :: Int -> Int
difficultyInverse n :: Int
n = Int
difficultyBound Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n

defaultChallenge :: Challenge
defaultChallenge :: Challenge
defaultChallenge = $WChallenge :: Int -> Bool -> Bool -> Challenge
Challenge { cdiff :: Int
cdiff = Int
difficultyDefault
                             , cwolf :: Bool
cwolf = Bool
False
                             , cfish :: Bool
cfish = Bool
False }

possibleActorFactions :: ItemKind -> FactionDict -> [(FactionId, Faction)]
possibleActorFactions :: ItemKind -> FactionDict -> [(FactionId, Faction)]
possibleActorFactions itemKind :: ItemKind
itemKind factionD :: FactionDict
factionD =
  let freqNames :: [GroupName ItemKind]
freqNames = ((GroupName ItemKind, Int) -> GroupName ItemKind)
-> [(GroupName ItemKind, Int)] -> [GroupName ItemKind]
forall a b. (a -> b) -> [a] -> [b]
map (GroupName ItemKind, Int) -> GroupName ItemKind
forall a b. (a, b) -> a
fst ([(GroupName ItemKind, Int)] -> [GroupName ItemKind])
-> [(GroupName ItemKind, Int)] -> [GroupName ItemKind]
forall a b. (a -> b) -> a -> b
$ ItemKind -> [(GroupName ItemKind, Int)]
IK.ifreq ItemKind
itemKind
      f :: (FactionId, Faction) -> Bool
f (_, fact :: Faction
fact) = (GroupName ItemKind -> Bool) -> [GroupName ItemKind] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (GroupName ItemKind -> [GroupName ItemKind] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Player -> [GroupName ItemKind]
fgroups (Faction -> Player
gplayer Faction
fact)) [GroupName ItemKind]
freqNames
      fidFactsRaw :: [(FactionId, Faction)]
fidFactsRaw = ((FactionId, Faction) -> Bool)
-> [(FactionId, Faction)] -> [(FactionId, Faction)]
forall a. (a -> Bool) -> [a] -> [a]
filter (FactionId, Faction) -> Bool
f ([(FactionId, Faction)] -> [(FactionId, Faction)])
-> [(FactionId, Faction)] -> [(FactionId, Faction)]
forall a b. (a -> b) -> a -> b
$ FactionDict -> [(FactionId, Faction)]
forall k a. Enum k => EnumMap k a -> [(k, a)]
EM.assocs FactionDict
factionD
  in if [(FactionId, Faction)] -> Bool
forall a. [a] -> Bool
null [(FactionId, Faction)]
fidFactsRaw
     then ((FactionId, Faction) -> Bool)
-> [(FactionId, Faction)] -> [(FactionId, Faction)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Faction -> Bool
isHorrorFact (Faction -> Bool)
-> ((FactionId, Faction) -> Faction)
-> (FactionId, Faction)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FactionId, Faction) -> Faction
forall a b. (a, b) -> b
snd) ([(FactionId, Faction)] -> [(FactionId, Faction)])
-> [(FactionId, Faction)] -> [(FactionId, Faction)]
forall a b. (a -> b) -> a -> b
$ FactionDict -> [(FactionId, Faction)]
forall k a. Enum k => EnumMap k a -> [(k, a)]
EM.assocs FactionDict
factionD  -- fall back
     else [(FactionId, Faction)]
fidFactsRaw