{-# 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
showList :: [AspectRecord] -> ShowS
$cshowList :: [AspectRecord] -> ShowS
show :: AspectRecord -> String
$cshow :: AspectRecord -> String
showsPrec :: Int -> AspectRecord -> ShowS
$cshowsPrec :: Int -> AspectRecord -> ShowS
Show, AspectRecord -> AspectRecord -> Bool
(AspectRecord -> AspectRecord -> Bool)
-> (AspectRecord -> AspectRecord -> Bool) -> Eq AspectRecord
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AspectRecord -> AspectRecord -> Bool
$c/= :: AspectRecord -> AspectRecord -> Bool
== :: AspectRecord -> AspectRecord -> Bool
$c== :: 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
min :: AspectRecord -> AspectRecord -> AspectRecord
$cmin :: AspectRecord -> AspectRecord -> AspectRecord
max :: AspectRecord -> AspectRecord -> AspectRecord
$cmax :: AspectRecord -> AspectRecord -> AspectRecord
>= :: AspectRecord -> AspectRecord -> Bool
$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
compare :: AspectRecord -> AspectRecord -> Ordering
$ccompare :: AspectRecord -> AspectRecord -> Ordering
$cp1Ord :: Eq 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
$cto :: forall x. Rep AspectRecord x -> AspectRecord
$cfrom :: forall x. AspectRecord -> Rep AspectRecord x
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
showList :: [KindMean] -> ShowS
$cshowList :: [KindMean] -> ShowS
show :: KindMean -> String
$cshow :: KindMean -> String
showsPrec :: Int -> KindMean -> ShowS
$cshowsPrec :: Int -> KindMean -> ShowS
Show, KindMean -> KindMean -> Bool
(KindMean -> KindMean -> Bool)
-> (KindMean -> KindMean -> Bool) -> Eq KindMean
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: KindMean -> KindMean -> Bool
$c/= :: KindMean -> KindMean -> Bool
== :: KindMean -> KindMean -> Bool
$c== :: 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
min :: KindMean -> KindMean -> KindMean
$cmin :: KindMean -> KindMean -> KindMean
max :: KindMean -> KindMean -> KindMean
$cmax :: KindMean -> KindMean -> KindMean
>= :: KindMean -> KindMean -> Bool
$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
compare :: KindMean -> KindMean -> Ordering
$ccompare :: KindMean -> KindMean -> Ordering
$cp1Ord :: Eq KindMean
Ord)

emptyAspectRecord :: AspectRecord
emptyAspectRecord :: AspectRecord
emptyAspectRecord = AspectRecord :: Int
-> Skills
-> Flags
-> Text
-> ThrowMod
-> Maybe (GroupName ItemKind)
-> Maybe EqpSlot
-> AspectRecord
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
      Int
n <- AbsDepth -> AbsDepth -> Dice -> Rnd Int
castDice AbsDepth
ldepth AbsDepth
totalDepth Dice
d
      AspectRecord -> Rnd AspectRecord
forall (m :: * -> *) a. Monad m => a -> m a
return (AspectRecord -> Rnd AspectRecord)
-> AspectRecord -> Rnd AspectRecord
forall a b. (a -> b) -> a -> b
$! 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 :: Int
aTimeout = Int
n}
    IK.AddSkill Skill
sk Dice
d -> do
      Int
n <- AbsDepth -> AbsDepth -> Dice -> Rnd Int
castDice AbsDepth
ldepth AbsDepth
totalDepth Dice
d
      AspectRecord -> Rnd AspectRecord
forall (m :: * -> *) a. Monad m => a -> m a
return (AspectRecord -> Rnd AspectRecord)
-> AspectRecord -> Rnd AspectRecord
forall a b. (a -> b) -> a -> b
$! if Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0
                then AspectRecord
ar {aSkills :: Skills
aSkills = Skill -> Int -> Skills -> Skills
Ability.addSk Skill
sk Int
n (AspectRecord -> Skills
aSkills AspectRecord
ar)}
                else AspectRecord
ar
    IK.SetFlag Flag
feat ->
      AspectRecord -> Rnd AspectRecord
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 :: Flags
aFlags = EnumSet Flag -> Flags
Ability.Flags
                             (EnumSet Flag -> Flags) -> EnumSet Flag -> Flags
forall a b. (a -> b) -> a -> b
$ Flag -> EnumSet Flag -> EnumSet Flag
forall k. Enum k => k -> EnumSet k -> EnumSet k
ES.insert Flag
feat (Flags -> EnumSet Flag
Ability.flags (Flags -> EnumSet Flag) -> Flags -> EnumSet Flag
forall a b. (a -> b) -> a -> b
$ AspectRecord -> Flags
aFlags AspectRecord
ar)}
    IK.ELabel Text
t -> AspectRecord -> Rnd AspectRecord
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 :: Text
aELabel = Text
t}
    IK.ToThrow ThrowMod
tt -> AspectRecord -> Rnd AspectRecord
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 :: ThrowMod
aToThrow = ThrowMod
tt}
    IK.PresentAs GroupName ItemKind
ha -> AspectRecord -> Rnd AspectRecord
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 :: Maybe (GroupName ItemKind)
aPresentAs = GroupName ItemKind -> Maybe (GroupName ItemKind)
forall a. a -> Maybe a
Just GroupName ItemKind
ha}
    IK.EqpSlot EqpSlot
slot -> AspectRecord -> Rnd AspectRecord
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 :: Maybe EqpSlot
aEqpSlot = EqpSlot -> Maybe EqpSlot
forall a. a -> Maybe a
Just EqpSlot
slot}
    IK.Odds Dice
d [Aspect]
aspects1 [Aspect]
aspects2 -> do
      Bool
pick1 <- AbsDepth -> AbsDepth -> Dice -> Rnd Bool
oddsDice AbsDepth
ldepth AbsDepth
totalDepth Dice
d
      (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
ar ([Aspect] -> Rnd AspectRecord) -> [Aspect] -> Rnd AspectRecord
forall a b. (a -> b) -> a -> b
$
        if Bool
pick1 then [Aspect]
aspects1 else [Aspect]
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 :: Int
aTimeout = Int
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 :: Skills
aSkills = Skill -> Int -> Skills -> Skills
Ability.addSk Skill
sk Int
n (AspectRecord -> Skills
aSkills AspectRecord
ar)}
         else AspectRecord
ar
    IK.SetFlag Flag
feat ->
      AspectRecord
ar {aFlags :: Flags
aFlags = EnumSet Flag -> Flags
Ability.Flags (EnumSet Flag -> Flags) -> EnumSet Flag -> Flags
forall a b. (a -> b) -> a -> b
$ Flag -> EnumSet Flag -> EnumSet Flag
forall k. Enum k => k -> EnumSet k -> EnumSet k
ES.insert Flag
feat (Flags -> EnumSet Flag
Ability.flags (Flags -> EnumSet Flag) -> Flags -> EnumSet Flag
forall a b. (a -> b) -> a -> b
$ AspectRecord -> Flags
aFlags AspectRecord
ar)}
    IK.ELabel Text
t -> AspectRecord
ar {aELabel :: Text
aELabel = Text
t}
    IK.ToThrow ThrowMod
tt -> AspectRecord
ar {aToThrow :: ThrowMod
aToThrow = ThrowMod
tt}
    IK.PresentAs GroupName ItemKind
ha -> AspectRecord
ar {aPresentAs :: Maybe (GroupName ItemKind)
aPresentAs = GroupName ItemKind -> Maybe (GroupName ItemKind)
forall a. a -> Maybe a
Just GroupName ItemKind
ha}
    IK.EqpSlot EqpSlot
slot -> AspectRecord
ar {aEqpSlot :: Maybe EqpSlot
aEqpSlot = EqpSlot -> Maybe EqpSlot
forall a. a -> Maybe a
Just EqpSlot
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 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
aEqpSlot :: Maybe EqpSlot
aPresentAs :: Maybe (GroupName ItemKind)
aToThrow :: ThrowMod
aELabel :: Text
aFlags :: Flags
aSkills :: Skills
aTimeout :: Int
aEqpSlot :: AspectRecord -> Maybe EqpSlot
aPresentAs :: AspectRecord -> Maybe (GroupName ItemKind)
aToThrow :: AspectRecord -> ThrowMod
aELabel :: AspectRecord -> Text
aFlags :: AspectRecord -> Flags
aSkills :: AspectRecord -> Skills
aTimeout :: AspectRecord -> Int
..} =
  [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 (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
throwHP :: ThrowMod -> Int
throwLinger :: ThrowMod -> Int
throwVelocity :: ThrowMod -> Int
throwHP :: Int
throwLinger :: Int
throwVelocity :: 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