    {-# LANGUAGE DeriveGeneric #-}
    -- | The type of item aspects and its operations.
    module Game.LambdaHack.Common.ItemAspect
      ( AspectRecord(..), KindMean(..)
      , emptyAspectRecord, addMeanAspect, castAspect, aspectsRandom
      , aspectRecordToList, rollAspectRecord, getSkill, checkFlag, meanAspect
      , onlyMinorEffects, itemTrajectory, totalRange, isHumanTrinket
      , goesIntoEqp, loreFromContainer
    #ifdef EXPOSE_INTERNAL
        -- * Internal operations
      , ceilingMeanDice
    #endif
      ) where

    import Prelude ()

    import Game.LambdaHack.Core.Prelude

    import qualified Control.Monad.Trans.State.Strict as St
    import           Data.Binary
    import qualified Data.EnumSet as ES
    import           Data.Hashable (Hashable)
    import qualified Data.Text as T
    import           GHC.Generics (Generic)
    import qualified System.Random.SplitMix32 as SM

    import           Game.LambdaHack.Common.Point
    import           Game.LambdaHack.Common.Time
    import           Game.LambdaHack.Common.Types
    import           Game.LambdaHack.Common.Vector
    import qualified Game.LambdaHack.Content.ItemKind as IK
    import qualified Game.LambdaHack.Core.Dice as Dice
    import           Game.LambdaHack.Core.Random
    import qualified Game.LambdaHack.Definition.Ability as Ability
    import           Game.LambdaHack.Definition.Defs

    -- | Record of skills conferred by an item as well as of item flags
    -- and other item aspects.
    data AspectRecord = AspectRecord
      { AspectRecord -> Int
    aTimeout   :: Int
      , AspectRecord -> Skills
    aSkills    :: Ability.Skills
      , AspectRecord -> Flags
    aFlags     :: Ability.Flags
      , AspectRecord -> Text
    aELabel    :: Text
      , AspectRecord -> ThrowMod
    aToThrow   :: IK.ThrowMod
      , AspectRecord -> Maybe (GroupName ItemKind)
    aPresentAs :: Maybe (GroupName IK.ItemKind)
      , AspectRecord -> Maybe EqpSlot
    aEqpSlot   :: Maybe Ability.EqpSlot
      }
      deriving (Int -> AspectRecord -> ShowS
    [AspectRecord] -> ShowS
    AspectRecord -> String
    (Int -> AspectRecord -> ShowS)
    -> (AspectRecord -> String)
    -> ([AspectRecord] -> ShowS)
    -> Show AspectRecord
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> AspectRecord -> ShowS
    showsPrec :: Int -> AspectRecord -> ShowS
    $cshow :: AspectRecord -> String
    show :: AspectRecord -> String
    $cshowList :: [AspectRecord] -> ShowS
    showList :: [AspectRecord] -> ShowS
    Show, AspectRecord -> AspectRecord -> Bool
    (AspectRecord -> AspectRecord -> Bool)
    -> (AspectRecord -> AspectRecord -> Bool) -> Eq AspectRecord
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: AspectRecord -> AspectRecord -> Bool
    == :: AspectRecord -> AspectRecord -> Bool
    $c/= :: AspectRecord -> AspectRecord -> Bool
    /= :: AspectRecord -> AspectRecord -> Bool
    Eq, Eq AspectRecord
    Eq AspectRecord =>
    (AspectRecord -> AspectRecord -> Ordering)
    -> (AspectRecord -> AspectRecord -> Bool)
    -> (AspectRecord -> AspectRecord -> Bool)
    -> (AspectRecord -> AspectRecord -> Bool)
    -> (AspectRecord -> AspectRecord -> Bool)
    -> (AspectRecord -> AspectRecord -> AspectRecord)
    -> (AspectRecord -> AspectRecord -> AspectRecord)
    -> Ord AspectRecord
    AspectRecord -> AspectRecord -> Bool
    AspectRecord -> AspectRecord -> Ordering
    AspectRecord -> AspectRecord -> AspectRecord
    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
    $ccompare :: AspectRecord -> AspectRecord -> Ordering
    compare :: AspectRecord -> AspectRecord -> Ordering
    $c< :: AspectRecord -> AspectRecord -> Bool
    < :: AspectRecord -> AspectRecord -> Bool
    $c<= :: AspectRecord -> AspectRecord -> Bool
    <= :: AspectRecord -> AspectRecord -> Bool
    $c> :: AspectRecord -> AspectRecord -> Bool
    > :: AspectRecord -> AspectRecord -> Bool
    $c>= :: AspectRecord -> AspectRecord -> Bool
    >= :: AspectRecord -> AspectRecord -> Bool
    $cmax :: AspectRecord -> AspectRecord -> AspectRecord
    max :: AspectRecord -> AspectRecord -> AspectRecord
    $cmin :: AspectRecord -> AspectRecord -> AspectRecord
    min :: AspectRecord -> AspectRecord -> AspectRecord
    Ord, (forall x. AspectRecord -> Rep AspectRecord x)
    -> (forall x. Rep AspectRecord x -> AspectRecord)
    -> Generic AspectRecord
    forall x. Rep AspectRecord x -> AspectRecord
    forall x. AspectRecord -> Rep AspectRecord x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. AspectRecord -> Rep AspectRecord x
    from :: forall x. AspectRecord -> Rep AspectRecord x
    $cto :: forall x. Rep AspectRecord x -> AspectRecord
    to :: forall x. Rep AspectRecord x -> AspectRecord
    Generic)

    instance Hashable AspectRecord

    instance Binary AspectRecord

    -- | Partial information about an item, deduced from its item kind.
    -- These are assigned to each 'IK.ItemKind'. The @kmConst@ flag says whether
    -- the item's aspect record is constant rather than random or dependent
    -- on item creation dungeon level.
    data KindMean = KindMean
      { KindMean -> Bool
    kmConst :: Bool  -- ^ whether the item doesn't need second identification
      , KindMean -> AspectRecord
    kmMean  :: AspectRecord  -- ^ mean value of item's possible aspect records
      }
      deriving (Int -> KindMean -> ShowS
    [KindMean] -> ShowS
    KindMean -> String
    (Int -> KindMean -> ShowS)
    -> (KindMean -> String) -> ([KindMean] -> ShowS) -> Show KindMean
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> KindMean -> ShowS
    showsPrec :: Int -> KindMean -> ShowS
    $cshow :: KindMean -> String
    show :: KindMean -> String
    $cshowList :: [KindMean] -> ShowS
    showList :: [KindMean] -> ShowS
    Show, KindMean -> KindMean -> Bool
    (KindMean -> KindMean -> Bool)
    -> (KindMean -> KindMean -> Bool) -> Eq KindMean
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: KindMean -> KindMean -> Bool
    == :: KindMean -> KindMean -> Bool
    $c/= :: KindMean -> KindMean -> Bool
    /= :: KindMean -> KindMean -> Bool
    Eq, Eq KindMean
    Eq KindMean =>
    (KindMean -> KindMean -> Ordering)
    -> (KindMean -> KindMean -> Bool)
    -> (KindMean -> KindMean -> Bool)
    -> (KindMean -> KindMean -> Bool)
    -> (KindMean -> KindMean -> Bool)
    -> (KindMean -> KindMean -> KindMean)
    -> (KindMean -> KindMean -> KindMean)
    -> Ord KindMean
    KindMean -> KindMean -> Bool
    KindMean -> KindMean -> Ordering
    KindMean -> KindMean -> KindMean
    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
    $ccompare :: KindMean -> KindMean -> Ordering
    compare :: KindMean -> KindMean -> Ordering
    $c< :: KindMean -> KindMean -> Bool
    < :: KindMean -> KindMean -> Bool
    $c<= :: KindMean -> KindMean -> Bool
    <= :: KindMean -> KindMean -> Bool
    $c> :: KindMean -> KindMean -> Bool
    > :: KindMean -> KindMean -> Bool
    $c>= :: KindMean -> KindMean -> Bool
    >= :: KindMean -> KindMean -> Bool
    $cmax :: KindMean -> KindMean -> KindMean
    max :: KindMean -> KindMean -> KindMean
    $cmin :: KindMean -> KindMean -> KindMean
    min :: KindMean -> KindMean -> KindMean
    Ord)

    emptyAspectRecord :: AspectRecord
    emptyAspectRecord :: AspectRecord
    emptyAspectRecord = AspectRecord
      { aTimeout :: Int
    aTimeout = Int
    0
      , aSkills :: Skills
    aSkills = Skills
    Ability.zeroSkills
      , aFlags :: Flags
    aFlags = EnumSet Flag -> Flags
    Ability.Flags EnumSet Flag
    forall k. EnumSet k
    ES.empty
      , aELabel :: Text
    aELabel = Text
    ""
      , aToThrow :: ThrowMod
    aToThrow = Int -> Int -> Int -> ThrowMod
    IK.ThrowMod Int
    100 Int
    100 Int
    1
      , aPresentAs :: Maybe (GroupName ItemKind)
    aPresentAs = Maybe (GroupName ItemKind)
    forall a. Maybe a
    Nothing
      , aEqpSlot :: Maybe EqpSlot
    aEqpSlot = Maybe EqpSlot
    forall a. Maybe a
    Nothing
      }

    castAspect :: Dice.AbsDepth -> Dice.AbsDepth -> AspectRecord -> IK.Aspect
               -> Rnd AspectRecord
    castAspect :: AbsDepth -> AbsDepth -> AspectRecord -> Aspect -> Rnd AspectRecord
    castAspect !AbsDepth
    ldepth !AbsDepth
    totalDepth !AspectRecord
    ar !Aspect
    asp =
      case Aspect
    asp of
        IK.Timeout Dice
    d -> do
          n <- AbsDepth -> AbsDepth -> Dice -> Rnd Int
    castDice AbsDepth
    ldepth AbsDepth
    totalDepth Dice
    d
          return $! assert (aTimeout ar == 0) $ ar {aTimeout = n}
        IK.AddSkill Skill
    sk Dice
    d -> do
          n <- AbsDepth -> AbsDepth -> Dice -> Rnd Int
    castDice AbsDepth
    ldepth AbsDepth
    totalDepth Dice
    d
          return $! if n /= 0
                    then ar {aSkills = Ability.addSk sk n (aSkills ar)}
                    else ar
        IK.SetFlag Flag
    feat ->
          AspectRecord -> Rnd AspectRecord
    forall a. a -> StateT SMGen Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (AspectRecord -> Rnd AspectRecord)
    -> AspectRecord -> Rnd AspectRecord
    forall a b. (a -> b) -> a -> b
    $! AspectRecord
    ar {aFlags = Ability.Flags
                                 $ ES.insert feat (Ability.flags $ aFlags ar)}
        IK.ELabel Text
    t -> AspectRecord -> Rnd AspectRecord
    forall a. a -> StateT SMGen Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (AspectRecord -> Rnd AspectRecord)
    -> AspectRecord -> Rnd AspectRecord
    forall a b. (a -> b) -> a -> b
    $! AspectRecord
    ar {aELabel = t}
        IK.ToThrow ThrowMod
    tt -> AspectRecord -> Rnd AspectRecord
    forall a. a -> StateT SMGen Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (AspectRecord -> Rnd AspectRecord)
    -> AspectRecord -> Rnd AspectRecord
    forall a b. (a -> b) -> a -> b
    $! AspectRecord
    ar {aToThrow = tt}
        IK.PresentAs GroupName ItemKind
    ha -> AspectRecord -> Rnd AspectRecord
    forall a. a -> StateT SMGen Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (AspectRecord -> Rnd AspectRecord)
    -> AspectRecord -> Rnd AspectRecord
    forall a b. (a -> b) -> a -> b
    $! AspectRecord
    ar {aPresentAs = Just ha}
        IK.EqpSlot EqpSlot
    slot -> AspectRecord -> Rnd AspectRecord
    forall a. a -> StateT SMGen Identity a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (AspectRecord -> Rnd AspectRecord)
    -> AspectRecord -> Rnd AspectRecord
    forall a b. (a -> b) -> a -> b
    $! AspectRecord
    ar {aEqpSlot = Just slot}
        IK.Odds Dice
    d [Aspect]
    aspects1 [Aspect]
    aspects2 -> do
          pick1 <- AbsDepth -> AbsDepth -> Dice -> Rnd Bool
    oddsDice AbsDepth
    ldepth AbsDepth
    totalDepth Dice
    d
          foldlM' (castAspect ldepth totalDepth) ar $
            if pick1 then aspects1 else aspects2

    -- If @False@, aspects of this kind are most probably fixed, not random
    -- nor dependent on dungeon level where the item is created.
    aspectsRandom :: [IK.Aspect] -> Bool
    aspectsRandom :: [Aspect] -> Bool
    aspectsRandom [Aspect]
    ass =
      let rollM :: Int -> Rnd AspectRecord
    rollM Int
    depth =
            (AspectRecord -> Aspect -> Rnd AspectRecord)
    -> AspectRecord -> [Aspect] -> Rnd AspectRecord
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> Rnd b) -> b -> t a -> Rnd b
    foldlM' (AbsDepth -> AbsDepth -> AspectRecord -> Aspect -> Rnd AspectRecord
    castAspect (Int -> AbsDepth
    Dice.AbsDepth Int
    depth) (Int -> AbsDepth
    Dice.AbsDepth Int
    10))
                    AspectRecord
    emptyAspectRecord [Aspect]
    ass
          gen :: SMGen
    gen = Word32 -> SMGen
    SM.mkSMGen Word32
    0
          (AspectRecord
    ar0, SMGen
    gen0) = Rnd AspectRecord -> SMGen -> (AspectRecord, SMGen)
    forall s a. State s a -> s -> (a, s)
    St.runState (Int -> Rnd AspectRecord
    rollM Int
    0) SMGen
    gen
          (AspectRecord
    ar1, SMGen
    gen1) = Rnd AspectRecord -> SMGen -> (AspectRecord, SMGen)
    forall s a. State s a -> s -> (a, s)
    St.runState (Int -> Rnd AspectRecord
    rollM Int
    10) SMGen
    gen0
      in SMGen -> String
    forall a. Show a => a -> String
    show SMGen
    gen String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    /= SMGen -> String
    forall a. Show a => a -> String
    show SMGen
    gen0 Bool -> Bool -> Bool
    || SMGen -> String
    forall a. Show a => a -> String
    show SMGen
    gen String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    /= SMGen -> String
    forall a. Show a => a -> String
    show SMGen
    gen1 Bool -> Bool -> Bool
    || AspectRecord
    ar0 AspectRecord -> AspectRecord -> Bool
    forall a. Eq a => a -> a -> Bool
    /= AspectRecord
    ar1

    addMeanAspect :: AspectRecord -> IK.Aspect -> AspectRecord
    addMeanAspect :: AspectRecord -> Aspect -> AspectRecord
    addMeanAspect !AspectRecord
    ar !Aspect
    asp =
      case Aspect
    asp of
        IK.Timeout Dice
    d ->
          let n :: Int
    n = Dice -> Int
    ceilingMeanDice Dice
    d
          in Bool -> AspectRecord -> AspectRecord
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert (AspectRecord -> Int
    aTimeout AspectRecord
    ar Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0) (AspectRecord -> AspectRecord) -> AspectRecord -> AspectRecord
    forall a b. (a -> b) -> a -> b
    $ AspectRecord
    ar {aTimeout = n}
        IK.AddSkill Skill
    sk Dice
    d ->
          let n :: Int
    n = Dice -> Int
    ceilingMeanDice Dice
    d
          in if Int
    n Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    0
             then AspectRecord
    ar {aSkills = Ability.addSk sk n (aSkills ar)}
             else AspectRecord
    ar
        IK.SetFlag Flag
    feat ->
          AspectRecord
    ar {aFlags = Ability.Flags $ ES.insert feat (Ability.flags $ aFlags ar)}
        IK.ELabel Text
    t -> AspectRecord
    ar {aELabel = t}
        IK.ToThrow ThrowMod
    tt -> AspectRecord
    ar {aToThrow = tt}
        IK.PresentAs GroupName ItemKind
    ha -> AspectRecord
    ar {aPresentAs = Just ha}
        IK.EqpSlot EqpSlot
    slot -> AspectRecord
    ar {aEqpSlot = Just slot}
        IK.Odds{} -> AspectRecord
    ar  -- can't tell, especially since we don't know the level

    ceilingMeanDice :: Dice.Dice -> Int
    ceilingMeanDice :: Dice -> Int
    ceilingMeanDice Dice
    d = Double -> Int
    forall b. Integral b => Double -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    ceiling (Double -> Int) -> Double -> Int
    forall a b. (a -> b) -> a -> b
    $ Dice -> Double
    Dice.meanDice Dice
    d

    aspectRecordToList :: AspectRecord -> [IK.Aspect]
    aspectRecordToList :: AspectRecord -> [Aspect]
    aspectRecordToList AspectRecord{Int
    Maybe EqpSlot
    Maybe (GroupName ItemKind)
    Text
    Flags
    Skills
    ThrowMod
    aTimeout :: AspectRecord -> Int
    aSkills :: AspectRecord -> Skills
    aFlags :: AspectRecord -> Flags
    aELabel :: AspectRecord -> Text
    aToThrow :: AspectRecord -> ThrowMod
    aPresentAs :: AspectRecord -> Maybe (GroupName ItemKind)
    aEqpSlot :: AspectRecord -> Maybe EqpSlot
    aTimeout :: Int
    aSkills :: Skills
    aFlags :: Flags
    aELabel :: Text
    aToThrow :: ThrowMod
    aPresentAs :: Maybe (GroupName ItemKind)
    aEqpSlot :: Maybe EqpSlot
    ..} =
      [Dice -> Aspect
    IK.Timeout (Dice -> Aspect) -> Dice -> Aspect
    forall a b. (a -> b) -> a -> b
    $ Int -> Dice
    Dice.intToDice Int
    aTimeout | Int
    aTimeout Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    0]
      [Aspect] -> [Aspect] -> [Aspect]
    forall a. [a] -> [a] -> [a]
    ++ [ Skill -> Dice -> Aspect
    IK.AddSkill Skill
    sk (Dice -> Aspect) -> Dice -> Aspect
    forall a b. (a -> b) -> a -> b
    $ Int -> Dice
    Dice.intToDice Int
    n
         | (Skill
    sk, Int
    n) <- Skills -> [(Skill, Int)]
    Ability.skillsToList Skills
    aSkills ]
      [Aspect] -> [Aspect] -> [Aspect]
    forall a. [a] -> [a] -> [a]
    ++ [Flag -> Aspect
    IK.SetFlag Flag
    feat | Flag
    feat <- EnumSet Flag -> [Flag]
    forall k. Enum k => EnumSet k -> [k]
    ES.elems (EnumSet Flag -> [Flag]) -> EnumSet Flag -> [Flag]
    forall a b. (a -> b) -> a -> b
    $ Flags -> EnumSet Flag
    Ability.flags Flags
    aFlags]
      [Aspect] -> [Aspect] -> [Aspect]
    forall a. [a] -> [a] -> [a]
    ++ [Text -> Aspect
    IK.ELabel Text
    aELabel | Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Text -> Bool
    T.null Text
    aELabel]
      [Aspect] -> [Aspect] -> [Aspect]
    forall a. [a] -> [a] -> [a]
    ++ [ThrowMod -> Aspect
    IK.ToThrow ThrowMod
    aToThrow | ThrowMod
    aToThrow ThrowMod -> ThrowMod -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int -> Int -> Int -> ThrowMod
    IK.ThrowMod Int
    100 Int
    100 Int
    1]
      [Aspect] -> [Aspect] -> [Aspect]
    forall a. [a] -> [a] -> [a]
    ++ [Aspect]
    -> (GroupName ItemKind -> [Aspect])
    -> Maybe (GroupName ItemKind)
    -> [Aspect]
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe [] (\GroupName ItemKind
    ha -> [GroupName ItemKind -> Aspect
    IK.PresentAs GroupName ItemKind
    ha]) Maybe (GroupName ItemKind)
    aPresentAs
      [Aspect] -> [Aspect] -> [Aspect]
    forall a. [a] -> [a] -> [a]
    ++ [Aspect] -> (EqpSlot -> [Aspect]) -> Maybe EqpSlot -> [Aspect]
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe [] (\EqpSlot
    slot -> [EqpSlot -> Aspect
    IK.EqpSlot EqpSlot
    slot]) Maybe EqpSlot
    aEqpSlot

    rollAspectRecord :: [IK.Aspect] -> Dice.AbsDepth -> Dice.AbsDepth
                     -> Rnd AspectRecord
    rollAspectRecord :: [Aspect] -> AbsDepth -> AbsDepth -> Rnd AspectRecord
    rollAspectRecord [Aspect]
    ass AbsDepth
    ldepth AbsDepth
    totalDepth =
      (AspectRecord -> Aspect -> Rnd AspectRecord)
    -> AspectRecord -> [Aspect] -> Rnd AspectRecord
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> Rnd b) -> b -> t a -> Rnd b
    foldlM' (AbsDepth -> AbsDepth -> AspectRecord -> Aspect -> Rnd AspectRecord
    castAspect AbsDepth
    ldepth AbsDepth
    totalDepth) AspectRecord
    emptyAspectRecord [Aspect]
    ass

    getSkill :: Ability.Skill -> AspectRecord -> Int
    {-# INLINE getSkill #-}
    getSkill :: Skill -> AspectRecord -> Int
    getSkill Skill
    sk AspectRecord
    ar = Skill -> Skills -> Int
    Ability.getSk Skill
    sk (Skills -> Int) -> Skills -> Int
    forall a b. (a -> b) -> a -> b
    $ AspectRecord -> Skills
    aSkills AspectRecord
    ar

    checkFlag :: Ability.Flag -> AspectRecord -> Bool
    {-# INLINE checkFlag #-}
    checkFlag :: Flag -> AspectRecord -> Bool
    checkFlag Flag
    flag AspectRecord
    ar = Flag -> Flags -> Bool
    Ability.checkFl Flag
    flag (AspectRecord -> Flags
    aFlags AspectRecord
    ar)

    meanAspect :: IK.ItemKind -> AspectRecord
    meanAspect :: ItemKind -> AspectRecord
    meanAspect ItemKind
    kind = (AspectRecord -> Aspect -> AspectRecord)
    -> AspectRecord -> [Aspect] -> AspectRecord
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' AspectRecord -> Aspect -> AspectRecord
    addMeanAspect AspectRecord
    emptyAspectRecord (ItemKind -> [Aspect]
    IK.iaspects ItemKind
    kind)

    -- Kinetic damage is not considered major effect, even though it
    -- identifies an item, when one hits with it. However, it's tedious
    -- to wait for weapon identification until first hit and also
    -- if a weapon is periodically activated, the kinetic damage would not apply,
    -- so we'd need special cases that force identification or warn
    -- or here not consider kinetic damage a major effect if item is periodic.
    -- So we opt for KISS and identify effect-less weapons at pick-up,
    -- not at first hit.
    onlyMinorEffects :: AspectRecord -> IK.ItemKind -> Bool
    onlyMinorEffects :: AspectRecord -> ItemKind -> Bool
    onlyMinorEffects AspectRecord
    ar ItemKind
    kind =
      Flag -> AspectRecord -> Bool
    checkFlag Flag
    Ability.MinorEffects AspectRecord
    ar  -- override
      Bool -> Bool -> Bool
    || (Effect -> Bool) -> [Effect] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Effect -> Bool
    IK.alwaysDudEffect (ItemKind -> [Effect]
    IK.ieffects ItemKind
    kind)
           -- exhibits no major effects

    itemTrajectory :: AspectRecord -> IK.ItemKind -> [Point]
                   -> ([Vector], (Speed, Int))
    itemTrajectory :: AspectRecord -> ItemKind -> [Point] -> ([Vector], (Speed, Int))
    itemTrajectory AspectRecord
    ar ItemKind
    itemKind [Point]
    path =
      let IK.ThrowMod{Int
    throwVelocity :: Int
    throwLinger :: Int
    throwHP :: Int
    throwHP :: ThrowMod -> Int
    throwLinger :: ThrowMod -> Int
    throwVelocity :: ThrowMod -> Int
    ..} = AspectRecord -> ThrowMod
    aToThrow AspectRecord
    ar
      in Int -> Int -> Int -> [Point] -> ([Vector], (Speed, Int))
    computeTrajectory (ItemKind -> Int
    IK.iweight ItemKind
    itemKind) Int
    throwVelocity Int
    throwLinger [Point]
    path

    totalRange :: AspectRecord -> IK.ItemKind -> Int
    totalRange :: AspectRecord -> ItemKind -> Int
    totalRange AspectRecord
    ar ItemKind
    itemKind = (Speed, Int) -> Int
    forall a b. (a, b) -> b
    snd ((Speed, Int) -> Int) -> (Speed, Int) -> Int
    forall a b. (a -> b) -> a -> b
    $ ([Vector], (Speed, Int)) -> (Speed, Int)
    forall a b. (a, b) -> b
    snd (([Vector], (Speed, Int)) -> (Speed, Int))
    -> ([Vector], (Speed, Int)) -> (Speed, Int)
    forall a b. (a -> b) -> a -> b
    $ AspectRecord -> ItemKind -> [Point] -> ([Vector], (Speed, Int))
    itemTrajectory AspectRecord
    ar ItemKind
    itemKind []

    isHumanTrinket :: IK.ItemKind -> Bool
    isHumanTrinket :: ItemKind -> Bool
    isHumanTrinket ItemKind
    itemKind =
      Bool -> (Int -> Bool) -> Maybe Int -> Bool
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Bool
    False (Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0) (Maybe Int -> Bool) -> Maybe Int -> Bool
    forall a b. (a -> b) -> a -> b
    $ GroupName ItemKind -> [(GroupName ItemKind, Int)] -> Maybe Int
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup GroupName ItemKind
    IK.VALUABLE ([(GroupName ItemKind, Int)] -> Maybe Int)
    -> [(GroupName ItemKind, Int)] -> Maybe Int
    forall a b. (a -> b) -> a -> b
    $ ItemKind -> [(GroupName ItemKind, Int)]
    IK.ifreq ItemKind
    itemKind
        -- risk from treasure hunters

    goesIntoEqp :: AspectRecord -> Bool
    goesIntoEqp :: AspectRecord -> Bool
    goesIntoEqp AspectRecord
    ar = Flag -> AspectRecord -> Bool
    checkFlag Flag
    Ability.Equipable AspectRecord
    ar
                     Bool -> Bool -> Bool
    || Flag -> AspectRecord -> Bool
    checkFlag Flag
    Ability.Meleeable AspectRecord
    ar

    loreFromContainer :: AspectRecord -> Container -> SLore
    loreFromContainer :: AspectRecord -> Container -> SLore
    loreFromContainer AspectRecord
    arItem Container
    c = case Container
    c of
      CFloor{} -> SLore
    SItem
      CEmbed{} -> SLore
    SEmbed
      CActor ActorId
    _ CStore
    store -> if | Flag -> AspectRecord -> Bool
    checkFlag Flag
    Ability.Blast AspectRecord
    arItem -> SLore
    SBlast
                           | Flag -> AspectRecord -> Bool
    checkFlag Flag
    Ability.Condition AspectRecord
    arItem -> SLore
    SCondition
                           | Bool
    otherwise -> ItemDialogMode -> SLore
    loreFromMode (ItemDialogMode -> SLore) -> ItemDialogMode -> SLore
    forall a b. (a -> b) -> a -> b
    $ CStore -> ItemDialogMode
    MStore CStore
    store
      CTrunk{} -> if Flag -> AspectRecord -> Bool
    checkFlag Flag
    Ability.Blast AspectRecord
    arItem then SLore
    SBlast else SLore
    STrunk