diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,7 +12,7 @@
 - make braced actors immune to translocation effects
 - use mouse for movement, actor selection, aiming
 - don't run straight with selected actors, but go-to cross-hair with them
-- speed up default frame rate, slot down projectiles visually
+- speed up default frame rate, slow down projectiles visually
 - rework item manipulation UI
 - you can pick up many items at once and it costs only one turn
 - allow actors to apply and project from the shared stash
diff --git a/Game/LambdaHack/Atomic/CmdAtomic.hs b/Game/LambdaHack/Atomic/CmdAtomic.hs
--- a/Game/LambdaHack/Atomic/CmdAtomic.hs
+++ b/Game/LambdaHack/Atomic/CmdAtomic.hs
@@ -97,12 +97,12 @@
   -- Assorted.
   | UpdTimeItem !ItemId !Container !ItemTimer !ItemTimer
   | UpdAgeGame !(Delta Time) ![LevelId]
-  | UpdDiscover !Container !ItemId !(Kind.Id ItemKind) !ItemSeed
-  | UpdCover !Container !ItemId !(Kind.Id ItemKind) !ItemSeed
+  | UpdDiscover !Container !ItemId !(Kind.Id ItemKind) !ItemSeed !AbsDepth
+  | UpdCover !Container !ItemId !(Kind.Id ItemKind) !ItemSeed !AbsDepth
   | UpdDiscoverKind !Container !ItemId !(Kind.Id ItemKind)
   | UpdCoverKind !Container !ItemId !(Kind.Id ItemKind)
-  | UpdDiscoverSeed !Container !ItemId !ItemSeed
-  | UpdCoverSeed !Container !ItemId !ItemSeed
+  | UpdDiscoverSeed !Container !ItemId !ItemSeed !AbsDepth
+  | UpdCoverSeed !Container !ItemId !ItemSeed !AbsDepth
   | UpdPerception !LevelId !Perception !Perception
   | UpdRestart !FactionId !DiscoveryKind !FactionPers !State !DebugModeCli
   | UpdRestartServer !State
@@ -182,12 +182,12 @@
   UpdLoseSmell lid sms -> Just $ UpdSpotSmell lid sms
   UpdTimeItem iid c fromIt toIt -> Just $ UpdTimeItem iid c toIt fromIt
   UpdAgeGame delta lids -> Just $ UpdAgeGame (timeDeltaReverse delta) lids
-  UpdDiscover c iid ik seed -> Just $ UpdCover c iid ik seed
-  UpdCover c iid ik seed -> Just $ UpdDiscover c iid ik seed
+  UpdDiscover c iid ik seed ldepth -> Just $ UpdCover c iid ik seed ldepth
+  UpdCover c iid ik seed ldepth -> Just $ UpdDiscover c iid ik seed ldepth
   UpdDiscoverKind c iid ik -> Just $ UpdCoverKind c iid ik
   UpdCoverKind c iid ik -> Just $ UpdDiscoverKind c iid ik
-  UpdDiscoverSeed c iid seed -> Just $ UpdCoverSeed c iid seed
-  UpdCoverSeed c iid seed -> Just $ UpdDiscoverSeed c iid seed
+  UpdDiscoverSeed c iid seed ldepth -> Just $ UpdCoverSeed c iid seed ldepth
+  UpdCoverSeed c iid seed ldepth -> Just $ UpdDiscoverSeed c iid seed ldepth
   UpdPerception lid outPer inPer -> Just $ UpdPerception lid inPer outPer
   UpdRestart{} -> Just cmd  -- here history ends; change direction
   UpdRestartServer{} -> Just cmd  -- here history ends; change direction
diff --git a/Game/LambdaHack/Atomic/PosAtomicRead.hs b/Game/LambdaHack/Atomic/PosAtomicRead.hs
--- a/Game/LambdaHack/Atomic/PosAtomicRead.hs
+++ b/Game/LambdaHack/Atomic/PosAtomicRead.hs
@@ -141,12 +141,12 @@
     return $! PosSmell lid ps
   UpdTimeItem _ c _ _ -> singleContainer c
   UpdAgeGame _ _ -> return PosAll
-  UpdDiscover c _ _ _ -> singleContainer c
-  UpdCover c _ _ _ -> singleContainer c
+  UpdDiscover c _ _ _ _ -> singleContainer c
+  UpdCover c _ _ _ _ -> singleContainer c
   UpdDiscoverKind c _ _ -> singleContainer c
   UpdCoverKind c _ _ -> singleContainer c
-  UpdDiscoverSeed c _ _ -> singleContainer c
-  UpdCoverSeed c _ _ -> singleContainer c
+  UpdDiscoverSeed c _ _ _ -> singleContainer c
+  UpdCoverSeed c _ _ _ -> singleContainer c
   UpdPerception{} -> return PosNone
   UpdRestart fid _ _ _ _ -> return $! PosFid fid
   UpdRestartServer _ -> return PosSer
@@ -302,7 +302,7 @@
       -- Death of a party member does not need to be heard,
       -- because it's seen.
       | not $ fid == bfid body || bproj body -> return $ Just "shriek"
-    UpdCreateItem{} -> return $ Just "clatter"
+    UpdCreateItem _ _ _ (CActor _ CGround) -> return $ Just "clatter"
     UpdAlterTile _ _ fromTile _ -> do
       Kind.COps{cotile} <- getsState scops
       if Tile.isDoor cotile fromTile
diff --git a/Game/LambdaHack/Client/AI/HandleAbilityClient.hs b/Game/LambdaHack/Client/AI/HandleAbilityClient.hs
--- a/Game/LambdaHack/Client/AI/HandleAbilityClient.hs
+++ b/Game/LambdaHack/Client/AI/HandleAbilityClient.hs
@@ -265,11 +265,10 @@
       filterWeapon | onlyWeapon = filter isWeapon
                    | otherwise = id
       prepareOne (oldN, l4) ((_, (k, _)), (iid, itemFull)) =
-        -- TODO: instead of pickup to eqp and then move to inv, pickup to inv
         let n = oldN + k
             (newN, toCStore)
               | calmE && goesIntoSha itemFull = (oldN, CSha)
-              | goesIntoInv itemFull || eqpOverfull b n = (oldN, CInv)
+              | not (goesIntoEqp itemFull) || eqpOverfull b n = (oldN, CInv)
               | otherwise = (n, CEqp)
         in (newN, (iid, k, CGround, toCStore) : l4)
       (_, prepared) = foldl' prepareOne (0, []) $ filterWeapon benItemL
@@ -676,10 +675,15 @@
   actorSk <- actorSkillsClient aid
   b <- getsState $ getActorBody aid
   localTime <- getsState $ getLocalTime (blid b)
-  let skill = EM.findWithDefault 0 AbProject actorSk
+  let skill = EM.findWithDefault 0 AbApply actorSk
       q _ itemFull _ activeItems =
-        either (const False) id
-        $ permittedApply " " localTime skill itemFull b activeItems
+        -- TODO: terrible hack to prevent the use of identified healing gems
+        let freq = case itemDisco itemFull of
+              Nothing -> []
+              Just ItemDisco{itemKind} -> IK.ifreq itemKind
+        in maybe True (<= 0) (lookup "gem" freq)
+           && either (const False) id
+                (permittedApply " " localTime skill itemFull b activeItems)
   benList <- benAvailableItems aid q [CEqp, CInv, CGround]
   organs <- mapM (getsState . getItemBody) $ EM.keys $ borgan b
   let itemLegal itemFull = case applyGroup of
diff --git a/Game/LambdaHack/Client/AI/Preferences.hs b/Game/LambdaHack/Client/AI/Preferences.hs
--- a/Game/LambdaHack/Client/AI/Preferences.hs
+++ b/Game/LambdaHack/Client/AI/Preferences.hs
@@ -156,7 +156,7 @@
             isWeapon = isMeleeEqp itemFull
             totalSum
               | isWeapon && effSum < 0 = - effSum + selfSum
-              | goesIntoInv itemFull = effSum
+              | not $ goesIntoEqp itemFull = effSum
               | mixedBlessing =
                   0  -- significant mixed blessings out of AI control
               | otherwise = selfSum  -- if the weapon heals the enemy, it
diff --git a/Game/LambdaHack/Client/HandleAtomicClient.hs b/Game/LambdaHack/Client/HandleAtomicClient.hs
--- a/Game/LambdaHack/Client/HandleAtomicClient.hs
+++ b/Game/LambdaHack/Client/HandleAtomicClient.hs
@@ -93,7 +93,7 @@
                                  || t /= Tile.hideAs cotile tClient)
         newTs = filter notKnown ts
     return $! if null newTs then [] else [UpdSpotTile lid newTs]
-  UpdDiscover c iid _ seed -> do
+  UpdDiscover c iid _ seed ldepth -> do
     itemD <- getsState sitemD
     case EM.lookup iid itemD of
       Nothing -> return []
@@ -104,9 +104,9 @@
             discoEffect <- getsClient sdiscoEffect
             if iid `EM.member` discoEffect
               then return []
-              else return [UpdDiscoverSeed c iid seed]
+              else return [UpdDiscoverSeed c iid seed ldepth]
           else return [cmd]
-  UpdCover c iid ik _ -> do
+  UpdCover c iid ik _ _ -> do
     itemD <- getsState sitemD
     case EM.lookup iid itemD of
       Nothing -> return []
@@ -137,7 +137,7 @@
         if jkindIx item `EM.notMember` discoKind
         then return []
         else return [cmd]
-  UpdDiscoverSeed _ iid _ -> do
+  UpdDiscoverSeed _ iid _ _ -> do
     itemD <- getsState sitemD
     case EM.lookup iid itemD of
       Nothing -> return []
@@ -150,7 +150,7 @@
           if iid `EM.member` discoEffect
             then return []
             else return [cmd]
-  UpdCoverSeed _ iid _ -> do
+  UpdCoverSeed _ iid _ _ -> do
     itemD <- getsState sitemD
     case EM.lookup iid itemD of
       Nothing -> return []
@@ -255,16 +255,16 @@
       cli { stargetD = case (mtgt, mleader) of
               (Just tgt, Just leader) -> EM.singleton leader tgt
               _ -> EM.empty }
-  UpdDiscover c iid ik seed -> do
+  UpdDiscover c iid ik seed ldepth -> do
     discoverKind c iid ik
-    discoverSeed c iid seed
-  UpdCover c iid ik seed -> do
+    discoverSeed c iid seed ldepth
+  UpdCover c iid ik seed _ldepth -> do
     coverSeed c iid seed
     coverKind c iid ik
   UpdDiscoverKind c iid ik -> discoverKind c iid ik
   UpdCoverKind c iid ik -> coverKind c iid ik
-  UpdDiscoverSeed c iid seed -> discoverSeed c iid seed
-  UpdCoverSeed c iid seed -> coverSeed c iid seed
+  UpdDiscoverSeed c iid seed  ldepth -> discoverSeed c iid seed ldepth
+  UpdCoverSeed c iid seed _ldepth -> coverSeed c iid seed
   UpdPerception lid outPer inPer -> perception lid outPer inPer
   UpdRestart side sdiscoKind sfper _ sdebugCli -> do
     shistory <- getsClient shistory
@@ -351,12 +351,11 @@
   modifyClient $ \cli -> cli {sdiscoKind = EM.alter f (jkindIx item) (sdiscoKind cli)}
 
 discoverSeed :: MonadClient m
-             => Container -> ItemId -> ItemSeed -> m ()
-discoverSeed c iid seed = do
+             => Container -> ItemId -> ItemSeed -> AbsDepth -> m ()
+discoverSeed c iid seed ldepth = do
   Kind.COps{coitem=Kind.Ops{okind}} <- getsState scops
   discoKind <- getsClient sdiscoKind
   item <- getsState $ getItemBody iid
-  Level{ldepth} <- getLevel (jlid item)
   totalDepth <- getsState stotalDepth
   case EM.lookup (jkindIx item) discoKind of
     Nothing -> assert `failure` "kind not known"
@@ -370,8 +369,8 @@
 
 coverSeed :: MonadClient m
           => Container -> ItemId -> ItemSeed -> m ()
-coverSeed c iid ik = do
-  let f Nothing = assert `failure` "already covered" `twith` (c, iid, ik)
+coverSeed c iid seed = do
+  let f Nothing = assert `failure` "already covered" `twith` (c, iid, seed)
       f Just{} = Nothing  -- checking that old and new agree is too much work
   modifyClient $ \cli -> cli {sdiscoEffect = EM.alter f iid (sdiscoEffect cli)}
 
diff --git a/Game/LambdaHack/Client/Key.hs b/Game/LambdaHack/Client/Key.hs
--- a/Game/LambdaHack/Client/Key.hs
+++ b/Game/LambdaHack/Client/Key.hs
@@ -173,6 +173,9 @@
                 ++ dirKeypadShiftKey
                 ++ map Char dirKeypadShiftChar
 
+dirRunShift :: [Key]
+dirRunShift = dirRunControl
+
 dirAllKey :: Bool -> Bool -> [Key]
 dirAllKey configVi configLaptop =
   dirMoveNoModifier configVi configLaptop
@@ -199,6 +202,7 @@
   in mapMove NoModifier (dirMoveNoModifier configVi configLaptop)
      ++ mapRun NoModifier (dirRunNoModifier configVi configLaptop)
      ++ mapRun Control dirRunControl
+     ++ mapRun Shift dirRunShift
 
 mkKM :: String -> KM
 mkKM s = let mkKey sk =
diff --git a/Game/LambdaHack/Client/UI/DisplayAtomicClient.hs b/Game/LambdaHack/Client/UI/DisplayAtomicClient.hs
--- a/Game/LambdaHack/Client/UI/DisplayAtomicClient.hs
+++ b/Game/LambdaHack/Client/UI/DisplayAtomicClient.hs
@@ -59,7 +59,10 @@
                        => Bool -> State -> StateClient -> UpdAtomic -> m ()
 displayRespUpdAtomicUI verbose oldState oldStateClient cmd = case cmd of
   -- Create/destroy actors and items.
-  UpdCreateActor aid body _ -> createActorUI aid body verbose "appear"
+  UpdCreateActor aid body _ -> do
+    side <- getsClient sside
+    let verb = "appear" <+> if bfid body == side then "" else "suddenly"
+    createActorUI aid body verbose (MU.Text verb)
   UpdDestroyActor aid body _ -> do
     destroyActorUI aid body "die" "be destroyed" verbose
     side <- getsClient sside
@@ -147,7 +150,18 @@
         when (null closeFoes) $ do  -- obvious where the feeling comes from
           aidVerbMU aid "hear something"
           msgDuplicateScrap
-  UpdFidImpressedActor{} -> return ()
+  UpdFidImpressedActor aid _fidOld fidNew -> do
+    b <- getsState $ getActorBody aid
+    actorVerbMU aid b $
+      if fidNew == bfid b then
+        "get calmed and refocused"
+-- TODO: only show for liquids; for others say 'flash', etc.
+--              "get refocused by the fragrant moisture"
+      else if fidNew == bfidOriginal b then
+        "remember forgone allegiance suddenly"
+      else
+        "experience anxiety that weakens resolve and erodes loyalty"
+-- TODO     "inhale the sweet smell that weakens resolve and erodes loyalty"
   UpdTrajectory{} -> return ()
   UpdColorActor{} -> return ()
   -- Change faction attributes.
@@ -218,11 +232,11 @@
   -- Assorted.
   UpdTimeItem{} -> return ()
   UpdAgeGame{} -> return ()
-  UpdDiscover c iid _ _ -> discover c oldStateClient iid
+  UpdDiscover c iid _ _ _ -> discover c oldStateClient iid
   UpdCover{} -> return ()  -- don't spam when doing undo
   UpdDiscoverKind c iid _ -> discover c oldStateClient iid
   UpdCoverKind{} -> return ()  -- don't spam when doing undo
-  UpdDiscoverSeed c iid _ -> discover c oldStateClient iid
+  UpdDiscoverSeed c iid _ _ -> discover c oldStateClient iid
   UpdCoverSeed{} -> return ()  -- don't spam when doing undo
   UpdPerception{} -> return ()
   UpdRestart fid _ _ _ _ -> do
@@ -740,16 +754,7 @@
             msgAdd $ makeSentence
               [MU.SubjectVerbSg subject verb, MU.Text fidSourceName, "control"]
           stopPlayBack
-        IK.Impress ->
-          actorVerbMU aid b
-          $ if bfidImpressed b /= bfid b
-            then
-              "get calmed and refocused"
--- TODO: only show for liquids; for others say "='flash', etc.
---              "get refocused by the fragrant moisture"
-            else
-              "experience anxiety that weakens resolve and erodes loyalty"
--- TODO:        "inhale the sweet smell that weakens resolve and erodes loyalty"
+        IK.Impress -> return ()
         IK.CallFriend{} -> return ()
         IK.Summon{} -> return ()
         IK.Ascend k | k > 0 -> actorVerbMU aid b "find a way upstairs"
@@ -843,7 +848,8 @@
             displayDelay
           let ageDisp = EM.insert arena localTime
           modifyClient $ \cli -> cli {sdisplayed = ageDisp $ sdisplayed cli}
-          displayPush ""
+          when (not (bproj b)) $  -- projectiles display animations instead
+            displayPush ""
 
 setLastSlot :: MonadClientUI m => ActorId -> ItemId -> CStore -> m ()
 setLastSlot aid iid cstore = do
diff --git a/Game/LambdaHack/Client/UI/HandleHumanGlobalClient.hs b/Game/LambdaHack/Client/UI/HandleHumanGlobalClient.hs
--- a/Game/LambdaHack/Client/UI/HandleHumanGlobalClient.hs
+++ b/Game/LambdaHack/Client/UI/HandleHumanGlobalClient.hs
@@ -23,6 +23,7 @@
 import Data.List
 import Data.Maybe
 import Data.Monoid
+import Data.Text (Text)
 import qualified NLP.Miniutter.English as MU
 
 import Game.LambdaHack.Client.BfsClient
@@ -261,7 +262,7 @@
 
 -- * MoveItem
 
-moveItemHuman :: MonadClientUI m
+moveItemHuman :: forall m. MonadClientUI m
               => [CStore] -> CStore -> Maybe MU.Part -> Bool
               -> m (SlideOrCmd (RequestTimed 'AbMoveItem))
 moveItemHuman cLegalRaw destCStore mverb auto = do
@@ -295,7 +296,7 @@
         then case destCStore of
           CEqp | calmE && goesIntoSha itemFull ->
             retRec CSha
-          CEqp | goesIntoInv itemFull ->
+          CEqp | not $ goesIntoEqp itemFull ->
             retRec CInv
           CEqp | eqpOverfull b (oldN + k) -> do
             msgAdd $ "Warning:" <+> showReqFailure EqpOverfull <> "."
@@ -305,9 +306,17 @@
         else case destCStore of
           CEqp | eqpOverfull b (oldN + k) -> failSer EqpOverfull
           _ -> retRec destCStore
-  ggi <- if auto
-         then getAnyItems verb cLegalRaw cLegal False False
-         else getAnyItems verb cLegalRaw cLegal True True
+      prompt = makePhrase ["What to", verb]
+      promptEqp = makePhrase ["What consumable to", verb]
+      p :: CStore -> (Text, m Suitability)
+      p cstore = if cstore `elem` [CEqp, CSha] && cLegalRaw /= [CGround]
+                 then (promptEqp, return $ SuitsSomething goesIntoEqp)
+                 else (prompt, return SuitsEverything)
+      (promptGeneric, psuit) = p destCStore
+  ggi <-
+    if auto
+    then getAnyItems psuit prompt promptGeneric cLegalRaw cLegal False False
+    else getAnyItems psuit prompt promptGeneric cLegalRaw cLegal True True
   case ggi of
     Right (l, MStore fromCStore) -> do
       leader2 <- getLeaderUI
@@ -466,7 +475,7 @@
   leader <- getLeaderUI
   b <- getsState $ getActorBody leader
   actorSk <- actorSkillsClient leader
-  let skill = EM.findWithDefault 0 AbProject actorSk
+  let skill = EM.findWithDefault 0 AbApply actorSk
   activeItems <- activeItemsClient leader
   localTime <- getsState $ getLocalTime (blid b)
   let cLegal = [CGround, CInv, CEqp, CSha]
@@ -674,7 +683,7 @@
     b <- getsState $ getActorBody leader
     cursorPos <- cursorToPos
     case cursorPos of
-      Nothing -> failWith "no leader"
+      Nothing -> failWith "crosshair position invalid"
       Just c | c == bpos b ->
         if initialStep
         then return $ Right $ RequestAnyAbility ReqWait
diff --git a/Game/LambdaHack/Client/UI/InventoryClient.hs b/Game/LambdaHack/Client/UI/InventoryClient.hs
--- a/Game/LambdaHack/Client/UI/InventoryClient.hs
+++ b/Game/LambdaHack/Client/UI/InventoryClient.hs
@@ -109,19 +109,21 @@
 -- and let him specify the number of items.
 -- Used, e.g., for picking up and inventory manipulation.
 getAnyItems :: MonadClientUI m
-            => MU.Part   -- ^ the verb describing the action
+            => m Suitability
+                         -- ^ which items to consider suitable
+            -> Text      -- ^ specific prompt for only suitable items
+            -> Text      -- ^ generic prompt
             -> [CStore]  -- ^ initial legal modes
             -> [CStore]  -- ^ legal modes after Calm taken into account
             -> Bool      -- ^ whether to ask, when the only item
                          --   in the starting mode is suitable
             -> Bool      -- ^ whether to ask for the number of items
             -> m (SlideOrCmd ([(ItemId, ItemFull)], ItemDialogMode))
-getAnyItems verb cLegalRaw cLegalAfterCalm askWhenLone askNumber = do
-  let prompt _ _ cCur =
-        makePhrase ["What to", verb, MU.Text $ ppItemDialogModeFrom cCur]
-  soc <- getFull (return SuitsEverything)
-                 prompt prompt False
-                 cLegalRaw cLegalAfterCalm
+getAnyItems psuit prompt promptGeneric cLegalRaw cLegalAfterCalm askWhenLone askNumber = do
+  soc <- getFull psuit
+                 (\_ _ cCur -> prompt <+> ppItemDialogModeFrom cCur)
+                 (\_ _ cCur -> promptGeneric <+> ppItemDialogModeFrom cCur)
+                 False cLegalRaw cLegalAfterCalm
                  askWhenLone True ISuitable
   case soc of
     Left _ -> return soc
diff --git a/Game/LambdaHack/Client/UI/KeyBindings.hs b/Game/LambdaHack/Client/UI/KeyBindings.hs
--- a/Game/LambdaHack/Client/UI/KeyBindings.hs
+++ b/Game/LambdaHack/Client/UI/KeyBindings.hs
@@ -75,7 +75,7 @@
       , "                /|\\            /|\\            /|\\"
       , "               1 2 3          j k l          b j n"
       , ""
-      , "In aiming mode the same keys (or mouse) move the crosshair (the white box)."
+      , "In aiming mode (KEYPAD_* or \\) the same keys (or mouse) move the crosshair."
       , "Press 'KEYPAD_5' (or 'i' or '.') to wait, bracing for blows, which reduces"
       , "any damage taken and makes it impossible for foes to displace you."
       , "You displace enemies or friends by bumping into them with SHIFT (or CTRL)."
@@ -108,7 +108,7 @@
       , "Press PGUP to return to previous pages or ESC to see the map again."
       ]
     pickLeaderDescription =
-      [ fmt 16 "0, 1, ... 6" "pick a particular actor as the new leader"
+      [ fmt 16 "0, 1 ... 6" "pick a particular actor as the new leader"
       ]
     casualDescription = "Minimal cheat sheet for casual play"
     fmt n k h = T.justifyRight 72 ' '
@@ -125,7 +125,7 @@
                          | (from, (_, cats, Macro _ [to])) <- bcmdList
                          , K.mkKM to == k
                          , any (`notElem` [CmdDebug, CmdInternal]) cats ]
-    disp k = T.concat $ intersperse " and " $ map K.showKM $ coImage k
+    disp k = T.concat $ intersperse " or " $ map K.showKM $ coImage k
     keysN n cat = [ fmt n (disp k) h
                   | (k, (h, cats, _)) <- bcmdList, cat `elem` cats, h /= "" ]
     -- TODO: measure the longest key sequence and set the caption automatically
diff --git a/Game/LambdaHack/Client/UI/MonadClientUI.hs b/Game/LambdaHack/Client/UI/MonadClientUI.hs
--- a/Game/LambdaHack/Client/UI/MonadClientUI.hs
+++ b/Game/LambdaHack/Client/UI/MonadClientUI.hs
@@ -295,13 +295,7 @@
       fact <- getsState $ (EM.! side) . sfactionD
       case gquit fact of
         Just Status{stDepth} -> return $! toEnum stDepth
-        Nothing -> do
-          dungeon <- getsState sdungeon
-          let (minD, maxD) =
-                case (EM.minViewWithKey dungeon, EM.maxViewWithKey dungeon) of
-                  (Just ((s, _), _), Just ((e, _), _)) -> (s, e)
-                  _ -> assert `failure` "empty dungeon" `twith` dungeon
-          return $! max minD $ min maxD $ toEnum $ fentryLevel $ gplayer fact
+        Nothing -> getEntryArena fact
 
 viewedLevel :: MonadClientUI m => m LevelId
 viewedLevel = do
@@ -319,12 +313,11 @@
       b <- getsState $ getActorBody aid
       maxHP <- sumOrganEqpClient IK.EqpSlotAddMaxHP aid
       let percentage = 100 * bhp b `div` xM (max 5 maxHP)
-          stars | percentage < 20  = "[_____]"
-                | percentage < 40  = "[*____]"
-                | percentage < 60  = "[**___]"
-                | percentage < 80  = "[***__]"
-                | percentage < 100 = "[****_]"
-                | otherwise        = "[*****]"
+          stars | percentage < 20  = "[____]"
+                | percentage < 40  = "[*___]"
+                | percentage < 60  = "[**__]"
+                | percentage < 80  = "[***_]"
+                | otherwise        = "[****]"
           hpIndicator = if bfid b == side then Nothing else Just stars
       return (bname b, hpIndicator)
     Just (TEnemyPos _ lid p _) -> do
diff --git a/Game/LambdaHack/Common/Actor.hs b/Game/LambdaHack/Common/Actor.hs
--- a/Game/LambdaHack/Common/Actor.hs
+++ b/Game/LambdaHack/Common/Actor.hs
@@ -184,7 +184,7 @@
   in bhp b <= oneM || 5 * bhp b < xM maxHP && bhp b <= xM 10
 
 hpHuge :: Actor -> Bool
-hpHuge b = bhp b > xM 30
+hpHuge b = bhp b > xM 40
 
 calmEnough :: Actor -> [ItemFull] -> Bool
 calmEnough b activeItems =
diff --git a/Game/LambdaHack/Common/ActorState.hs b/Game/LambdaHack/Common/ActorState.hs
--- a/Game/LambdaHack/Common/ActorState.hs
+++ b/Game/LambdaHack/Common/ActorState.hs
@@ -12,8 +12,8 @@
   , nearbyFreePoints, whereTo, getCarriedAssocs, getCarriedIidCStore
   , posToActors, posToActor, getItemBody, memActor, getActorBody
   , tryFindHeroK, getLocalTime, itemPrice, regenCalmDelta
-  , actorInAmbient, actorSkills, dispEnemy
-  , fullAssocs, itemToFull, goesIntoInv, goesIntoSha, eqpOverfull
+  , actorInAmbient, actorSkills, dispEnemy, fullAssocs, itemToFull
+  , goesIntoEqp, goesIntoInv, goesIntoSha, eqpOverfull
   , storeFromC, lidFromC, aidFromC, hasCharge
   , strongestMelee, isMelee, isMeleeEqp
   ) where
@@ -380,13 +380,17 @@
 -- Non-durable item that hurts doesn't go into equipment by default,
 -- but if it is in equipment or among organs, it's used for melee
 -- nevertheless, e.g., thorns.
-goesIntoInv :: ItemFull -> Bool
-goesIntoInv itemFull = not (isJust (strengthEqpSlot $ itemBase itemFull))
+goesIntoEqp :: ItemFull -> Bool
+goesIntoEqp itemFull = isJust (strengthEqpSlot $ itemBase itemFull)
 -- TODO: not needed if EqpSlotWeapon stays         || isMeleeEqp itemFull)
 
+goesIntoInv :: ItemFull -> Bool
+goesIntoInv itemFull = IK.Precious `notElem` jfeature (itemBase itemFull)
+                       && not (goesIntoEqp itemFull)
+
 goesIntoSha :: ItemFull -> Bool
 goesIntoSha itemFull = IK.Precious `elem` jfeature (itemBase itemFull)
-                       && goesIntoInv itemFull
+                       && not (goesIntoEqp itemFull)
 
 eqpOverfull :: Actor -> Int -> Bool
 eqpOverfull b n = let size = sum $ map fst $ EM.elems $ beqp b
diff --git a/Game/LambdaHack/Common/MonadStateRead.hs b/Game/LambdaHack/Common/MonadStateRead.hs
--- a/Game/LambdaHack/Common/MonadStateRead.hs
+++ b/Game/LambdaHack/Common/MonadStateRead.hs
@@ -2,9 +2,11 @@
 -- player actions. Has no access to the the main action type.
 module Game.LambdaHack.Common.MonadStateRead
   ( MonadStateRead(..)
-  , getLevel, nUI, posOfAid, factionCanEscape, factionLoots, getGameMode
+  , getLevel, nUI, posOfAid, factionCanEscape, factionLoots
+  , getGameMode, getEntryArena
   ) where
 
+import Control.Exception.Assert.Sugar
 import qualified Data.EnumMap.Strict as EM
 
 import Game.LambdaHack.Common.Actor
@@ -55,3 +57,12 @@
   Kind.COps{comode=Kind.Ops{okind}} <- getsState scops
   t <- getsState sgameModeId
   return $! okind t
+
+getEntryArena :: MonadStateRead m => Faction -> m LevelId
+getEntryArena fact = do
+  dungeon <- getsState sdungeon
+  let (minD, maxD) =
+        case (EM.minViewWithKey dungeon, EM.maxViewWithKey dungeon) of
+          (Just ((s, _), _), Just ((e, _), _)) -> (s, e)
+          _ -> assert `failure` "empty dungeon" `twith` dungeon
+  return $! max minD $ min maxD $ toEnum $ fentryLevel $ gplayer fact
diff --git a/Game/LambdaHack/Common/Time.hs b/Game/LambdaHack/Common/Time.hs
--- a/Game/LambdaHack/Common/Time.hs
+++ b/Game/LambdaHack/Common/Time.hs
@@ -3,7 +3,8 @@
 module Game.LambdaHack.Common.Time
   ( Time, timeZero, timeClip, timeTurn, timeEpsilon
   , absoluteTimeAdd, absoluteTimeNegate, timeFit, timeFitUp
-  , Delta(..), timeShift, timeDeltaToFrom, timeDeltaReverse, timeDeltaScale
+  , Delta(..), timeShift, timeDeltaToFrom
+  , timeDeltaSubtract, timeDeltaReverse, timeDeltaScale
   , timeDeltaToDigit, ticksPerMeter
   , Speed, toSpeed, fromSpeed, speedZero, speedNormal
   , speedScale, timeDeltaDiv, speedAdd, speedNegate
@@ -99,6 +100,11 @@
 -- The arguments are in the same order as in the underlying scalar subtraction.
 timeDeltaToFrom :: Time -> Time -> Delta Time
 timeDeltaToFrom (Time t1) (Time t2) = Delta $ Time (t1 - t2)
+
+-- | Time time vector between the second and the first absolute times.
+-- The arguments are in the same order as in the underlying scalar subtraction.
+timeDeltaSubtract :: Delta Time -> Delta Time -> Delta Time
+timeDeltaSubtract (Delta (Time t1)) (Delta (Time t2)) = Delta $ Time (t1 - t2)
 
 -- | Scale the time vector by an @Int@ scalar value.
 timeDeltaScale :: Delta Time -> Int -> Delta Time
diff --git a/Game/LambdaHack/Server/CommonServer.hs b/Game/LambdaHack/Server/CommonServer.hs
--- a/Game/LambdaHack/Server/CommonServer.hs
+++ b/Game/LambdaHack/Server/CommonServer.hs
@@ -3,8 +3,8 @@
 module Game.LambdaHack.Server.CommonServer
   ( execFailure, resetFidPerception, resetLitInDungeon, getPerFid
   , revealItems, moveStores, deduceQuits, deduceKilled, electLeader
-  , addActor, addActorIid, projectFail, pickWeaponServer, sumOrganEqpServer
-  , actorSkillsServer
+  , addActor, addActorIid, projectFail
+  , pickWeaponServer, sumOrganEqpServer, actorSkillsServer
   ) where
 
 import Control.Applicative
@@ -101,11 +101,10 @@
       per = EM.findWithDefault failLvl lid fper
   return $! per
 
--- We don't provide ActorId, because the actor can be dead and then, e.g.,
--- containers with the ActorId are invalid and lead to crashes.
 revealItems :: (MonadAtomic m, MonadServer m)
             => Maybe FactionId -> Maybe (ActorId, Actor) -> m ()
 revealItems mfid mbody = do
+  let !_A = assert (maybe True (not . bproj . snd) mbody) ()
   itemToF <- itemToFullServer
   dungeon <- getsState sdungeon
   let discover aid store iid k =
@@ -114,12 +113,14 @@
         in case itemDisco itemFull of
           Just ItemDisco{itemKindId} -> do
             seed <- getsServer $ (EM.! iid) . sitemSeedD
-            execUpdAtomic $ UpdDiscover c iid itemKindId seed
+            Level{ldepth} <- getLevel $ jlid $ itemBase itemFull
+            execUpdAtomic $ UpdDiscover c iid itemKindId seed ldepth
           _ -> assert `failure` (mfid, mbody, c, iid, itemFull)
       f aid = do
         b <- getsState $ getActorBody aid
         let ourSide = maybe True (== bfid b) mfid
-        when ourSide $
+        -- Don't ID projectiles, because client may not see them.
+        when (not (bproj b) && ourSide) $
           -- CSha is IDed for each actor of each faction, which is OK,
           -- even though it may introduce a slight lag.
           -- AI clients being sent this is a bigger waste anyway.
@@ -401,12 +402,14 @@
   let diffBonusCoeff = difficultyCoeff sdifficultySer
       hasUIorEscapes Faction{gplayer} =
         fhasUI gplayer || nU == 0 && fcanEscape gplayer
-      boostFact fact = not bproj
-                       && if diffBonusCoeff > 0
-                          then hasUIorEscapes fact
-                          else any hasUIorEscapes
-                               $ filter (`isAtWar` bfid) $ EM.elems factionD
-      diffHP | boostFact factMine = hp * 2 ^ abs diffBonusCoeff
+      boostFact = not bproj
+                  && if diffBonusCoeff > 0
+                     then hasUIorEscapes factMine
+                          || any hasUIorEscapes
+                                 (filter (`isAllied` bfid) $ EM.elems factionD)
+                     else any hasUIorEscapes
+                              (filter (`isAtWar` bfid) $ EM.elems factionD)
+      diffHP | boostFact = hp * 2 ^ abs diffBonusCoeff
              | otherwise = hp
       bonusHP = fromIntegral $ (diffHP - hp) `divUp` oneM
       healthOrgans = [(Just bonusHP, ("bonus HP", COrgan)) | bonusHP /= 0]
@@ -433,9 +436,10 @@
                   Just ItemDisco{itemAE=
                   Just ItemAspectEffect{jeffects=_:_}}}, _)) ->
         return ()  -- discover by use
-      Just (iid, _) -> do
+      Just (iid, (ItemFull{itemBase=itemBase2}, _)) -> do
         seed <- getsServer $ (EM.! iid) . sitemSeedD
-        execUpdAtomic $ UpdDiscoverSeed container iid seed
+        Level{ldepth} <- getLevel $ jlid itemBase2
+        execUpdAtomic $ UpdDiscoverSeed container iid seed ldepth
   return $ Just aid
 
 -- Server has to pick a random weapon or it could leak item discovery
diff --git a/Game/LambdaHack/Server/HandleEffectServer.hs b/Game/LambdaHack/Server/HandleEffectServer.hs
--- a/Game/LambdaHack/Server/HandleEffectServer.hs
+++ b/Game/LambdaHack/Server/HandleEffectServer.hs
@@ -168,7 +168,9 @@
   case EM.lookup (jkindIx item) discoKind of
     Just itemKindId -> do
       seed <- getsServer $ (EM.! iid) . sitemSeedD
-      execUpdAtomic $ UpdDiscover c iid itemKindId seed
+      Level{ldepth} <- getLevel $ jlid item
+      -- TODO: we leak first depth the item was created at on the server
+      execUpdAtomic $ UpdDiscover c iid itemKindId seed ldepth
       itemEffect source target iid recharged periodic effs
     _ -> assert `failure` (source, target, iid, item)
 
@@ -212,7 +214,7 @@
     IK.RefillCalm p -> effectRefillCalm False execSfx p source target
     IK.OverfillCalm p -> effectRefillCalm True execSfx p source target
     IK.Dominate -> effectDominate recursiveCall source target
-    IK.Impress -> effectImpress execSfx source target
+    IK.Impress -> effectImpress source target
     IK.CallFriend p -> effectCallFriend p source target
     IK.Summon freqs p -> effectSummon freqs p source target
     IK.Ascend p -> effectAscend recursiveCall execSfx p source target
@@ -288,8 +290,7 @@
       block = braced tb
   return $! itemBonus - if block then 50 else 0
 
-halveCalm :: (MonadAtomic m, MonadServer m)
-          => ActorId -> m ()
+halveCalm :: (MonadAtomic m, MonadServer m) => ActorId -> m ()
 halveCalm target = do
   tb <- getsState $ getActorBody target
   activeItems <- activeItemsServer target
@@ -301,7 +302,7 @@
   -- HP loss decreases Calm by at least minusTwoM, to overcome Calm regen,
   -- when far from shooting foe and to avoid "hears something",
   -- which is emitted for decrease @minusM@.
-  execUpdAtomic $ UpdRefillCalm target deltaCalm
+  udpateCalm target deltaCalm
 
 -- ** Burn
 
@@ -409,7 +410,7 @@
     then return False
     else do
       execSfx
-      execUpdAtomic $ UpdRefillCalm target deltaCalm
+      udpateCalm target deltaCalm
       return True
 
 -- ** Dominate
@@ -431,14 +432,13 @@
 -- ** Impress
 
 effectImpress :: (MonadAtomic m, MonadServer m)
-              => m () -> ActorId -> ActorId -> m Bool
-effectImpress execSfx source target = do
+              => ActorId -> ActorId -> m Bool
+effectImpress source target = do
   sb <- getsState $ getActorBody source
   tb <- getsState $ getActorBody target
   if bfidImpressed tb == bfid sb || bproj tb then
     return False
   else do
-    execSfx
     execUpdAtomic $ UpdFidImpressedActor target (bfidImpressed tb) (bfid sb)
     return True
 
@@ -495,7 +495,7 @@
     return False
   else do
     let deltaCalm = - xM 10
-    unless (bproj tb) $ execUpdAtomic $ UpdRefillCalm target deltaCalm
+    unless (bproj tb) $ udpateCalm target deltaCalm
     let validTile t = not $ Tile.hasFeature cotile TK.NoActor t
     ps <- getsState $ nearbyFreePoints validTile (bpos tb) (blid tb)
     localTime <- getsState $ getLocalTime (blid tb)
@@ -927,7 +927,9 @@
 identifyIid execSfx iid c itemKindId = do
   execSfx
   seed <- getsServer $ (EM.! iid) . sitemSeedD
-  execUpdAtomic $ UpdDiscover c iid itemKindId seed
+  item <- getsState $ getItemBody iid
+  Level{ldepth} <- getLevel $ jlid item
+  execUpdAtomic $ UpdDiscover c iid itemKindId seed ldepth
 
 -- ** SendFlying
 
diff --git a/Game/LambdaHack/Server/HandleRequestServer.hs b/Game/LambdaHack/Server/HandleRequestServer.hs
--- a/Game/LambdaHack/Server/HandleRequestServer.hs
+++ b/Game/LambdaHack/Server/HandleRequestServer.hs
@@ -363,7 +363,9 @@
   else do
     when (fromCStore == CGround) $ do
       seed <- getsServer $ (EM.! iid) . sitemSeedD
-      execUpdAtomic $ UpdDiscoverSeed fromC iid seed
+      item <- getsState $ getItemBody iid
+      Level{ldepth} <- getLevel $ jlid item
+      execUpdAtomic $ UpdDiscoverSeed fromC iid seed ldepth
     upds <- generalMoveItem iid k fromC toC
     mapM_ execUpdAtomic upds
     -- Reset timeout for equipped periodic items.
@@ -439,7 +441,7 @@
       activeItems <- activeItemsServer aid
       actorSk <- actorSkillsServer aid
       localTime <- getsState $ getLocalTime (blid b)
-      let skill = EM.findWithDefault 0 Ability.AbProject actorSk
+      let skill = EM.findWithDefault 0 Ability.AbApply actorSk
           itemFull = itemToF iid kit
           legal = permittedApply " " localTime skill itemFull b activeItems
       case legal of
diff --git a/Game/LambdaHack/Server/LoopServer.hs b/Game/LambdaHack/Server/LoopServer.hs
--- a/Game/LambdaHack/Server/LoopServer.hs
+++ b/Game/LambdaHack/Server/LoopServer.hs
@@ -3,6 +3,7 @@
 -- moves turn by turn.
 module Game.LambdaHack.Server.LoopServer (loopSer) where
 
+import Control.Applicative
 import Control.Arrow ((&&&))
 import Control.Exception.Assert.Sugar
 import Control.Monad
@@ -100,14 +101,23 @@
   -- Run the leader and other actors moves. Eventually advance the time
   -- and repeat.
   let loop = do
+        -- Note that if a faction enters dungeon on a level with no spawners,
+        -- the faction won't cause spawning on its active arena
+        -- as long as it has no leader. This may cause regeneration items
+        -- of its opponents become overpowered and lead to micromanagement
+        -- (make sure to kill all actors of the faction, go to a no-spawn
+        -- level and heal fully with no risk nor cost).
         let factionArena fact =
               case gleader fact of
-               -- Even spawners and horrors need an active arena
-               -- for their leader, or they start clogging stairs.
+               -- Even spawners need an active arena for their leader,
+               -- or they start clogging stairs.
                Just (leader, _) -> do
                   b <- getsState $ getActorBody leader
                   return $ Just $ blid b
-               Nothing -> return Nothing
+               Nothing -> if fleaderMode (gplayer fact) == LeaderNull
+                             || EM.null (gvictims fact)
+                          then return Nothing
+                          else Just <$> getEntryArena fact
         factionD <- getsState sfactionD
         marenas <- mapM factionArena $ EM.elems factionD
         let arenas = ES.toList $ ES.fromList $ catMaybes marenas
@@ -275,15 +285,29 @@
             hasWait _ = False
         maybe (return ()) (setBWait (hasWait cmdS)) aidNew
         -- Advance time once, after the leader switched perhaps many times.
-        -- Sometimes this may result in a double move of the new leader,
-        -- followed by a double pause. Or a fractional variant of that.
-        -- In this setup, reading a scroll of Previous Leader is a free action
-        -- for the old leader, but otherwise his time is undisturbed.
-        -- He is able to move normally in the same turn, immediately
-        -- after the new leader completes his move.
+        -- The following was true before, but now we badly want to avoid double
+        -- moves against the UI player (especially deadly when using stairs),
+        -- so this is no longer true:
+          -- Sometimes this may result in a double move of the new leader,
+          -- followed by a double pause. Or a fractional variant of that.
+          -- In this setup, reading a scroll of Previous Leader is a free action
+          -- for the old leader, but otherwise his time is undisturbed.
+          -- He is able to move normally in the same turn, immediately
+          -- after the new leader completes his move.
+        -- So now we exchange times of the old and new leader.
+        -- This permits an abuse, because a slow tank can be moved fast
+        -- by alternating between it and many fast actors (until all of them
+        -- get slowed down by this and none remain). But at least the sum
+        -- of all times of a faction is conserved. And we avoid double moves
+        -- against the UI player caused by his leader changes. There may still
+        -- happen double moves caused by AI leader changes, but that's rare.
+        -- The flip side is the possibility of multi-moves of the UI player
+        -- as in the case of the tank, but at least the sum of times is OK.
         -- Warning: when the action is performed on the server,
         -- the time of the actor is different than when client prepared that
         -- action, so any client checks involving time should discount this.
+        when (aidIsLeader && Just aid /= aidNew) $
+          maybe (return ()) (swapTime aid) aidNew
         maybe (return ()) advanceTime aidNew
         action
         maybe (return ()) managePerTurn aidNew
diff --git a/Game/LambdaHack/Server/PeriodicServer.hs b/Game/LambdaHack/Server/PeriodicServer.hs
--- a/Game/LambdaHack/Server/PeriodicServer.hs
+++ b/Game/LambdaHack/Server/PeriodicServer.hs
@@ -2,13 +2,14 @@
 -- and related operations.
 module Game.LambdaHack.Server.PeriodicServer
   ( spawnMonster, addAnyActor, dominateFidSfx
-  , advanceTime, managePerTurn, leadLevelSwitch
+  , advanceTime, swapTime, managePerTurn, leadLevelSwitch, udpateCalm
   ) where
 
 import Control.Exception.Assert.Sugar
 import Control.Monad
 import qualified Data.EnumMap.Strict as EM
 import qualified Data.EnumSet as ES
+import Data.Int (Int64)
 import Data.List
 import Data.Maybe
 
@@ -91,7 +92,7 @@
       pers <- getsServer sper
       let allPers = ES.unions $ map (totalVisible . (EM.! lid))
                     $ EM.elems $ EM.delete fid pers  -- expensive :(
-          mobile = any (`elem` freqNames) ["civilian", "horror"]
+          mobile = any (`elem` freqNames) ["mobile", "horror"]
       pos <- case mpos of
         Just pos -> return pos
         Nothing -> do
@@ -110,16 +111,14 @@
              mobile lid Level{ltile, lxsize, lysize} fact s = do
   let inhabitants = actorRegularList (isAtWar fact) lid s
       as = actorList (const True) lid s
-      isLit = Tile.isLit cotile
       distantSo df p _ =
         all (\b -> df $ chessDist (bpos b) p) inhabitants
       middlePos = Point (lxsize `div` 2) (lysize `div` 2)
       distantMiddle d p _ = chessDist p middlePos < d
       condList | mobile =
-        [ \_ t -> not (isLit t) -- no such tiles on some maps
-        , distantSo (<= 10)  -- try to harass enemies
-        , distantSo (>= 5)   -- but leave room for yourself for ranged combat
-        , distantSo (<= 20)  -- but applying pressure is more important
+        [ distantSo (<= 10)  -- try hard to harass enemies
+        , distantSo (<= 15)
+        , distantSo (<= 20)
         ]
                | otherwise =
         [ distantMiddle 5
@@ -135,8 +134,9 @@
               && not (Tile.hasFeature cotile TK.NoActor t)
               && unoccupied as p)
     (condList
-     ++ [ \p _ -> not (p `ES.member` visible)  -- surprise and believability
-        , distantSo (>= 3)  -- otherwise fast actor approach and hit in one turn
+     ++ [ distantSo (> 5)  -- otherwise actors in dark rooms are swarmed
+        , distantSo (> 2)  -- otherwise actors can be hit on entering level
+        , \p _ -> not (p `ES.member` visible)  -- surprise and believability
         ])
 
 dominateFidSfx :: (MonadAtomic m, MonadServer m)
@@ -183,8 +183,10 @@
   execUpdAtomic $ UpdSpotActor target bNew ais
   let discoverSeed (iid, cstore) = do
         seed <- getsServer $ (EM.! iid) . sitemSeedD
+        item <- getsState $ getItemBody iid
+        Level{ldepth} <- getLevel $ jlid item
         let c = CActor target cstore
-        execUpdAtomic $ UpdDiscoverSeed c iid seed
+        execUpdAtomic $ UpdDiscoverSeed c iid seed ldepth
       aic = getCarriedIidCStore tb
   mapM_ discoverSeed aic
   mleaderOld <- getsState $ gleader . (EM.! fid) . sfactionD
@@ -207,6 +209,31 @@
   let t = ticksPerMeter $ bspeed b activeItems
   execUpdAtomic $ UpdAgeActor aid t
 
+-- | Swap the relative move times of two actors (e.g., when switching
+-- a UI leader).
+swapTime :: (MonadAtomic m, MonadServer m) => ActorId -> ActorId -> m ()
+swapTime source target = do
+  sb <- getsState $ getActorBody source
+  tb <- getsState $ getActorBody target
+  slvl <- getsState $ getLocalTime (blid sb)
+  tlvl <- getsState $ getLocalTime (blid tb)
+  let lvlDelta = slvl `timeDeltaToFrom` tlvl
+      bDelta = btime sb `timeDeltaToFrom` btime tb
+      sdelta = timeDeltaSubtract lvlDelta bDelta
+      tdelta = timeDeltaReverse sdelta
+  -- Equivalent, for the assert:
+  let !_A = let sbodyDelta = btime sb `timeDeltaToFrom` slvl
+                tbodyDelta = btime tb `timeDeltaToFrom` tlvl
+                sgoal = slvl `timeShift` tbodyDelta
+                tgoal = tlvl `timeShift` sbodyDelta
+                sdelta' = sgoal `timeDeltaToFrom` btime sb
+                tdelta' = tgoal `timeDeltaToFrom` btime tb
+            in assert (sdelta == sdelta' && tdelta == tdelta'
+                      `blame` ( slvl, tlvl, btime sb, btime tb
+                              , sdelta, sdelta', tdelta, tdelta' )) ()
+  when (sdelta /= Delta timeZero) $ execUpdAtomic $ UpdAgeActor source sdelta
+  when (tdelta /= Delta timeZero) $ execUpdAtomic $ UpdAgeActor target tdelta
+
 -- | Check if the given actor is dominated and update his calm.
 -- We don't update calm once per game turn (even though
 -- it would make fast actors less overpowered),
@@ -222,6 +249,10 @@
     activeItems <- activeItemsServer aid
     fact <- getsState $ (EM.! bfid b) . sfactionD
     dominated <-
+      -- We react one turn after bcalm reaches 0, to let it be
+      -- displayed first, to let the player panic in advance
+      -- and also to avoid the dramatic domination message
+      -- be swamped in other enemy turn messages.
       if bcalm b == 0
          && bfidImpressed b /= bfid b
          && fleaderMode (gplayer fact) /= LeaderNull
@@ -233,13 +264,25 @@
       let clearMark = 0
       unless (newCalmDelta <= 0) $
         -- Update delta for the current player turn.
-        execUpdAtomic $ UpdRefillCalm aid newCalmDelta
+        udpateCalm aid newCalmDelta
       unless (bcalmDelta b == ResDelta 0 0) $
         -- Clear delta for the next player turn.
         execUpdAtomic $ UpdRefillCalm aid clearMark
       unless (bhpDelta b == ResDelta 0 0) $
         -- Clear delta for the next player turn.
         execUpdAtomic $ UpdRefillHP aid clearMark
+
+udpateCalm :: (MonadAtomic m, MonadServer m) => ActorId -> Int64 -> m ()
+udpateCalm target deltaCalm = do
+  tb <- getsState $ getActorBody target
+  activeItems <- activeItemsServer target
+  let calmMax64 = xM $ sumSlotNoFilter IK.EqpSlotAddMaxCalm activeItems
+  execUpdAtomic $ UpdRefillCalm target deltaCalm
+  when (bcalm tb < calmMax64
+        && bcalm tb + deltaCalm >= calmMax64
+        && bfidImpressed tb /= bfidOriginal tb) $
+    execUpdAtomic $
+      UpdFidImpressedActor target (bfidImpressed tb) (bfidOriginal tb)
 
 leadLevelSwitch :: (MonadAtomic m, MonadServer m) => m ()
 leadLevelSwitch = do
diff --git a/GameDefinition/Content/CaveKind.hs b/GameDefinition/Content/CaveKind.hs
--- a/GameDefinition/Content/CaveKind.hs
+++ b/GameDefinition/Content/CaveKind.hs
@@ -30,15 +30,15 @@
   , cminPlaceSize = DiceXY (2 * d 2 + 2) 4
   , cmaxPlaceSize = DiceXY 15 10
   , cdarkChance   = d 54 + dl 20
-  , cnightChance  = 51
+  , cnightChance  = 51  -- always night
   , cauxConnects  = 1%3
   , cmaxVoid      = 1%6
   , cminStairDist = 30
   , cdoorChance   = 1%2
   , copenChance   = 1%10
   , chidden       = 8
-  , cactorCoeff   = 150  -- the maze requires time to explore
-  , cactorFreq    = [("monster", 40), ("animal", 60)]
+  , cactorCoeff   = 130  -- the maze requires time to explore
+  , cactorFreq    = [("monster", 60), ("animal", 40)]
   , citemNum      = 10 * d 2
   , citemFreq     = [("useful", 50), ("treasure", 50)]
   , cplaceFreq    = [("rogue", 100)]
@@ -57,12 +57,14 @@
   , cfreq         = [("campaign random", 50), ("caveArena", 1)]
   , cgrid         = DiceXY (2 * d 2) (2 * d 2)
   , cminPlaceSize = DiceXY (2 * d 2 + 3) 4
-  , cdarkChance   = d 60 + dl 60
-  , cnightChance  = d 60 + dl 60 -- trails provide enough light for fun stealth
+  , cdarkChance   = d 100 - dl 50
+  -- Trails provide enough light for fun stealth. Light is not too deadly,
+  -- because not many obstructions, so foes visible from far away.
+  , cnightChance  = d 50 + dl 50
   , cmaxVoid      = 1%4
   , chidden       = 1000
   , cactorCoeff   = 100
-  , cactorFreq    = [("monster", 70), ("animal", 30)]
+  , cactorFreq    = [("monster", 30), ("animal", 70)]
   , citemNum      = 9 * d 2  -- few rooms
   , citemFreq     = [("useful", 20), ("treasure", 30), ("any scroll", 50)]
   , cpassable     = True
@@ -78,12 +80,12 @@
   , cminPlaceSize = DiceXY 10 10
   , cmaxPlaceSize = DiceXY 24 12
   , cdarkChance   = d 80 + dl 80
-  , cnightChance  = 0
+  , cnightChance  = 0  -- always day
   , cauxConnects  = 1
   , cmaxVoid      = 1%2
   , cminStairDist = 50
   , chidden       = 1000
-  , cactorCoeff   = 20
+  , cactorCoeff   = 3
   , cactorFreq    = [("monster", 2), ("animal", 8), ("immobile vents", 90)]
       -- The geysers on lvl 3 act like HP resets. They are needed to avoid
       -- cascading failure, if the particular starting conditions were
@@ -104,11 +106,14 @@
   , cgrid         = DiceXY (2 + d 2) 3
   , cminPlaceSize = DiceXY 12 5
   , cmaxPlaceSize = DiceXY 24 12
-  , cnightChance  = d 80 + dl 80
+  , cdarkChance   = 0  -- few rooms, so all lit
+  -- Light is deadly, because nowhere to hide and pillars enable spawning
+  -- very close to heroes, so deep down light should be rare.
+  , cnightChance  = dl 300
   , cauxConnects  = 0
   , cmaxVoid      = 0
   , chidden       = 1000
-  , cactorCoeff   = 200  -- the maze requires time to explore
+  , cactorCoeff   = 160  -- the maze requires time to explore
   , cactorFreq    = [("monster", 80), ("animal", 20)]
   , citemNum      = 12 * d 2  -- an incentive to explore the labyrinth
   , cpassable     = True
@@ -134,7 +139,7 @@
   , cminPlaceSize = DiceXY 4 4
   , cmaxPlaceSize = DiceXY 9 7
   , cdarkChance   = 0
-  , cnightChance  = 100
+  , cnightChance  = 51  -- always night
   , cmaxVoid      = 0
   , cdoorChance   = 2%10
   , copenChance   = 9%10
@@ -177,7 +182,7 @@
   , cminPlaceSize = DiceXY 3 3
   , cmaxPlaceSize = DiceXY 5 5
   , cdarkChance   = 0
-  , cnightChance  = 100
+  , cnightChance  = 51  -- always night
   , cauxConnects  = 1
   , cdoorChance   = 1%10
   , copenChance   = 9%10
diff --git a/GameDefinition/Content/ItemKind.hs b/GameDefinition/Content/ItemKind.hs
--- a/GameDefinition/Content/ItemKind.hs
+++ b/GameDefinition/Content/ItemKind.hs
@@ -150,7 +150,7 @@
   , ifreq    = [("useful", 100)]
   , iflavour = zipPlain [White]
   , icount   = 1
-  , irarity  = [(1, 2), (10, 1)]
+  , irarity  = [(1, 2)]
   , iverbHit = "prod"
   , iweight  = 10000
   , iaspects = [Timeout $ d 2 + 2 - dl 2 |*| 10]
@@ -180,7 +180,7 @@
   , ifreq    = [("useful", 100)]
   , iflavour = zipPlain [Red]
   , icount   = 1
-  , irarity  = [(10, 1)]
+  , irarity  = [(1, 1)]
   , iverbHit = "gaze at"
   , iweight  = 100
   , iaspects = [ AddSight 10, AddMaxCalm 60, AddLight 2
@@ -199,8 +199,8 @@
   , iname    = "wooden torch"
   , ifreq    = [("useful", 100), ("light source", 100)]
   , iflavour = zipPlain [Brown]
-  , icount   = 1 + d 3
-  , irarity  = [(1, 8)]
+  , icount   = d 2
+  , irarity  = [(1, 10)]
   , iverbHit = "scorch"
   , iweight  = 1200
   , iaspects = [ AddLight 3       -- not only flashes, but also sparks
@@ -216,7 +216,7 @@
   , ifreq    = [("useful", 100), ("light source", 100)]
   , iflavour = zipPlain [BrYellow]
   , icount   = 1
-  , irarity  = [(7, 10)]
+  , irarity  = [(6, 7)]
   , iverbHit = "burn"
   , iweight  = 1000
   , iaspects = [AddLight 3, AddSight (-1)]
@@ -232,7 +232,7 @@
   , ifreq    = [("useful", 100), ("light source", 100)]
   , iflavour = zipPlain [BrWhite]
   , icount   = 1
-  , irarity  = [(10, 3)]
+  , irarity  = [(10, 5)]
   , iverbHit = "burn"
   , iweight  = 2400
   , iaspects = [AddLight 4, AddSight (-1)]
@@ -291,7 +291,7 @@
   }
 necklace2 = necklace
   { ifreq    = [("treasure", 100)]  -- just too nasty to call it useful
-  , irarity  = [(10, 1)]
+  , irarity  = [(1, 1)]
   , iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 10) : iaspects necklace
   , ieffects = [ Recharging Impress
                , Recharging (DropItem COrgan "temporary conditions" True)
@@ -366,7 +366,7 @@
   , iverbHit = "knock"
   , iweight  = 15
   , iaspects = []
-  , ieffects = [Explode "blast 2"]
+  , ieffects = [Explode "blast 20"]
   , ifeature = [Precious, Identified]
   , idesc    = "It looks like an ordinary object, but it's in fact a generator of exceptional effects: adding to some of your natural abilities and subtracting from others. You'd profit enormously if you could find a way to multiply such generators."
   , ikit     = []
@@ -408,15 +408,15 @@
   }
 ring7 = ring
   { ifreq    = [("useful", 100), ("ring of opportunity sniper", 1) ]
-  , irarity  = [(10, 1)]
-  , iaspects = [AddSkills $ EM.fromList [(AbProject, 9)]]
+  , irarity  = [(1, 1)]
+  , iaspects = [AddSkills $ EM.fromList [(AbProject, 8)]]
   , ieffects = [ NoEffect "of opportunity sniper"
                , Explode "distortion" ]  -- strong magic
   , ifeature = ifeature ring ++ [EqpSlot (EqpSlotAddSkills AbProject) ""]
   }
 ring8 = ring
   { ifreq    = [("useful", 1), ("ring of opportunity grenadier", 1) ]
-  , irarity  = [(10, 1)]
+  , irarity  = [(1, 1)]
   , iaspects = [AddSkills $ EM.fromList [(AbProject, 11)]]
   , ieffects = [ NoEffect "of opportunity grenadier"
                , Explode "distortion" ]  -- strong magic
@@ -463,22 +463,24 @@
                , OnSmash (Explode "healing mist 2") ]
   }
 potion5 = potion
-  { ieffects = [ OneOf [ Impress, OverfillHP 10, OverfillHP 5, Burn 5 ]
+  { ieffects = [ OneOf [ OverfillHP 10, OverfillHP 5, Burn 5
+                       , toOrganActorTurn "strengthened" (20 + d 5) ]
                , OnSmash (OneOf [ Explode "healing mist"
                                 , Explode "wounding mist"
                                 , Explode "fragrance"
+                                , Explode "smelly droplet"
                                 , Explode "blast 10" ]) ]
   }
 potion6 = potion
   { irarity  = [(3, 3), (10, 6)]
   , ieffects = [ Impress
                , OneOf [ OverfillCalm (-60)
-                       , toOrganActorTurn "fast 20" (20 + d 5)
-                       , OverfillHP 20, OverfillHP 10, Burn 10 ]
+                       , OverfillHP 20, OverfillHP 10, Burn 10
+                       , toOrganActorTurn "fast 20" (20 + d 5) ]
                , OnSmash (OneOf [ Explode "healing mist 2"
                                 , Explode "calming mist"
                                 , Explode "distressing odor"
-                                , Explode "distortion"  -- outlier, OK
+                                , Explode "eye drop"
                                 , Explode "blast 20" ]) ]
   }
 potion7 = potion
@@ -561,18 +563,17 @@
   { irarity  = [(10, 7)]
   , ieffects = [ NoEffect "of eye drops"
                , toOrganActorTurn "far-sighted" (20 + d 5)
-               , OnSmash (Explode "eye drop") ]
+               , OnSmash (Explode "blast 10") ]
   }
 flask8 = flask
   { irarity  = [(10, 3)]
   , ieffects = [ NoEffect "of smelly concoction"
                , toOrganActorTurn "keen-smelling" (20 + d 5)
-               , OnSmash (Explode "smelly droplet") ]
+               , OnSmash (Explode "blast 10") ]
   }
 flask9 = flask
   { ieffects = [ NoEffect "of bait cocktail"
                , toOrganActorTurn "drunk" (5 + d 5)
-               , Impress
                , OnSmash (Summon [("mobile animal", 1)] $ 1 + dl 2)
                , OnSmash (Explode "waste") ]
   }
@@ -721,7 +722,7 @@
   , irarity  = [(5, 9), (10, 9)]
   , iverbHit = "flap"
   , iweight  = 100
-  , iaspects = [ AddHurtMelee $ (d 2 + dl 10) * 3
+  , iaspects = [ AddHurtMelee $ (d 2 + dl 10) |*| 3
                , AddArmorRanged $ d 2 |*| 5 ]
   , ieffects = []
   , ifeature = [ toVelocity 30  -- flaps and flutters
@@ -795,7 +796,7 @@
   , ifreq    = [("useful", 100), ("starting weapon", 100)]
   , iflavour = zipPlain [BrCyan]
   , icount   = 1
-  , irarity  = [(1, 20), (10, 1)]
+  , irarity  = [(1, 20)]
   , iverbHit = "stab"
   , iweight  = 1000
   , iaspects = [ AddHurtMelee $ d 3 + dl 3 |*| 3
@@ -950,7 +951,9 @@
   , irarity  = []
   , iverbHit = "tap"
   , iweight  = 50
-  , iaspects = [AddLight 1, AddSpeed (-1)]  -- reflects strongly, distracts
+  , iaspects = [AddLight 1, AddSpeed (-1)]
+                 -- reflects strongly, distracts; so it glows in the dark,
+                 -- is visible on dark floor, but not too tempting to wear
   , ieffects = []
   , ifeature = [Precious]
   , idesc    = "Useless, and still worth around 100 gold each. Would gems of thought and pearls of artful design be valued that much in our age of Science and Progress!"
@@ -971,7 +974,7 @@
   , irarity  = [(1, 40), (10, 40)]
   , iaspects = []
   , ieffects = [NoEffect "of youth", OverfillCalm 5, OverfillHP 15]
-  , ifeature = [Identified, Precious]  -- TODO: only for humans
+  , ifeature = [Identified, Applicable, Precious]  -- TODO: only heal humans
   , idesc    = "A crystal vial of amber liquid, supposedly granting eternal youth and fetching 100 gold per piece. The main effect seems to be mild euphoria, but it admittedly heals minor ailments rather well."
   }
 currency = ItemKind
diff --git a/GameDefinition/Content/ItemKindActor.hs b/GameDefinition/Content/ItemKindActor.hs
--- a/GameDefinition/Content/ItemKindActor.hs
+++ b/GameDefinition/Content/ItemKindActor.hs
@@ -20,7 +20,7 @@
 warrior = ItemKind
   { isymbol  = '@'
   , iname    = "warrior"  -- modified if in hero faction
-  , ifreq    = [("hero", 100), ("civilian", 100)]
+  , ifreq    = [("hero", 100), ("civilian", 100), ("mobile", 1)]
   , iflavour = zipPlain [BrBlack]  -- modified if in hero faction
   , icount   = 1
   , irarity  = [(1, 5)]
@@ -46,12 +46,12 @@
 
 soldier = warrior
   { iname    = "soldier"
-  , ifreq    = [("soldier", 100)]
+  , ifreq    = [("soldier", 100), ("mobile", 1)]
   , ikit     = ikit warrior ++ [("starting weapon", CEqp)]
   }
 sniper = warrior
   { iname    = "sniper"
-  , ifreq    = [("sniper", 100)]
+  , ifreq    = [("sniper", 100), ("mobile", 1)]
   , ikit     = ikit warrior
                ++ [ ("ring of opportunity sniper", CEqp)
                   , ("any arrow", CInv), ("any arrow", CInv)
@@ -62,7 +62,7 @@
 
 civilian = warrior
   { iname    = "clerk"
-  , ifreq    = [("civilian", 100)] }
+  , ifreq    = [("civilian", 100), ("mobile", 1)] }
 civilian2 = civilian
   { iname    = "hairdresser" }
 civilian3 = civilian
@@ -118,7 +118,7 @@
   , iverbHit = "thud"
   , iweight  = 80000
   , iaspects = [ AddMaxHP 30, AddMaxCalm 30, AddSpeed 18
-               , AddSkills $ EM.fromList [(AbProject, -1), (AbApply, -1)] ]
+               , AddSkills $ EM.fromList [(AbProject, -1)] ]
   , ieffects = []
   , ifeature = [Durable, Identified]
   , idesc    = "No mouth, yet it devours everything around, constantly sniffing itself inward; pure movement structure, no constant point to focus one's maddened gaze on."
@@ -149,13 +149,13 @@
 torsor = ItemKind
   { isymbol  = 'T'
   , iname    = "The Forgetful Torsor"
-  , ifreq    = [("monster", 100)]
+  , ifreq    = [("monster", 100), ("mobile", 1)]
   , iflavour = zipFancy [BrCyan]
   , icount   = 1
   , irarity  = [(9, 0), (10, 1000)]  -- unique
   , iverbHit = "thud"
   , iweight  = 80000
-  , iaspects = [ Unique, AddMaxHP 200, AddMaxCalm 100, AddSpeed 10
+  , iaspects = [ Unique, AddMaxHP 300, AddMaxCalm 100, AddSpeed 10
                , AddSkills $ EM.fromList
                    [(AbProject, 2), (AbApply, 1), (AbTrigger, -1)] ]
                    -- can't switch levels, a miniboss
@@ -292,7 +292,7 @@
   , irarity  = [(7, 0), (10, 10)]
   , iverbHit = "thud"
   , iweight  = 80000
-  , iaspects = [ AddMaxHP 40, AddMaxCalm 60, AddSpeed 16 ]
+  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 16 ]
   , ieffects = []
   , ifeature = [Durable, Identified]
   , idesc    = ""
@@ -326,7 +326,7 @@
   , irarity  = [(6, 1), (10, 9)]
   , iverbHit = "thud"
   , iweight  = 80000
-  , iaspects = [ AddMaxHP 40, AddMaxCalm 60, AddSpeed 17 ]
+  , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 15 ]
   , ieffects = []
   , ifeature = [Durable, Identified]
   , idesc    = ""
@@ -338,13 +338,13 @@
 rhinoceros = ItemKind
   { isymbol  = 'R'
   , iname    = "The Maddened Rhinoceros"
-  , ifreq    = [("animal", 100)]
+  , ifreq    = [("animal", 100), ("mobile", 1)]
   , iflavour = zipPlain [Brown]
   , icount   = 1
   , irarity  = [(2, 0), (3, 1000000), (4, 0)]  -- unique
   , iverbHit = "thud"
   , iweight  = 80000
-  , iaspects = [ Unique, AddMaxHP 70, AddMaxCalm 60, AddSpeed 25
+  , iaspects = [ Unique, AddMaxHP 90, AddMaxCalm 60, AddSpeed 25
                , AddSkills $ EM.singleton AbTrigger (-1) ]
                    -- can't switch levels, a miniboss
   , ieffects = []
@@ -395,10 +395,10 @@
 thornbush = ItemKind
   { isymbol  = 't'
   , iname    = "thornbush"
-  , ifreq    = [("animal", 100)]
+  , ifreq    = [("animal", 50), ("immobile vents", 100)]
   , iflavour = zipPlain [Brown]
   , icount   = 1
-  , irarity  = [(1, 3), (10, 1)]
+  , irarity  = [(1, 3)]
   , iverbHit = "thud"
   , iweight  = 80000
   , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20
@@ -411,13 +411,13 @@
 geyserBoiling = ItemKind
   { isymbol  = 'g'
   , iname    = "geyser"
-  , ifreq    = [("animal", 50), ("immobile vents", 100)]
+  , ifreq    = [("animal", 50), ("immobile vents", 50)]
   , iflavour = zipPlain [Blue]
   , icount   = 1
-  , irarity  = [(5, 2), (10, 1)]
+  , irarity  = [(5, 2)]
   , iverbHit = "thud"
   , iweight  = 80000
-  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 5
+  , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 10
                , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..])
                , AddArmorMelee 80, AddArmorRanged 80 ]
   , ieffects = []
@@ -431,7 +431,7 @@
   , ifreq    = [("animal", 50), ("immobile vents", 100)]
   , iflavour = zipPlain [Cyan]
   , icount   = 1
-  , irarity  = [(5, 2), (10, 1)]
+  , irarity  = [(5, 2)]
   , iverbHit = "thud"
   , iweight  = 80000
   , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddLight 3
@@ -447,13 +447,13 @@
   , ifreq    = [("animal", 50), ("immobile vents", 300)]
   , iflavour = zipPlain [BrYellow]  -- exception, animal with bright color
   , icount   = 1
-  , irarity  = [(5, 4), (10, 2)]
+  , irarity  = [(5, 2)]
   , iverbHit = "thud"
   , iweight  = 80000
   , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddLight 3
                , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ]
   , ieffects = []
-  , ifeature = [Durable, Identified]
+  , ifeature = [Durable, Identified]  -- TODO: only heal humans
   , idesc    = ""
   , ikit     = [("sulfur vent", COrgan), ("sulfur fissure", COrgan)]
   }
diff --git a/GameDefinition/Content/ItemKindBlast.hs b/GameDefinition/Content/ItemKindBlast.hs
--- a/GameDefinition/Content/ItemKindBlast.hs
+++ b/GameDefinition/Content/ItemKindBlast.hs
@@ -47,7 +47,7 @@
   , iverbHit = "tear apart"
   , iweight  = 1
   , iaspects = [AddLight $ intToDice n]
-  , ieffects = [Impress, RefillHP (- n `div` 2)]
+  , ieffects = [RefillHP (- n `div` 2)]
                ++ [PushActor (ThrowMod (100 * (n `div` 5)) 50)]
                ++ [DropItem COrgan "temporary conditions" True | n >= 10]
   , ifeature = [Fragile, toLinger 20, Identified]
@@ -68,8 +68,7 @@
   , iverbHit = "crack"
   , iweight  = 1
   , iaspects = [AddLight $ intToDice $ n `div` 2]
-  , ieffects = [Impress]
-               ++ [ RefillCalm (-1) | n >= 5 ]
+  , ieffects = [ RefillCalm (-1) | n >= 5 ]
                ++ [ DropBestWeapon | n >= 5]
                ++ [ OnSmash (Explode $ toGroupName
                              $ "firecracker" <+> tshow (n - 1))
@@ -212,7 +211,7 @@
   , iverbHit = "engulf"
   , iweight  = 1
   , iaspects = []
-  , ieffects = [Impress, Teleport $ 15 + d 10]
+  , ieffects = [Teleport $ 15 + d 10]
   , ifeature = [ toVelocity 7  -- the slowest that gets anywhere (1 step only)
                , Fragile, Identified ]
   , idesc    = ""
@@ -482,7 +481,7 @@
   , iverbHit = "inebriate"
   , iweight  = 1
   , iaspects = []
-  , ieffects = [Impress, toOrganActorTurn "drunk" (3 + d 3)]
+  , ieffects = [toOrganActorTurn "drunk" (3 + d 3)]
   , ifeature = [ toVelocity 13  -- the slowest that travels at least 2 steps
                , Fragile, Identified ]
   , idesc    = ""
diff --git a/GameDefinition/Content/ItemKindOrgan.hs b/GameDefinition/Content/ItemKindOrgan.hs
--- a/GameDefinition/Content/ItemKindOrgan.hs
+++ b/GameDefinition/Content/ItemKindOrgan.hs
@@ -409,16 +409,14 @@
   , ifreq    = [("arsenic vent", 100)]
   , iflavour = zipPlain [Cyan]
   , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5]
-  , ieffects = [ Recharging (Explode "weakness mist")
-               , Recharging (RefillHP (-1)) ]
+  , ieffects = [Recharging (Explode "weakness mist")]
   }
 sulfurVent = boilingVent
   { iname    = "vent"
   , ifreq    = [("sulfur vent", 100)]
   , iflavour = zipPlain [BrYellow]
   , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5]
-  , ieffects = [ Recharging (Explode "strength mist")
-               , Recharging (RefillHP (-1)) ]
+  , ieffects = [Recharging (Explode "strength mist")]
   }
 bonusHP = armoredSkin
   { iname    = "bonus HP"
diff --git a/GameDefinition/Content/ModeKind.hs b/GameDefinition/Content/ModeKind.hs
--- a/GameDefinition/Content/ModeKind.hs
+++ b/GameDefinition/Content/ModeKind.hs
@@ -263,8 +263,12 @@
                      "Animal Magnificent Specimen Variety")
                   , ("Monster Tourist Office",
                      "Animal Exquisite Herds and Packs") ]
-  , rosterAlly = [( "Animal Magnificent Specimen Variety"
-                  , "Animal Exquisite Herds and Packs" )] }
+  , rosterAlly = [ ( "Animal Magnificent Specimen Variety"
+                   , "Animal Exquisite Herds and Packs" )
+                 , ( "Animal Magnificent Specimen Variety"
+                   , "Hunam Convict Pack" )
+                 , ( "Hunam Convict Pack"
+                   , "Animal Exquisite Herds and Packs" ) ] }
 
 rosterSafariSurvival = rosterSafari
   { rosterList = [ playerMonsterTourist
@@ -309,13 +313,10 @@
                  , ("Green", "Monster Hive")
                  , ("Green", "Leaderless Monster Hive") ] }
 
-rosterDefense = Roster
+rosterDefense = rosterCampaign
   { rosterList = [ playerAntiHero
                  , playerAntiMonster
-                 , playerAnimal ]
-  , rosterEnemy = [ ("Adventurer Party", "Monster Hive")
-                  , ("Adventurer Party", "Animal Kingdom") ]
-  , rosterAlly = [("Monster Hive", "Animal Kingdom")] }
+                 , playerAnimal ] }
 
 rosterBoardgame = Roster
   { rosterList = [ playerHero { fname = "Blue"
diff --git a/GameDefinition/PLAYING.md b/GameDefinition/PLAYING.md
--- a/GameDefinition/PLAYING.md
+++ b/GameDefinition/PLAYING.md
@@ -95,14 +95,14 @@
                  /|\            /|\            /|\
                 1 2 3          j k l          b j n
 
-In aiming mode the same keys (or the middle and right mouse buttons)
-move the crosshair (the white box). In normal mode, `SHIFT` (or `CTRL`)
-and a movement key make the current party leader run in the indicated
-direction, until anything of interest is spotted. The `5` keypad key
-and the `i` and `.` keys consume a turn and make you brace for combat,
-which reduces any damage taken for a turn and makes it impossible
-for foes to displace you. You displace enemies or friends by bumping
-into them with `SHIFT` (or `CTRL`).
+In aiming mode (KEYPAD_* or \) the same keys (or the middle and right
+mouse buttons) move the crosshair (the white box). In normal mode,
+`SHIFT` (or `CTRL`) and a movement key make the current party leader
+run in the indicated direction, until anything of interest is spotted.
+The `5` keypad key and the `i` and `.` keys consume a turn and make you
+brace for combat, which reduces any damage taken for a turn and makes it
+impossible for foes to displace you. You displace enemies or friends
+by bumping into them with `SHIFT` (or `CTRL`).
 
 Melee, searching for secret doors, looting and opening closed doors
 can be done by bumping into a monster, a wall and a door, respectively.
@@ -123,7 +123,7 @@
         >               descend a level
         c               close door
         E               manage equipment of the leader
-        g and ,         get items
+        g or ,          get items
         a               apply consumable
         f               fling projectile
         +               swerve the aiming line
@@ -141,8 +141,8 @@
 using the aiming and targeting commands listed below.
 
         keys            command
-        KEYPAD_* and \  aim at an enemy
-        KEYPAD_/ and |  cycle aiming styles
+        KEYPAD_* or \   aim at an enemy
+        KEYPAD_/ or |   cycle aiming styles
         +               swerve the aiming line
         -               unswerve the aiming line
         CTRL-?          set crosshair to the closest unknown spot
@@ -150,7 +150,7 @@
         CTRL-{          set crosshair to the closest stairs up
         CTRL-}          set crosshair to the closest stairs down
         BACKSPACE       reset target/crosshair
-        RET and INSERT  accept target/choice
+        RET or INSERT   accept target/choice
 
 For ranged attacks, setting the crosshair or individual targets
 beforehand is not mandatory, because the crosshair is set automatically
diff --git a/LambdaHack.cabal b/LambdaHack.cabal
--- a/LambdaHack.cabal
+++ b/LambdaHack.cabal
@@ -5,7 +5,7 @@
 -- PVP summary: +-+------- breaking API changes
 --              | | +----- non-breaking API additions
 --              | | |   +--- code changes with no API change
-version:        0.4.101.0
+version:        0.4.101.1
 synopsis:       A game engine library for roguelike dungeon crawlers
 description:   LambdaHack is a game engine library for roguelike games
                of arbitrary theme, size and complexity,
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -243,27 +243,3 @@
 	cp README.md /tmp/LambdaHackTheGame
 	cp /home/mikolaj/.wine/drive_c/users/mikolaj/gtk/bin/zlib1.dll /tmp/LambdaHackTheGame
 	wine Z:/home/mikolaj/.local/share/wineprefixes/7zip/drive_c/Program\ Files/7-Zip/7z.exe a -ssc -sfx Z:/tmp/LambdaHack_x_windows-i386.exe Z:/tmp/LambdaHackTheGame
-
-
-# The rest of the makefile is unmaintained at the moment.
-
-default : dist/setup-config
-	runghc Setup build
-
-dist/setup-config : LambdaHack.cabal
-	runghc Setup configure -fvty --user
-
-vty :
-	runghc Setup configure -fvty --user
-
-gtk :
-	runghc Setup configure --user
-
-curses :
-	runghc Setup configure -fcurses --user
-
-clean :
-	runghc Setup clean
-
-ghci :
-	ghci -XCPP -idist/build/autogen:.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -72,11 +72,11 @@
 
 If you use the numeric keypad, use the NumLock key on your keyboard
 to toggle the game keyboard mode. With NumLock off, you walk with the numeric
-keys and run with Shift (or Control) and the keys. This mode is probably
+keys and run with SHIFT (or CONTROL) and the keys. This mode is probably
 the best if you use mouse for running. When you turn NumLock on,
 the reversed key setup enforces good playing habits by setting as the default
 the run command (which automatically stops at threats, keeping you safe)
-and requiring Shift for the error-prone step by step walking.
+and requiring SHIFT (or CONTROL) for the error-prone step by step walking.
 
 If you don't have the numeric keypad, you can use laptop keys (uk8o79jl)
 or you can enable the Vi keys (aka roguelike keys) in the config file.
