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 150 $ 10 * Dice.meanDice d)
IK.Burn d -> (min 200 $ 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 activeItems fact
in total `divUp` count
IK.CreateItem{} -> 30
IK.DropItem COrgan grp True ->
let (total, _) = organBenefit grp cops b activeItems fact
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 _ -> 0
IK.Recharging e ->
effectToBenefit cops b activeItems fact e
IK.Temporary _ -> 0
organBenefit :: GroupName ItemKind -> Kind.COps
-> Actor -> [ItemFull] -> Faction
-> (Int, Int)
organBenefit t cops@Kind.COps{coitem=Kind.Ops{ofoldrGroup}} b activeItems fact =
let f p _ kind (sacc, pacc) =
let paspect asp = p * aspectToBenefit cops b (Dice.meanDice <$> asp)
peffect eff = p * effectToBenefit cops b activeItems fact eff
in ( sacc + sum (map paspect $ IK.iaspects kind)
+ sum (map peffect $ IK.ieffects 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 < 0 -> 0
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
| not $ goesIntoEqp 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