module Game.LambdaHack.Common.ItemStrongest
(
strengthOnSmash, strengthToThrow, strengthEqpSlot, strengthFromEqpSlot
, strongestSlotNoFilter, strongestSlot, sumSlotNoFilter, sumSkills
, totalRange, computeTrajectory, itemTrajectory
, unknownPrecious, permittedRanged, unknownMelee
) where
import Control.Applicative
import Control.Exception.Assert.Sugar
import qualified Control.Monad.State as St
import qualified Data.EnumMap.Strict as EM
import Data.List
import Data.Maybe
import qualified Data.Ord as Ord
import Data.Text (Text)
import qualified Game.LambdaHack.Common.Ability as Ability
import qualified Game.LambdaHack.Common.Dice as Dice
import Game.LambdaHack.Common.Effect
import Game.LambdaHack.Common.Item
import Game.LambdaHack.Common.Point
import Game.LambdaHack.Common.Time
import Game.LambdaHack.Common.Vector
import Game.LambdaHack.Content.ItemKind
dice999 :: Dice.Dice -> Int
dice999 d = fromMaybe 999 $ Dice.reduceDice d
strengthAspect :: (Aspect Int -> [b]) -> ItemFull -> [b]
strengthAspect f itemFull =
case itemDisco itemFull of
Just ItemDisco{itemAE=Just ItemAspectEffect{jaspects}} ->
concatMap f jaspects
Just ItemDisco{itemKind=ItemKind{iaspects}} ->
let trav x = St.evalState (aspectTrav x (return . round . Dice.meanDice))
()
in concatMap f $ map trav iaspects
Nothing -> []
strengthAspectMaybe :: Show b => (Aspect Int -> [b]) -> ItemFull -> Maybe b
strengthAspectMaybe f itemFull =
case strengthAspect f itemFull of
[] -> Nothing
[x] -> Just x
xs -> assert `failure` (xs, itemFull)
strengthEffect999 :: (Effect Int -> [b]) -> ItemFull -> [b]
strengthEffect999 f itemFull =
case itemDisco itemFull of
Just ItemDisco{itemAE=Just ItemAspectEffect{jeffects}} ->
concatMap f jeffects
Just ItemDisco{itemKind=ItemKind{ieffects}} ->
let trav x = St.evalState (effectTrav x (return . dice999)) ()
in concatMap f $ map trav ieffects
Nothing -> []
strengthFeature :: (Feature -> [b]) -> Item -> [b]
strengthFeature f item = concatMap f (jfeature item)
strengthMelee :: ItemFull -> Maybe Int
strengthMelee itemFull =
let durable = Durable `elem` jfeature (itemBase itemFull)
p (Hurt d) = [floor (Dice.meanDice d)]
p (Burn k) = [k]
p _ = []
hasNoEffects = case itemDisco itemFull of
Just ItemDisco{itemAE=Just ItemAspectEffect{jeffects}} ->
null jeffects
Just ItemDisco{itemKind=ItemKind{ieffects}} ->
null ieffects
Nothing -> True
in if hasNoEffects
then Nothing
else Just $ sum (strengthEffect999 p itemFull)
+ if durable then 100 else 0
strengthOnSmash :: ItemFull -> [Effect Int]
strengthOnSmash =
let p (OnSmash eff) = [eff]
p _ = []
in strengthEffect999 p
strengthPeriodic :: ItemFull -> Maybe Int
strengthPeriodic =
let p (Periodic k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddMaxHP :: ItemFull -> Maybe Int
strengthAddMaxHP =
let p (AddMaxHP k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddMaxCalm :: ItemFull -> Maybe Int
strengthAddMaxCalm =
let p (AddMaxCalm k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddSpeed :: ItemFull -> Maybe Int
strengthAddSpeed =
let p (AddSpeed k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddSkills :: ItemFull -> Maybe Ability.Skills
strengthAddSkills =
let p (AddSkills a) = [a]
p _ = []
in strengthAspectMaybe p
strengthAddHurtMelee :: ItemFull -> Maybe Int
strengthAddHurtMelee =
let p (AddHurtMelee k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddHurtRanged :: ItemFull -> Maybe Int
strengthAddHurtRanged =
let p (AddHurtRanged k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddArmorMelee :: ItemFull -> Maybe Int
strengthAddArmorMelee =
let p (AddArmorMelee k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddArmorRanged :: ItemFull -> Maybe Int
strengthAddArmorRanged =
let p (AddArmorRanged k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddSight :: ItemFull -> Maybe Int
strengthAddSight =
let p (AddSight k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddSmell :: ItemFull -> Maybe Int
strengthAddSmell =
let p (AddSmell k) = [k]
p _ = []
in strengthAspectMaybe p
strengthAddLight :: ItemFull -> Maybe Int
strengthAddLight =
let p (AddLight k) = [k]
p _ = []
in strengthAspectMaybe p
strengthEqpSlot :: Item -> Maybe (EqpSlot, Text)
strengthEqpSlot item =
let p (EqpSlot eqpSlot t) = [(eqpSlot, t)]
p _ = []
in case strengthFeature p item of
[] -> Nothing
[x] -> Just x
xs -> assert `failure` (xs, item)
strengthToThrow :: Item -> ThrowMod
strengthToThrow item =
let p (ToThrow tmod) = [tmod]
p _ = []
in case strengthFeature p item of
[] -> ThrowMod 100 100
[x] -> x
xs -> assert `failure` (xs, item)
computeTrajectory :: Int -> Int -> Int -> [Point] -> ([Vector], (Speed, Int))
computeTrajectory weight throwVelocity throwLinger path =
let speed = speedFromWeight weight throwVelocity
trange = rangeFromSpeedAndLinger speed throwLinger
btrajectory = take trange $ pathToTrajectory path
in (btrajectory, (speed, trange))
itemTrajectory :: Item -> [Point] -> ([Vector], (Speed, Int))
itemTrajectory item path =
let ThrowMod{..} = strengthToThrow item
in computeTrajectory (jweight item) throwVelocity throwLinger path
totalRange :: Item -> Int
totalRange item = snd $ snd $ itemTrajectory item []
strengthFromEqpSlot :: EqpSlot -> ItemFull -> Maybe Int
strengthFromEqpSlot eqpSlot =
case eqpSlot of
EqpSlotPeriodic -> strengthPeriodic
EqpSlotAddMaxHP -> strengthAddMaxHP
EqpSlotAddMaxCalm -> strengthAddMaxCalm
EqpSlotAddSpeed -> strengthAddSpeed
EqpSlotAddSkills -> \itemFull -> sum . EM.elems <$> strengthAddSkills itemFull
EqpSlotAddHurtMelee -> strengthAddHurtMelee
EqpSlotAddHurtRanged -> strengthAddHurtRanged
EqpSlotAddArmorMelee -> strengthAddArmorMelee
EqpSlotAddArmorRanged -> strengthAddArmorRanged
EqpSlotAddSight -> strengthAddSight
EqpSlotAddSmell -> strengthAddSmell
EqpSlotAddLight -> strengthAddLight
EqpSlotWeapon -> strengthMelee
strongestSlotNoFilter :: EqpSlot -> [(ItemId, ItemFull)]
-> [(Int, (ItemId, ItemFull))]
strongestSlotNoFilter eqpSlot is =
let f = strengthFromEqpSlot eqpSlot
g (iid, itemFull) = (\v -> (v, (iid, itemFull))) <$> (f itemFull)
in sortBy (flip $ Ord.comparing fst) $ mapMaybe g is
strongestSlot :: EqpSlot -> [(ItemId, ItemFull)]
-> [(Int, (ItemId, ItemFull))]
strongestSlot eqpSlot is =
let f (_, itemFull) = case strengthEqpSlot $ itemBase itemFull of
Just (eqpSlot2, _) | eqpSlot2 == eqpSlot -> True
_ -> False
slotIs = filter f is
in strongestSlotNoFilter eqpSlot slotIs
sumSlotNoFilter :: EqpSlot -> [ItemFull] -> Int
sumSlotNoFilter eqpSlot is = assert (eqpSlot /= EqpSlotWeapon) $
let f = strengthFromEqpSlot eqpSlot
g itemFull = (* itemK itemFull) <$> f itemFull
in sum $ mapMaybe g is
sumSkills :: [ItemFull] -> Ability.Skills
sumSkills is =
let g itemFull = (Ability.scaleSkills (itemK itemFull))
<$> strengthAddSkills itemFull
in foldr Ability.addSkills Ability.zeroSkills $ mapMaybe g is
unknownPrecious :: ItemFull -> Bool
unknownPrecious itemFull =
Durable `notElem` jfeature (itemBase itemFull)
&& case itemDisco itemFull of
Just ItemDisco{itemAE=Just _} -> False
_ -> Precious `elem` jfeature (itemBase itemFull)
permittedRanged :: ItemFull -> Maybe Int -> Bool
permittedRanged itemFull _ =
let hasEffects = case itemDisco itemFull of
Just ItemDisco{itemAE=Just ItemAspectEffect{jeffects=[]}} -> False
Just ItemDisco{itemAE=Nothing, itemKind=ItemKind{ieffects=[]}} -> False
_ -> True
in hasEffects
&& not (unknownPrecious itemFull)
&& case strengthEqpSlot (itemBase itemFull) of
Just (EqpSlotAddLight, _) -> True
Just _ -> False
Nothing -> True
unknownAspect :: (Aspect Dice.Dice -> [Dice.Dice]) -> ItemFull -> Bool
unknownAspect f itemFull =
case itemDisco itemFull of
Just ItemDisco{itemAE=Nothing, itemKind=ItemKind{iaspects}} ->
let unknown x = Dice.minDice x /= Dice.maxDice x
in or $ concatMap (map unknown . f) iaspects
_ -> False
unknownMelee :: [ItemFull] -> Bool
unknownMelee =
let p (AddHurtMelee k) = [k]
p _ = []
f itemFull b = b || unknownAspect p itemFull
in foldr f False