-- | Descripitons of items. module Game.LambdaHack.Common.ItemDescription ( partItemN, partItem, partItemWs, partItemAW, partItemWownW , itemDesc, textAllAE, viewItem ) where import Data.List import Data.Maybe import Data.Text (Text) import qualified Data.Text as T import qualified NLP.Miniutter.English as MU import Game.LambdaHack.Common.ActorState import qualified Game.LambdaHack.Common.Color as Color import qualified Game.LambdaHack.Common.Dice as Dice import Game.LambdaHack.Common.EffectDescription import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Item import Game.LambdaHack.Common.ItemStrongest import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Common.Time import qualified Game.LambdaHack.Content.ItemKind as IK -- TODO: remove _lid if still unused after some time -- | The part of speech describing the item parameterized by the number -- of effects/aspects to show.. partItemN :: Bool -> Int -> Container -> LevelId -> Time -> ItemFull -> (MU.Part, MU.Part) partItemN fullInfo n c _lid localTime itemFull = let genericName = jname $ itemBase itemFull in case itemDisco itemFull of Nothing -> let flav = flavourToName $ jflavour $ itemBase itemFull in (MU.Text $ flav <+> genericName, "") Just _ -> let effTs = filter (not . T.null) $ textAllAE fullInfo c itemFull it1 = case strengthFromEqpSlot IK.EqpSlotTimeout itemFull of Nothing -> [] Just timeout -> let timeoutTurns = timeDeltaScale (Delta timeTurn) timeout f startT = timeShift startT timeoutTurns > localTime in filter f (itemTimer itemFull) len = length it1 timer = if len == 0 then "" else if itemK itemFull == 1 && len == 1 then "(charging)" else "(" <> tshow len <+> "charging" <> ")" ts = take n effTs ++ (if length effTs > n then ["(...)"] else []) ++ [timer] in (MU.Text genericName, MU.Phrase $ map MU.Text ts) -- | The part of speech describing the item. partItem :: Container -> LevelId -> Time -> ItemFull -> (MU.Part, MU.Part) partItem = partItemN False 4 textAllAE :: Bool -> Container -> ItemFull -> [Text] textAllAE fullInfo c ItemFull{itemBase, itemDisco} = let features | fullInfo = map featureToSuff $ sort $ jfeature itemBase | otherwise = [] in case itemDisco of Nothing -> features Just ItemDisco{itemKind, itemAE} -> let periodicAspect :: IK.Aspect a -> Bool periodicAspect IK.Periodic = True periodicAspect _ = False timeoutAspect :: IK.Aspect a -> Bool timeoutAspect IK.Timeout{} = True timeoutAspect _ = False hurtEffect :: IK.Effect -> Bool hurtEffect (IK.Hurt _) = True hurtEffect _ = False notDetail :: IK.Effect -> Bool notDetail IK.Explode{} = fullInfo notDetail _ = True cstore = storeFromC c active = cstore `elem` [CEqp, COrgan] || cstore == CGround && isJust (strengthEqpSlot itemBase) splitAE :: (Num a, Show a, Ord a) => (a -> Text) -> [IK.Aspect a] -> (IK.Aspect a -> Text) -> [IK.Effect] -> (IK.Effect -> Text) -> [Text] splitAE reduce_a aspects ppA effects ppE = let mperiodic = find periodicAspect aspects mtimeout = find timeoutAspect aspects restAs = sort aspects (hurtEs, restEs) = partition hurtEffect $ sort $ filter notDetail effects aes = map ppE hurtEs ++ if active then map ppA restAs ++ map ppE restEs else map ppE restEs ++ map ppA restAs rechargingTs = T.intercalate (T.singleton ' ') $ filter (not . T.null) $ map ppE $ stripRecharging restEs onSmashTs = T.intercalate (T.singleton ' ') $ filter (not . T.null) $ map ppE $ stripOnSmash restEs durable = IK.Durable `elem` jfeature itemBase periodicOrTimeout = case mperiodic of _ | T.null rechargingTs -> "" Just IK.Periodic -> case mtimeout of Just (IK.Timeout 0) | not durable -> "(each turn until gone:" <+> rechargingTs <> ")" Just (IK.Timeout t) -> "(every" <+> reduce_a t <> ":" <+> rechargingTs <> ")" _ -> "" _ -> case mtimeout of Just (IK.Timeout t) -> "(timeout" <+> reduce_a t <> ":" <+> rechargingTs <> ")" _ -> "" onSmash = if T.null onSmashTs then "" else "(on smash:" <+> onSmashTs <> ")" in [periodicOrTimeout] ++ aes ++ [onSmash | fullInfo] aets = case itemAE of Just ItemAspectEffect{jaspects, jeffects} -> splitAE tshow jaspects aspectToSuffix jeffects effectToSuffix Nothing -> splitAE (\d -> maybe "?" tshow $ Dice.reduceDice d) (IK.iaspects itemKind) kindAspectToSuffix (IK.ieffects itemKind) kindEffectToSuffix in aets ++ features -- TODO: use kit partItemWs :: Int -> Container -> LevelId -> Time -> ItemFull -> MU.Part partItemWs count c lid localTime itemFull = let (name, stats) = partItem c lid localTime itemFull in MU.Phrase [MU.CarWs count name, stats] partItemAW :: Container -> LevelId -> Time -> ItemFull -> MU.Part partItemAW c lid localTime itemFull = let (name, stats) = partItem c lid localTime itemFull in MU.AW $ MU.Phrase [name, stats] partItemWownW :: MU.Part -> Container -> LevelId -> Time -> ItemFull -> MU.Part partItemWownW partA c lid localTime itemFull = let (name, stats) = partItem c lid localTime itemFull in MU.WownW partA $ MU.Phrase [name, stats] itemDesc :: Container -> LevelId -> Time -> ItemFull -> Overlay itemDesc c lid localTime itemFull = let (name, stats) = partItemN True 99 c lid localTime itemFull nstats = makePhrase [name, stats] desc = case itemDisco itemFull of Nothing -> "This item is as unremarkable as can be." Just ItemDisco{itemKind} -> IK.idesc itemKind weight = jweight (itemBase itemFull) (scaledWeight, unitWeight) = if weight > 1000 then (tshow $ fromIntegral weight / (1000 :: Double), "kg") else (tshow weight, "g") ln = abs $ fromEnum $ jlid (itemBase itemFull) colorSymbol = uncurry (flip Color.AttrChar) (viewItem $ itemBase itemFull) f color = Color.AttrChar Color.defAttr color lxsize = fst normalLevelBound + 1 -- TODO blurb = "D" -- dummy <+> nstats <> ":" <+> desc <+> makeSentence ["Weighs", MU.Text scaledWeight <> unitWeight] <+> makeSentence ["First found on level", MU.Text $ tshow ln] splitBlurb = splitText lxsize blurb attrBlurb = map (map f . T.unpack) splitBlurb in encodeOverlay $ (colorSymbol : tail (head attrBlurb)) : tail attrBlurb viewItem :: Item -> (Char, Color.Attr) viewItem item = ( jsymbol item , Color.defAttr {Color.fg = flavourToColor $ jflavour item} )