module Game.LambdaHack.Client.AI.Preferences
( totalUsefulness, effectToBenefit
) where
import Control.Applicative
import qualified Data.EnumMap.Strict as EM
import Game.LambdaHack.Common.Actor
import Game.LambdaHack.Common.ActorState
import qualified Game.LambdaHack.Common.Dice as Dice
import Game.LambdaHack.Common.Faction
import Game.LambdaHack.Common.Item
import Game.LambdaHack.Common.ItemStrongest
import qualified Game.LambdaHack.Common.Kind as Kind
import Game.LambdaHack.Common.Misc
import Game.LambdaHack.Content.ItemKind (ItemKind)
import qualified Game.LambdaHack.Content.ItemKind as IK
import Game.LambdaHack.Content.ModeKind
effectToBenefit :: Kind.COps -> Actor -> [ItemFull] -> Faction
-> IK.Effect -> Int
effectToBenefit cops b activeItems fact eff =
let dungeonDweller = not $ fcanEscape $ gplayer fact
in case eff of
IK.NoEffect _ -> 0
IK.Hurt d -> (min 100 $ 10 * Dice.meanDice d)
IK.Burn d -> (min 150 $ 15 * Dice.meanDice d)
IK.Explode _ -> 0
IK.RefillHP p ->
let hpMax = sumSlotNoFilter IK.EqpSlotAddMaxHP activeItems
in if p > 0
then 10 * min p (max 0 $ fromIntegral
$ (xM hpMax bhp b) `divUp` oneM)
else max (99) (11 * p)
IK.OverfillHP p ->
let hpMax = sumSlotNoFilter IK.EqpSlotAddMaxHP activeItems
in if p > 0
then 11 * min p (max 1 $ fromIntegral
$ (xM hpMax bhp b) `divUp` oneM)
else max (99) (11 * p)
IK.RefillCalm p ->
let calmMax = sumSlotNoFilter IK.EqpSlotAddMaxCalm activeItems
in if p > 0
then min p (max 0 $ fromIntegral
$ (xM calmMax bcalm b) `divUp` oneM)
else max (20) p
IK.OverfillCalm p ->
let calmMax = sumSlotNoFilter IK.EqpSlotAddMaxCalm activeItems
in if p > 0
then min p (max 1 $ fromIntegral
$ (xM calmMax bcalm b) `divUp` oneM)
else max (20) p
IK.Dominate -> 200
IK.Impress -> 10
IK.CallFriend d -> 100 * Dice.meanDice d
IK.Summon _ d | dungeonDweller ->
50 * Dice.meanDice d
IK.Summon{} -> 0
IK.Ascend{} -> 1
IK.Escape{} -> 10000
IK.Paralyze d -> 20 * Dice.meanDice d
IK.InsertMove d -> 50 * Dice.meanDice d
IK.Teleport d ->
let p = Dice.meanDice d
in if p <= 8
&& dungeonDweller
then 1
else p
IK.CreateItem COrgan grp _ ->
let (total, count) = organBenefit grp cops b
in total `divUp` count
IK.CreateItem{} -> 30
IK.DropItem COrgan grp True ->
let (total, _) = organBenefit grp cops b
in total
IK.DropItem _ _ False -> 15
IK.DropItem _ _ True -> 30
IK.PolyItem -> 0
IK.Identify -> 0
IK.SendFlying _ -> 10
IK.PushActor _ -> 10
IK.PullActor _ -> 10
IK.DropBestWeapon -> 50
IK.ActivateInv ' ' -> 100
IK.ActivateInv _ -> 50
IK.ApplyPerfume -> 0
IK.OneOf _ -> 1
IK.OnSmash _ -> 10
IK.Recharging e ->
effectToBenefit cops b activeItems fact e
IK.Temporary _ -> 0
organBenefit :: GroupName ItemKind -> Kind.COps -> Actor -> (Int, Int)
organBenefit t cops@Kind.COps{coitem=Kind.Ops{ofoldrGroup}} b =
let f p _ kind (sacc, pacc) =
let paspect asp = p * aspectToBenefit cops b (Dice.meanDice <$> asp)
in ( sacc + sum (map paspect $ IK.iaspects kind)
, pacc + p )
in ofoldrGroup t f (0, 0)
aspectToBenefit :: Kind.COps -> Actor -> IK.Aspect Int -> Int
aspectToBenefit _cops _b asp =
case asp of
IK.Unique{} -> 0
IK.Periodic{} -> 0
IK.Timeout{} -> 0
IK.AddHurtMelee p -> p
IK.AddHurtRanged p -> p `divUp` 5
IK.AddArmorMelee p -> p `divUp` 5
IK.AddArmorRanged p -> p `divUp` 10
IK.AddMaxHP p -> p
IK.AddMaxCalm p -> p `div` 5
IK.AddSpeed p -> p * 10000
IK.AddSkills m -> 5 * sum (EM.elems m)
IK.AddSight p -> p * 10
IK.AddSmell p -> p * 10
IK.AddLight p -> p * 10
totalUsefulness :: Kind.COps -> Actor -> [ItemFull] -> Faction -> ItemFull
-> Maybe (Int, Int)
totalUsefulness cops b activeItems fact itemFull =
let ben effects aspects =
let effBens = map (effectToBenefit cops b activeItems fact) effects
aspBens = map (aspectToBenefit cops b) aspects
periodicEffBens = map (effectToBenefit cops b activeItems fact)
(allRecharging effects)
periodicBens =
case strengthFromEqpSlot IK.EqpSlotPeriodic itemFull of
Nothing -> []
Just timeout ->
map (\eff -> eff * 10 `divUp` timeout) periodicEffBens
selfBens = aspBens ++ periodicBens
selfSum = sum selfBens
mixedBlessing =
not (null selfBens)
&& (selfSum > 0 && minimum selfBens < 10
|| selfSum < 0 && maximum selfBens > 10)
effSum = sum effBens
isWeapon = isMeleeEqp itemFull
totalSum
| isWeapon && effSum < 0 = effSum + selfSum
| goesIntoInv itemFull = effSum
| mixedBlessing =
0
| otherwise = selfSum
in (totalSum, effSum)
in case itemDisco itemFull of
Just ItemDisco{itemAE=Just ItemAspectEffect{jaspects, jeffects}} ->
Just $ ben jeffects jaspects
Just ItemDisco{itemKind=IK.ItemKind{iaspects, ieffects}} ->
let jaspects = map (fmap Dice.meanDice) iaspects
in Just $ ben ieffects jaspects
_ -> Nothing