    -- | Common client monad operations.
    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           Game.LambdaHack.Common.Actor
    import           Game.LambdaHack.Common.ActorState
    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.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)
    import           Game.LambdaHack.Core.Random
    import qualified Game.LambdaHack.Definition.Ability as Ability
    import           Game.LambdaHack.Definition.Defs

    -- | Get the current perception of a client.
    getPerFid :: MonadClientRead m => LevelId -> m Perception
    getPerFid :: forall (m :: * -> *). MonadClientRead m => LevelId -> m Perception
    getPerFid LevelId
    lid = do
      fper <- (StateClient -> PerLid) -> m PerLid
    forall a. (StateClient -> a) -> m a
    forall (m :: * -> *) a.
    MonadClientRead m =>
    (StateClient -> a) -> m a
    getsClient StateClient -> PerLid
    sfper
      let assFail = [Char] -> Perception
    forall a. HasCallStack => [Char] -> a
    error ([Char] -> Perception) -> [Char] -> Perception
    forall a b. (a -> b) -> a -> b
    $ [Char]
    "no perception at given level"
                            [Char] -> (LevelId, PerLid) -> [Char]
    forall v. Show v => [Char] -> v -> [Char]
    `showFailure` (LevelId
    lid, PerLid
    fper)
      return $! EM.findWithDefault assFail lid fper

    -- | Calculate the position of an actor's target.
    -- This matches @pathGoal@, but sometimes path is not defined.
    aidTgtToPos :: Maybe ActorId -> LevelId -> Maybe Target -> State -> Maybe Point
    aidTgtToPos :: Maybe ActorId -> LevelId -> Maybe Target -> State -> Maybe Point
    aidTgtToPos Maybe ActorId
    _ LevelId
    _ Maybe Target
    Nothing State
    _ = Maybe Point
    forall a. Maybe a
    Nothing
    aidTgtToPos Maybe ActorId
    maid LevelId
    lidV (Just Target
    tgt) State
    s = case Target
    tgt of
      TEnemy ActorId
    a ->
        let body :: Actor
    body = ActorId -> State -> Actor
    getActorBody ActorId
    a State
    s
        in if Actor -> LevelId
    blid Actor
    body LevelId -> LevelId -> Bool
    forall a. Eq a => a -> a -> Bool
    == LevelId
    lidV then Point -> Maybe Point
    forall a. a -> Maybe a
    Just (Actor -> Point
    bpos Actor
    body) else Maybe Point
    forall a. Maybe a
    Nothing
      TNonEnemy ActorId
    a ->
        let body :: Actor
    body = ActorId -> State -> Actor
    getActorBody ActorId
    a State
    s
        in if Actor -> LevelId
    blid Actor
    body LevelId -> LevelId -> Bool
    forall a. Eq a => a -> a -> Bool
    == LevelId
    lidV then Point -> Maybe Point
    forall a. a -> Maybe a
    Just (Actor -> Point
    bpos Actor
    body) else Maybe Point
    forall a. Maybe a
    Nothing
      TPoint TGoal
    _ LevelId
    lid Point
    p ->
        if LevelId
    lid LevelId -> LevelId -> Bool
    forall a. Eq a => a -> a -> Bool
    == LevelId
    lidV then Point -> Maybe Point
    forall a. a -> Maybe a
    Just Point
    p else Maybe Point
    forall a. Maybe a
    Nothing
      TVector Vector
    v -> case Maybe ActorId
    maid of
        Maybe ActorId
    Nothing -> Maybe Point
    forall a. Maybe a
    Nothing
        Just ActorId
    aid ->
          let COps{corule :: COps -> RuleContent
    corule=RuleContent{Int
    rWidthMax :: Int
    rWidthMax :: RuleContent -> Int
    rWidthMax, Int
    rHeightMax :: Int
    rHeightMax :: RuleContent -> Int
    rHeightMax}} = State -> COps
    scops State
    s
              b :: Actor
    b = ActorId -> State -> Actor
    getActorBody ActorId
    aid State
    s
              shifted :: Point
    shifted = Int -> Int -> Point -> Vector -> Point
    shiftBounded Int
    rWidthMax Int
    rHeightMax (Actor -> Point
    bpos Actor
    b) Vector
    v
          in if Point
    shifted Point -> Point -> Bool
    forall a. Eq a => a -> a -> Bool
    == Actor -> Point
    bpos Actor
    b Bool -> Bool -> Bool
    && Vector
    v Vector -> Vector -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int -> Int -> Vector
    Vector Int
    0 Int
    0 then Maybe Point
    forall a. Maybe a
    Nothing else Point -> Maybe Point
    forall a. a -> Maybe a
    Just Point
    shifted

    -- | Counts the number of steps until the projectile would hit a non-projectile
    -- actor or obstacle. Starts searching with the given eps and returns
    -- the first found eps for which the number reaches the distance between
    -- actor and target position, or Nothing if none can be found.
    -- Treats unknown tiles as walkable, but prefers known.
    makeLine :: Bool -> Actor -> Point -> Int -> COps -> Level -> Maybe Int
    makeLine :: Bool -> Actor -> Point -> Int -> COps -> Level -> Maybe Int
    makeLine Bool
    onlyFirst Actor
    body Point
    fpos Int
    epsOld COps
    cops Level
    lvl =
      let COps{TileSpeedup
    coTileSpeedup :: TileSpeedup
    coTileSpeedup :: COps -> TileSpeedup
    coTileSpeedup} = COps
    cops
          dist :: Int
    dist = Point -> Point -> Int
    chessDist (Actor -> Point
    bpos Actor
    body) Point
    fpos
          calcScore :: Int -> Int
          calcScore :: Int -> Int
    calcScore Int
    eps = case Int -> Point -> Point -> Maybe [Point]
    bresenhamsLineAlgorithm Int
    eps (Actor -> Point
    bpos Actor
    body) Point
    fpos of
            Just [Point]
    bl ->
              let blDist :: [Point]
    blDist = Int -> [Point] -> [Point]
    forall a. Int -> [a] -> [a]
    take (Int
    dist Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) [Point]
    bl  -- goal not checked; actor well aware
                  noActor :: Point -> Bool
    noActor Point
    p = Point
    p Point -> Point -> Bool
    forall a. Eq a => a -> a -> Bool
    == Point
    fpos Bool -> Bool -> Bool
    || Bool -> Bool
    not (Point -> Level -> Bool
    occupiedBigLvl Point
    p Level
    lvl)
                  accessibleUnknown :: Point -> Bool
    accessibleUnknown Point
    tpos =
                    let tt :: ContentId TileKind
    tt = Level
    lvl Level -> Point -> ContentId TileKind
    `at` Point
    tpos
                    in TileSpeedup -> ContentId TileKind -> Bool
    Tile.isWalkable TileSpeedup
    coTileSpeedup ContentId TileKind
    tt Bool -> Bool -> Bool
    || ContentId TileKind -> Bool
    isUknownSpace ContentId TileKind
    tt
                  accessU :: Bool
    accessU = (Point -> Bool) -> [Point] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Point -> Bool
    noActor [Point]
    blDist
                            Bool -> Bool -> Bool
    && (Point -> Bool) -> [Point] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Point -> Bool
    accessibleUnknown [Point]
    blDist
                  accessFirst :: Bool
    accessFirst | Bool -> Bool
    not Bool
    onlyFirst = Bool
    False
                              | Bool
    otherwise =
                    (Point -> Bool) -> [Point] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Point -> Bool
    noActor (Int -> [Point] -> [Point]
    forall a. Int -> [a] -> [a]
    take Int
    1 [Point]
    blDist)
                    Bool -> Bool -> Bool
    && (Point -> Bool) -> [Point] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Point -> Bool
    accessibleUnknown (Int -> [Point] -> [Point]
    forall a. Int -> [a] -> [a]
    take Int
    1 [Point]
    blDist)
                  nUnknown :: Int
    nUnknown = [Point] -> Int
    forall a. [a] -> Int
    length ([Point] -> Int) -> [Point] -> Int
    forall a b. (a -> b) -> a -> b
    $ (Point -> Bool) -> [Point] -> [Point]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (ContentId TileKind -> Bool
    isUknownSpace (ContentId TileKind -> Bool)
    -> (Point -> ContentId TileKind) -> Point -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Level
    lvl Level -> Point -> ContentId TileKind
    `at`)) [Point]
    blDist
              in if | Bool
    accessU -> - Int
    nUnknown
                    | Bool
    accessFirst -> -Int
    10000
                    | Bool
    otherwise -> Int
    forall a. Bounded a => a
    minBound
            Maybe [Point]
    Nothing -> [Char] -> Int
    forall a. HasCallStack => [Char] -> a
    error ([Char] -> Int) -> [Char] -> Int
    forall a b. (a -> b) -> a -> b
    $ [Char]
    "" [Char] -> (Actor, Point, Int) -> [Char]
    forall v. Show v => [Char] -> v -> [Char]
    `showFailure` (Actor
    body, Point
    fpos, Int
    epsOld)
          tryLines :: Int -> (Maybe Int, Int) -> Maybe Int
          tryLines :: Int -> (Maybe Int, Int) -> Maybe Int
    tryLines Int
    curEps (Maybe Int
    acc, Int
    _) | Int
    curEps Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    epsOld Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    dist = Maybe Int
    acc
          tryLines Int
    curEps (Maybe Int
    acc, Int
    bestScore) =
            let curScore :: Int
    curScore = Int -> Int
    calcScore Int
    curEps
                newAcc :: (Maybe Int, Int)
    newAcc = if Int
    curScore Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    bestScore
                         then (Int -> Maybe Int
    forall a. a -> Maybe a
    Just Int
    curEps, Int
    curScore)
                         else (Maybe Int
    acc, Int
    bestScore)
            in Int -> (Maybe Int, Int) -> Maybe Int
    tryLines (Int
    curEps Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) (Maybe Int, Int)
    newAcc
      in if | Int
    dist Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    0 -> Maybe Int
    forall a. Maybe a
    Nothing  -- ProjectAimOnself
            | Int -> Int
    calcScore Int
    epsOld Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    forall a. Bounded a => a
    minBound -> Int -> Maybe Int
    forall a. a -> Maybe a
    Just Int
    epsOld  -- keep old
            | Bool
    otherwise -> Int -> (Maybe Int, Int) -> Maybe Int
    tryLines (Int
    epsOld Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) (Maybe Int
    forall a. Maybe a
    Nothing, Int
    forall a. Bounded a => a
    minBound)  -- find best

    -- @MonadStateRead@ would be enough, but the logic is sound only on client.
    currentSkillsClient :: MonadClientRead m => ActorId -> m Ability.Skills
    currentSkillsClient :: forall (m :: * -> *). MonadClientRead m => ActorId -> m Skills
    currentSkillsClient ActorId
    aid = do
      body <- (State -> Actor) -> m Actor
    forall a. (State -> a) -> m a
    forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
    getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
    forall a b. (a -> b) -> a -> b
    $ ActorId -> State -> Actor
    getActorBody ActorId
    aid
      side <- getsClient sside
      -- Newest Leader in sleader, not yet in sfactionD.
      mleader <- if bfid body == side
                 then getsClient sleader
                 else do
                   fact <- getsState $ (EM.! bfid body) . sfactionD
                   return $! gleader fact
      getsState $ actorCurrentSkills mleader aid  -- keep it lazy

    -- Client has to choose the weapon based on its partial knowledge,
    -- because if server chose it, it would leak item discovery information.
    --
    -- Note that currently the aspects of the target actor are not considered,
    -- because all weapons share the sum of all source actor aspects and only differ
    -- in damage (equally important for all targets) and effects (really hard
    -- to tell which is better for which target or even which is better
    -- for the same target, so it's random). If only individual weapon's +toHit
    -- was applied to the target, situation would be much more complex,
    -- which is precisely why we keep it as is and let the player make choices
    -- by equipping and unequipping weapons instead. Content should ensure
    -- that the rule of thumb (which AI uses) that more weapons is better
    -- should give good results almost always, at least at the start of the game,
    -- to limit micromanagement and to spare newbies.
    --
    -- Note that situation is completely different with choosing projectiles
    -- against a particular foe, even before (potential) splash damage
    -- that hits multiple tagets comes into the equation. AI has to be very
    -- primitive and random here as well.
    pickWeaponClient :: MonadClient m
                     => ActorId -> ActorId -> m (Maybe RequestTimed)
    pickWeaponClient :: forall (m :: * -> *).
    MonadClient m =>
    ActorId -> ActorId -> m (Maybe RequestTimed)
    pickWeaponClient ActorId
    source ActorId
    target = do
      eqpAssocs <- (State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)]
    forall a. (State -> a) -> m a
    forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
    getsState ((State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)])
    -> (State -> [(ItemId, ItemFullKit)]) -> m [(ItemId, ItemFullKit)]
    forall a b. (a -> b) -> a -> b
    $ ActorId -> [CStore] -> State -> [(ItemId, ItemFullKit)]
    kitAssocs ActorId
    source [CStore
    CEqp]
      bodyAssocs <- getsState $ kitAssocs source [COrgan]
      actorSk <- currentSkillsClient source
      tb <- getsState $ getActorBody target
      let kitAssRaw = [(ItemId, ItemFullKit)]
    eqpAssocs [(ItemId, ItemFullKit)]
    -> [(ItemId, ItemFullKit)] -> [(ItemId, ItemFullKit)]
    forall a. [a] -> [a] -> [a]
    ++ [(ItemId, ItemFullKit)]
    bodyAssocs
          kitAss = ((ItemId, ItemFullKit) -> Bool)
    -> [(ItemId, ItemFullKit)] -> [(ItemId, ItemFullKit)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Flag -> AspectRecord -> Bool
    IA.checkFlag Flag
    Ability.Meleeable
                           (AspectRecord -> Bool)
    -> ((ItemId, ItemFullKit) -> AspectRecord)
    -> (ItemId, ItemFullKit)
    -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ItemFull -> AspectRecord
    aspectRecordFull (ItemFull -> AspectRecord)
    -> ((ItemId, ItemFullKit) -> ItemFull)
    -> (ItemId, ItemFullKit)
    -> AspectRecord
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ItemFullKit -> ItemFull
    forall a b. (a, b) -> a
    fst (ItemFullKit -> ItemFull)
    -> ((ItemId, ItemFullKit) -> ItemFullKit)
    -> (ItemId, ItemFullKit)
    -> ItemFull
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ItemId, ItemFullKit) -> ItemFullKit
    forall a b. (a, b) -> b
    snd) [(ItemId, ItemFullKit)]
    kitAssRaw
          benign ItemFull
    itemFull = let arItem :: AspectRecord
    arItem = ItemFull -> AspectRecord
    aspectRecordFull ItemFull
    itemFull
                            in Flag -> AspectRecord -> Bool
    IA.checkFlag Flag
    Ability.Benign AspectRecord
    arItem
      discoBenefit <- getsClient sdiscoBenefit
      strongest <- pickWeaponM False (Just discoBenefit) kitAss actorSk source
      case strongest of
        [] -> Maybe RequestTimed -> m (Maybe RequestTimed)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe RequestTimed
    forall a. Maybe a
    Nothing
        (Double
    _, Bool
    _, Int
    _, Int
    _, ItemId
    _, (ItemFull
    itemFull, ItemQuant
    _)) : [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    _ | ItemFull -> Bool
    benign ItemFull
    itemFull Bool -> Bool -> Bool
    && Actor -> Bool
    bproj Actor
    tb ->
          Maybe RequestTimed -> m (Maybe RequestTimed)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe RequestTimed
    forall a. Maybe a
    Nothing  -- if strongest is benign, don't waste fun on a projectile
        iis :: [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    iis@(ii1 :: (Double, Bool, Int, Int, ItemId, ItemFullKit)
    ii1@(Double
    value1, Bool
    hasEffect1, Int
    timeout1, Int
    _, ItemId
    _, (ItemFull
    itemFull1, ItemQuant
    _)) : [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    _) -> do
          let minIis :: [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    minIis = ((Double, Bool, Int, Int, ItemId, ItemFullKit) -> Bool)
    -> [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    -> [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    forall a. (a -> Bool) -> [a] -> [a]
    takeWhile (\(Double
    value, Bool
    hasEffect, Int
    timeout, Int
    _, ItemId
    _, ItemFullKit
    _) ->
                                     Double
    value Double -> Double -> Bool
    forall a. Eq a => a -> a -> Bool
    == Double
    value1
                                     Bool -> Bool -> Bool
    && Bool
    hasEffect Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Bool
    hasEffect1
                                     Bool -> Bool -> Bool
    && Int
    timeout Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    timeout1)
                                 [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    iis
          -- Randomize only the no-timeout items. Others need to activate
          -- in the order shown in HUD and also not risk of only one always used.
          (_, _, _, _, iid, _) <- if Int
    timeout1 Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    0 Bool -> Bool -> Bool
    || ItemFull -> Bool
    itemSuspect ItemFull
    itemFull1
                                  then (Double, Bool, Int, Int, ItemId, ItemFullKit)
    -> m (Double, Bool, Int, Int, ItemId, ItemFullKit)
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Double, Bool, Int, Int, ItemId, ItemFullKit)
    ii1
                                  else Rnd (Double, Bool, Int, Int, ItemId, ItemFullKit)
    -> m (Double, Bool, Int, Int, ItemId, ItemFullKit)
    forall (m :: * -> *) a. MonadClient m => Rnd a -> m a
    rndToAction (Rnd (Double, Bool, Int, Int, ItemId, ItemFullKit)
     -> m (Double, Bool, Int, Int, ItemId, ItemFullKit))
    -> Rnd (Double, Bool, Int, Int, ItemId, ItemFullKit)
    -> m (Double, Bool, Int, Int, ItemId, ItemFullKit)
    forall a b. (a -> b) -> a -> b
    $ [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    -> Rnd (Double, Bool, Int, Int, ItemId, ItemFullKit)
    forall a. [a] -> Rnd a
    oneOf [(Double, Bool, Int, Int, ItemId, ItemFullKit)]
    minIis
          -- Prefer COrgan, to hint to the player to trash the equivalent CEqp item.
          let cstore = if Maybe ItemFullKit -> Bool
    forall a. Maybe a -> Bool
    isJust (ItemId -> [(ItemId, ItemFullKit)] -> Maybe ItemFullKit
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup ItemId
    iid [(ItemId, ItemFullKit)]
    bodyAssocs) then CStore
    COrgan else CStore
    CEqp
          return $ Just $ ReqMelee target iid cstore

    updateSalter :: MonadClient m
                 => LevelId -> [(Point, ContentId TileKind)] -> m ()
    updateSalter :: forall (m :: * -> *).
    MonadClient m =>
    LevelId -> [(Point, ContentId TileKind)] -> m ()
    updateSalter LevelId
    lid [(Point, ContentId TileKind)]
    pts = do
      COps{coTileSpeedup} <- (State -> COps) -> m COps
    forall a. (State -> a) -> m a
    forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
    getsState State -> COps
    scops
      let pas = ((Point, ContentId TileKind) -> (Point, Word8))
    -> [(Point, ContentId TileKind)] -> [(Point, Word8)]
    forall a b. (a -> b) -> [a] -> [b]
    map ((ContentId TileKind -> Word8)
    -> (Point, ContentId TileKind) -> (Point, Word8)
    forall b c d. (b -> c) -> (d, b) -> (d, c)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (d, b) (d, c)
    second ((ContentId TileKind -> Word8)
     -> (Point, ContentId TileKind) -> (Point, Word8))
    -> (ContentId TileKind -> Word8)
    -> (Point, ContentId TileKind)
    -> (Point, Word8)
    forall a b. (a -> b) -> a -> b
    $ Int -> Word8
    forall a. Enum a => Int -> a
    toEnum (Int -> Word8)
    -> (ContentId TileKind -> Int) -> ContentId TileKind -> Word8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TileSpeedup -> ContentId TileKind -> Int
    Tile.alterMinWalk TileSpeedup
    coTileSpeedup) [(Point, ContentId TileKind)]
    pts
          f = (Array Word8 -> [(Point, Word8)] -> Array Word8
    forall c. UnboxRepClass c => Array c -> [(Point, c)] -> Array c
    PointArray.// [(Point, Word8)]
    pas)
      modifyClient $ \StateClient
    cli -> StateClient
    cli {salter = EM.adjust f lid $ salter cli}

    createSalter :: State -> AlterLid
    createSalter :: State -> EnumMap LevelId (Array Word8)
    createSalter State
    s =
      let COps{TileSpeedup
    coTileSpeedup :: COps -> TileSpeedup
    coTileSpeedup :: TileSpeedup
    coTileSpeedup} = State -> COps
    scops State
    s
          f :: Level -> Array Word8
    f Level{TileMap
    ltile :: TileMap
    ltile :: Level -> TileMap
    ltile} =
            (ContentId TileKind -> Word8) -> TileMap -> Array Word8
    forall c d.
    (UnboxRepClass c, UnboxRepClass d) =>
    (c -> d) -> Array c -> Array d
    PointArray.mapA (Int -> Word8
    forall a. Enum a => Int -> a
    toEnum (Int -> Word8)
    -> (ContentId TileKind -> Int) -> ContentId TileKind -> Word8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TileSpeedup -> ContentId TileKind -> Int
    Tile.alterMinWalk TileSpeedup
    coTileSpeedup) TileMap
    ltile
      in (Level -> Array Word8)
    -> EnumMap LevelId Level -> EnumMap LevelId (Array Word8)
    forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
    EM.map Level -> Array Word8
    f (EnumMap LevelId Level -> EnumMap LevelId (Array Word8))
    -> EnumMap LevelId Level -> EnumMap LevelId (Array Word8)
    forall a b. (a -> b) -> a -> b
    $ State -> EnumMap LevelId Level
    sdungeon State
    s