module Game.LambdaHack.Client.CommonM
( getPerFid, aidTgtToPos, makeLine
, currentSkillsClient, pickWeaponClient
, updateSalter, createSalter
) where
import Prelude ()
import Game.LambdaHack.Core.Prelude
import qualified Data.EnumMap.Strict as EM
import Game.LambdaHack.Client.MonadClient
import Game.LambdaHack.Client.Request
import Game.LambdaHack.Client.State
import qualified Game.LambdaHack.Definition.Ability as Ability
import Game.LambdaHack.Common.Actor
import Game.LambdaHack.Common.ActorState
import Game.LambdaHack.Definition.Defs
import Game.LambdaHack.Common.Faction
import Game.LambdaHack.Common.Item
import qualified Game.LambdaHack.Common.ItemAspect as IA
import Game.LambdaHack.Common.Kind
import Game.LambdaHack.Common.Level
import Game.LambdaHack.Common.MonadStateRead
import Game.LambdaHack.Common.Perception
import Game.LambdaHack.Common.Point
import qualified Game.LambdaHack.Common.PointArray as PointArray
import Game.LambdaHack.Core.Random
import Game.LambdaHack.Common.State
import qualified Game.LambdaHack.Common.Tile as Tile
import Game.LambdaHack.Common.Types
import Game.LambdaHack.Common.Vector
import Game.LambdaHack.Content.RuleKind
import Game.LambdaHack.Content.TileKind (TileKind, isUknownSpace)
getPerFid :: MonadClientRead m => LevelId -> m Perception
getPerFid lid = do
fper <- getsClient sfper
let assFail = error $ "no perception at given level"
`showFailure` (lid, fper)
return $! EM.findWithDefault assFail lid fper
aidTgtToPos :: ActorId -> LevelId -> Maybe Target -> State -> Maybe Point
aidTgtToPos _ _ Nothing _ = Nothing
aidTgtToPos aid lidV (Just tgt) s = case tgt of
TEnemy a ->
let body = getActorBody a s
in if blid body == lidV then Just (bpos body) else Nothing
TNonEnemy a ->
let body = getActorBody a s
in if blid body == lidV then Just (bpos body) else Nothing
TPoint _ lid p ->
if lid == lidV then Just p else Nothing
TVector v ->
let COps{corule=RuleContent{rXmax, rYmax}} = scops s
b = getActorBody aid s
shifted = shiftBounded rXmax rYmax (bpos b) v
in if shifted == bpos b && v /= Vector 0 0 then Nothing else Just shifted
makeLine :: MonadStateRead m => Bool -> Actor -> Point -> Int -> m (Maybe Int)
makeLine onlyFirst body fpos epsOld = do
COps{corule=RuleContent{rXmax, rYmax}, coTileSpeedup} <- getsState scops
lvl <- getLevel (blid body)
let dist = chessDist (bpos body) fpos
calcScore eps = case bla rXmax rYmax eps (bpos body) fpos of
Just bl ->
let blDist = take (dist - 1) bl
noActor p = p == fpos || not (occupiedBigLvl p lvl)
accessibleUnknown tpos =
let tt = lvl `at` tpos
in Tile.isWalkable coTileSpeedup tt || isUknownSpace tt
accessU = all noActor blDist
&& all accessibleUnknown blDist
accessFirst | not onlyFirst = False
| otherwise =
all noActor (take 1 blDist)
&& all accessibleUnknown (take 1 blDist)
nUnknown = length $ filter (isUknownSpace . (lvl `at`)) blDist
in if | accessU -> - nUnknown
| accessFirst -> -10000
| otherwise -> minBound
Nothing -> error $ "" `showFailure` (body, fpos, epsOld)
tryLines curEps (acc, _) | curEps == epsOld + dist = acc
tryLines curEps (acc, bestScore) =
let curScore = calcScore curEps
newAcc = if curScore > bestScore
then (Just curEps, curScore)
else (acc, bestScore)
in tryLines (curEps + 1) newAcc
return $! if | dist <= 0 -> Nothing
| calcScore epsOld > minBound -> Just epsOld
| otherwise ->
tryLines (epsOld + 1) (Nothing, minBound)
currentSkillsClient :: MonadClientRead m => ActorId -> m Ability.Skills
currentSkillsClient aid = do
body <- getsState $ getActorBody aid
side <- getsClient sside
mleader <- if bfid body == side
then getsClient sleader
else do
fact <- getsState $ (EM.! bfid body) . sfactionD
return $! gleader fact
getsState $ actorCurrentSkills mleader aid
pickWeaponClient :: MonadClient m
=> ActorId -> ActorId
-> m (Maybe RequestTimed)
pickWeaponClient source target = do
eqpAssocs <- getsState $ kitAssocs source [CEqp]
bodyAssocs <- getsState $ kitAssocs source [COrgan]
actorSk <- currentSkillsClient source
let kitAssRaw = eqpAssocs ++ bodyAssocs
kitAss = filter (IA.checkFlag Ability.Meleeable
. aspectRecordFull . fst . snd) kitAssRaw
discoBenefit <- getsClient sdiscoBenefit
strongest <- pickWeaponM False (Just discoBenefit) kitAss actorSk source
case strongest of
[] -> return Nothing
iis@((maxS, _) : _) -> do
let maxIis = map snd $ takeWhile ((== maxS) . fst) iis
(_, (iid, _)) <- rndToAction $ oneOf maxIis
let cstore = if isJust (lookup iid bodyAssocs) then COrgan else CEqp
return $ Just $ ReqMelee target iid cstore
updateSalter :: MonadClient m
=> LevelId -> [(Point, ContentId TileKind)] -> m ()
updateSalter lid pts = do
COps{coTileSpeedup} <- getsState scops
let pas = map (second $ toEnum . Tile.alterMinWalk coTileSpeedup) pts
f = (PointArray.// pas)
modifyClient $ \cli -> cli {salter = EM.adjust f lid $ salter cli}
createSalter :: State -> AlterLid
createSalter s =
let COps{coTileSpeedup} = scops s
f Level{ltile} =
PointArray.mapA (toEnum . Tile.alterMinWalk coTileSpeedup) ltile
in EM.map f $ sdungeon s