Files
loop/src/Dodge/Update/Input/InGame.hs
T
2024-11-26 22:55:55 +00:00

587 lines
22 KiB
Haskell

{-# LANGUAGE LambdaCase #-}
module Dodge.Update.Input.InGame (
updateUseInputInGame,
updateMouseInGame,
) where
import Data.Monoid
import NewInt
import Control.Applicative
import Control.Monad
import Data.Foldable
import qualified Data.IntMap.Strict as IM
import qualified Data.IntSet as IS
import Data.List (sort)
import qualified Data.Map.Strict as M
import Data.Maybe
import Dodge.Button.Event
import Dodge.Camera
import Dodge.Creature.Action
import Dodge.Data.Combine
import Dodge.Data.Universe
import Dodge.DisplayInventory
import Dodge.Event.Test
import Dodge.Inventory
import Dodge.Inventory.Add
import Dodge.ListDisplayParams
import Dodge.Menu
import Dodge.Save
import Dodge.SelectionSections
import Dodge.SoundLogic
import Dodge.Terminal
import Dodge.Update.Input.Text
import Dodge.WorldPos
import Geometry
import LensHelp
import SDL
updateUseInputInGame :: Universe -> Universe
updateUseInputInGame u = updateFunctionKeys $ case u ^. uvWorld . hud . hudElement of
DisplayCarte -> over uvWorld updatePressedButtonsCarte u
DisplayInventory{_subInventory = si, _diSelection = disel} -> case si of
DisplayTerminal tmid -> updateKeysInTerminal tmid u
CombineInventory{_ciSections = sss, _ciSelection = msel@(Just (-1,_,_))} ->
u
& uvWorld . hud . hudElement . subInventory
%~ docombineregexinput sss msel
& uvWorld . worldEventFlags . at CombineInventoryChange ?~ ()
_ | disel ^? _Just . _1 == Just (-1) ->
u & uvWorld . hud . hudElement
%~ dodisplayregexinput diInvFilter diInvFilter (-1)
& uvWorld . worldEventFlags . at InventoryChange ?~ ()
& uvWorld %~ setInvPosFromSS
_ | disel ^? _Just . _1 == Just 2 ->
u & uvWorld . hud . hudElement
%~ dodisplayregexinput diCloseFilter diCloseFilter 2
& uvWorld . worldEventFlags . at InventoryChange ?~ ()
& uvWorld %~ setInvPosFromSS
_ -> M.foldlWithKey' updateKeyInGame u pkeys
where
pkeys = u ^. uvWorld . input . pressedKeys
dodisplayregexinput filterprism filterlens x di = fromMaybe di $ do
sss <- di ^? diSections
msel <- di ^? diSelection
filts <- di ^? filterprism
let (sss', msel', filts') = doRegexInput (u ^. uvWorld . input) x sss msel filts
return $
di & diSections .~ sss'
& diSelection .~ msel'
& filterlens .~ filts'
docombineregexinput sss msel ci = fromMaybe ci $ do
filts <- ci ^? ciFilter
let (sss', msel', filts') = doRegexInput (u ^. uvWorld . input) (-1) sss msel filts
return $
ci & ciSections .~ sss'
& ciSelection .~ msel'
& ciFilter .~ filts'
updateMouseInGame :: Configuration -> World -> World
updateMouseInGame cfig w = case w ^? input . mouseButtons . ix ButtonLeft of
Just 0 -> updateMouseClickInGame cfig w
Just _ -> updateMouseHeldInGame cfig w
Nothing -> case w ^? input . mouseButtonsReleased . ix ButtonLeft of
Just 0 -> updateMouseReleaseInGame w
_ -> w
updateMouseHeldInGame :: Configuration -> World -> World
updateMouseHeldInGame cfig w = case w ^. input . mouseContext of
OverInvDragSelect sstart _ -> fromMaybe w $ do
sss <- w ^? hud . hudElement . diSections
let msel = inverseSelNumPos cfig invDP sss (w ^. input . mousePos)
guard $ Just (fst sstart) == fmap fst msel || isNothing msel
return $ w & input . mouseContext . mcoSelEnd .~ fmap snd msel
OverInvDrag k mmouseover ab bn -> doDrag 30 k mmouseover ab bn w
_ -> w
doDrag :: Int
-> Int
-> Maybe (Int, Int)
-> Maybe (Int, Int)
-> Maybe (Int, Int)
-> World
-> World
doDrag 0 _ _ _ _ w = w
doDrag n k mmouseover ab bn w = fromMaybe w $ do
ss <- w ^? hud . hudElement . diSections . ix k . ssItems
x <- mmouseover
is <- w ^? hud . hudElement . diSelection . _Just . _3
return $ if concurrentIS is
then shiftInvItems n k x ab bn is ss w
else collectInvItems k is w
tryDropSelected :: Maybe (Int,Int) -> World -> Maybe World
tryDropSelected mpos w = do
guard $ maybe True (\(i,_) -> i == 3) mpos
cr <- w ^? cWorld . lWorld . creatures . ix 0
(0, _, xs) <- w ^? hud . hudElement . diSelection . _Just
return . foldl' (flip $ dropItem cr) w . IS.toDescList $ xs
tryPickupSelected :: Int -> Maybe (Int,Int) -> World -> Maybe World
tryPickupSelected k mpos w = do
guard $ k == 3
guard $ maybe True (\(i,_) -> i == 0 || i == 1) mpos
cr <- w ^? cWorld . lWorld . creatures . ix 0
let nfreeslots = crNumFreeSlots cr
xs <- w ^? hud . hudElement . diSelection . _Just . _3
let itmstopickup = mapMaybe g $ IS.toList xs
let slotsneeded = alaf Sum foldMap (_itInvSize . _flIt) itmstopickup
guard $ nfreeslots >= slotsneeded
return $ case mpos of
Just (0,j) -> foldr (pickUpItemAt j 0) w itmstopickup
& hud . hudElement . diSelection ?~ (0,j
, IS.fromDistinctAscList [j..j+IS.size xs-1])
_ -> foldl' (flip $ pickUpItem 0) w itmstopickup
& hud . hudElement . diSelection . _Just . _3 %~ const mempty
where
g i = do
NInt j <- w ^? hud . closeItems . ix i
w ^? cWorld . lWorld . floorItems . unNIntMap . ix j
updateMouseReleaseInGame :: World -> World
updateMouseReleaseInGame w = case w ^. input . mouseContext of
OverInvDrag k mpos _ _ ->
input . mouseContext .~ MouseInGame $
fromMaybe w $ tryDropSelected mpos w <|> tryPickupSelected k mpos w
OverInvDragSelect ssel mesel | ScancodeLShift `M.member` (w ^. input . pressedKeys)
-> w & input . mouseContext .~ MouseInGame
& hud . hudElement . diSelection . _Just . _3 %~ getuniques
(maybe mempty (h ssel)
(guard (ssel ^? _1 == w ^? hud . hudElement . diSelection . _Just . _1)
>> mesel ^? _Just))
OverInvDragSelect _ Nothing ->
w & input . mouseContext .~ MouseInGame
& hud . hudElement . diSelection . _Just . _3 %~ const mempty
OverInvDragSelect ssel (Just esel) ->
w & input . mouseContext .~ MouseInGame
& augInvDirectSelect (f (min ssel (fst ssel,esel)) (h ssel esel))
_ -> w
where
getuniques x y = IS.union x y IS.\\ IS.intersection x y
f (x,y) z = (x,y,z)
h (k,i) j = fold $ do
sss <- w ^? hud . hudElement . diSections . ix k . ssItems
let (_, xss) = IM.split (min i j -1) sss
(yss, _) = IM.split (max i j + 1) xss
return . IM.keysSet $ yss
isGroupSelectableSection :: Int -> Bool
isGroupSelectableSection = \case
0 -> True
3 -> True
_ -> False
updateMouseClickInGame :: Configuration -> World -> World
updateMouseClickInGame cfig w = case w ^. input . mouseContext of
MouseInGame -> fromMaybe w $ do
sss <- w ^? hud . hudElement . diSections
ysel <- inverseSelSecYint (posSelSecYint cfig invDP (mpos ^. _y)) sss
guard (isGroupSelectableSection $ fst ysel)
return $
w & input . mouseContext
.~ OverInvDragSelect ysel Nothing
OverInvSelect (-1,_) | selsec == Just (-1) -> w
& hud . hudElement . diSelection %~ endRegex (-1) w
& hud . hudElement . diInvFilter .~ Nothing
OverInvSelect (2,_) | selsec == Just 2 -> w
& hud . hudElement . diSelection %~ endRegex 2 w
& hud . hudElement . diCloseFilter .~ Nothing
OverInvSelect x | ScancodeLShift `M.member` (w ^. input . pressedKeys )
-> fromMaybe w $ do
guard (isGroupSelectableSection $ fst x)
return $ w & input . mouseContext .~ OverInvDragSelect x (Just $ snd x)
OverInvSelect x -> startDrag x cfig w
OverTerminalReturn tmid -> terminalReturnEffect tmid w
OverTerminalEscape ->
w & hud . hudElement . subInventory .~ NoSubInventory
OverCombSelect x ->
w & hud . hudElement . subInventory . ciSelection ?~ f x
& worldEventFlags . at CombineInventoryChange ?~ ()
OverCombFilter ->
w & hud . hudElement . subInventory . ciFilter .~ Nothing
& worldEventFlags . at CombineInventoryChange ?~ ()
& hud . hudElement . subInventory . ciSelection %~ endCombineRegex w
OverCombCombine x ->
w
& tryCombine x
& worldEventFlags . at CombineInventoryChange ?~ ()
& worldEventFlags . at InventoryChange ?~ ()
& maybeExitCombine
OverCombEscape ->
w
& worldEventFlags . at InventoryChange ?~ ()
& hud . hudElement . subInventory .~ NoSubInventory
OverCombFiltInv (i, j) -> fromMaybe w $ do
guard $ i == 0
str <-
fmap (take 5) $
w
^? hud . hudElement . diSections . ix i . ssItems . ix j . siPictures . ix 0
return . (worldEventFlags . at CombineInventoryChange ?~ ()) $
case w ^? hud . hudElement . subInventory . ciFilter . _Just of
Just (_ : xs)
| str == xs ->
w
& hud . hudElement . subInventory . ciFilter .~ Nothing
_ -> w & hud . hudElement . subInventory . ciFilter ?~ ("<" ++ str)
_ -> w
where
mpos = w ^. input . mousePos
f (x,y) = (x,y,mempty)
selsec = w ^? hud . hudElement . diSelection . _Just . _1
endRegex :: Int -> World
-> Maybe (Int,Int,IS.IntSet)
-> Maybe (Int,Int,IS.IntSet)
endRegex i w = fromMaybe id $ do
sss <- w ^? hud . hudElement . diSections
let j = fromMaybe 0 $ do
itms <- sss ^? ix i . ssItems
(k,_) <- IM.lookupMin itms
return k
return $ ssSetCursor (ssLookupDown i j) sss
endCombineRegex ::World
-> Maybe (Int,Int,IS.IntSet)
-> Maybe (Int,Int,IS.IntSet)
endCombineRegex w = fromMaybe id $ do
sss <- w ^? hud . hudElement . subInventory . ciSections
let j = fromMaybe 0 $ do
itms <- sss ^? ix 0 . ssItems
(k,_) <- IM.lookupMin itms
return (k-1)
return $ ssSetCursor (ssLookupDown 0 j) sss
startDrag :: (Int, Int) -> Configuration -> World -> World
startDrag (a, b) cfig w = setcontext
. fromMaybe (augInvDirectSelect (a, b, IS.singleton b) w) $ do
(i, _, xs) <- w ^? hud . hudElement . diSelection . _Just
guard $ i == a && b `IS.member` xs
return w
where
setcontext = input . mouseContext .~ OverInvDrag a (Just (a, b)) above bneath
above = do
sss <- w ^? hud . hudElement . diSections
inverseSelSecYint (yint - 1) sss
bneath = do
sss <- w ^? hud . hudElement . diSections
inverseSelSecYint (yint + 1) sss
yint = posSelSecYint cfig invDP (w ^. input . mousePos . _y)
concurrentIS :: IS.IntSet -> Bool
concurrentIS = go . IS.minView
where
go Nothing = True
go (Just (i, is)) = fromMaybe True $ do
(j, js) <- IS.minView is
return $ i + 1 == j && go (Just (j, js))
collectInvItems :: Int -> IS.IntSet -> World -> World
collectInvItems secid is w = fromMaybe w $ do
guard $ secid == 0
(j, js) <- IS.minView is
return $ h j js w
where
h j js w' = fromMaybe w' $ do
(k, ks) <- IS.minView js
return . h (j + 1) ks $ swapInvItems (\_ _ -> Just (j + 1)) k w'
shiftInvItems ::
Int -> -- recurse limit
Int -> -- section where drag started
(Int,Int) -> -- selection item mouse is over
Maybe (Int,Int) -> -- selection item "above" mouse position (can be same as over)
Maybe (Int,Int) -> -- selection item "below" mouse position (can be same as over)
IS.IntSet ->
IM.IntMap (SelectionItem a) ->
World ->
World
shiftInvItems n k x ab bn xs ss w = setSelWhileDragging . fromMaybe w $ do
let xk = fst x
guard $ xk == k || xk + 1 == k || xk -1 == k
(maxi,_) <- IS.maxView xs
(mini,_) <- IS.minView xs
case True of
_ | x < (k,mini) -> do
guard $ not . null . fst $ IM.split mini ss
guard $ Just (k,mini-1) /= ab
return . doDrag (n-1) k (Just x) ab bn $ shiftInvItemsUp k xs w
_ | x > (k,maxi) -> do
guard $ not . null . snd $ IM.split maxi ss
guard $ Just (k,maxi+1) /= bn
return . doDrag (n-1) k (Just x) ab bn $ shiftInvItemsDown k xs w
_ -> Nothing
setSelWhileDragging :: World -> World
setSelWhileDragging w = fromMaybe w $ do
(i,_,xs) <- w ^? hud . hudElement . diSelection . _Just
(k,j) <- w ^? input . mouseContext . mcoMaybeSelect . _Just
guard $ i == k && j `IS.member` xs
return $ w & hud . hudElement . diSelection . _Just . _2 .~ j
shiftInvItemsUp :: Int -> IS.IntSet -> World -> World
shiftInvItemsUp j is w = IS.foldl' f w is
where
f w' i' = swapItemWith g (j, i') w'
g i' m = fst <$> IM.lookupLT i' m
shiftInvItemsDown :: Int -> IS.IntSet -> World -> World
shiftInvItemsDown j is w = fromMaybe w $ do
let i = IS.findMax is
guard . isJust $
w ^? hud . hudElement . diSections . ix j . ssItems . ix i
return $ IS.foldr f w is
where
f i' w' = swapItemWith g (j, i') w'
g i' m = fst <$> IM.lookupGT i' m
updateFunctionKeys :: Universe -> Universe
updateFunctionKeys u =
M.foldlWithKey'
updateFunctionKey
u
(u ^. uvWorld . input . pressedKeys)
updateFunctionKey :: Universe -> Scancode -> PressType -> Universe
updateFunctionKey uv sc InitialPress = case sc of
ScancodeF1 -> useNormalCamera uv
ScancodeF2 -> pauseAndFloatCam uv
ScancodeF5 -> doQuicksave uv
ScancodeF9 -> doQuickload uv
ScancodeEscape -> pauseGame uv
_ -> uv
updateFunctionKey uv _ _ = uv
updatePressedButtonsCarte :: World -> World
updatePressedButtonsCarte w = updatePressedButtonsCarte' (_mouseButtons (_input w)) w
updatePressedButtonsCarte' :: M.Map MouseButton Int -> World -> World
updatePressedButtonsCarte' pkeys w
| isDown ButtonRight =
w & hud . carteCenter %~ (-.- trans)
| isDown ButtonLeft =
w
& hud . carteRot -~ rot
& hud . carteZoom *~ czoom
| otherwise = w
where
isDown but = but `M.member` pkeys
mbutpos but = theinput ^. heldPos . at but
rot = maybe 0 (angleBetween (_mousePos (_input w))) $ mbutpos SDL.ButtonLeft
czoom = fromMaybe 1 $ do
p <- mbutpos SDL.ButtonLeft
return $ magV (_mousePos theinput) / magV p
theinput = w ^. input
trans = fromMaybe 0 $ do
p <- mbutpos SDL.ButtonRight
return . rotateV (w ^. hud . carteRot) $
1 / (w ^. hud . carteZoom) *.* (_mousePos (_input w) -.- p)
updateKeysInTerminal :: Int -> Universe -> Universe
updateKeysInTerminal tmid u =
u
& doTextInputOverUniverse
(uvWorld . cWorld . lWorld . terminals . ix tmid . tmInput . tiText)
& checkEndStatus
where
checkEndStatus
| u ^. uvWorld . input . pressedKeys . at ScancodeReturn == Just InitialPress =
uvWorld %~ terminalReturnEffect tmid
| otherwise = id
updateKeyInGame :: Universe -> Scancode -> PressType -> Universe
updateKeyInGame uv sc pt = case pt of
InitialPress -> updateInitialPressInGame uv sc
LongPress -> updateLongPressInGame uv sc
_ -> uv
updateInitialPressInGame :: Universe -> Scancode -> Universe
updateInitialPressInGame uv sc = case sc of
ScancodeSpace -> over uvWorld spaceAction uv
ScancodeP -> pauseGame uv
ScancodeF -> over uvWorld youDropItem uv
ScancodeM -> toggleMap uv
-- ScancodeR -> over (uvWorld . cWorld . lWorld . creatures . ix 0) crReloadToggle uv
ScancodeT -> over uvWorld testEvent uv
ScancodeX -> uv & uvWorld %~ toggleTweakInv
ScancodeC -> toggleCombineInv uv
-- the following should be put in a more sensible place
ScancodeSlash -> uv & uvWorld %~ updateEnterRegex
ScancodeBackspace -> uv & uvWorld %~ updateBackspaceRegex
_ -> uv
updateLongPressInGame :: Universe -> Scancode -> Universe
updateLongPressInGame uv sc = case sc of
ScancodeF -> over uvWorld youDropItem uv
ScancodeSpace -> over uvWorld spaceAction uv
_ -> uv
doRegexInput ::
Input ->
Int ->
IM.IntMap (SelectionSection a) ->
Maybe (Int, Int, IS.IntSet) ->
Maybe String ->
(IM.IntMap (SelectionSection a), Maybe (Int, Int, IS.IntSet), Maybe String)
doRegexInput inp i sss msel filts
| backspacetonothing || escapekey = endregex i 0
| endkeys = endregex (i + 1) (j -1)
| otherwise =
( sss
, msel
, filts & doTextInputOver inp _Just
)
where
endregex a b =
--( sss & ix i . ssItems .~ mempty
( sss -- & ix i . ssItems .~ mempty
, msel & ssSetCursor (ssLookupDown a b) sss
, Nothing
)
j = fromMaybe 0 $ do
itms <- sss ^? ix (i + 1) . ssItems
fst <$> IM.lookupMin itms
escapekey = ScancodeEscape `M.lookup` pkeys == Just InitialPress
endkeys =
any
((== Just InitialPress) . (`M.lookup` pkeys))
[ScancodeReturn, ScancodeSlash]
backspacetonothing =
filts == Just ""
&& ScancodeBackspace `M.lookup` pkeys == Just InitialPress
pkeys = inp ^. pressedKeys
updateBackspaceRegex :: World -> World
updateBackspaceRegex w = case di ^? subInventory of
Just NoSubInventory{}
| secfocus (-1) 0 ->
w & hud . hudElement %~ trybackspace (-1) diInvFilter diInvFilter diSelection
& worldEventFlags . at InventoryChange ?~ ()
Just NoSubInventory{}
| secfocus 2 3 ->
w & hud . hudElement %~ trybackspace 2 diCloseFilter diCloseFilter diSelection
& worldEventFlags . at InventoryChange ?~ ()
Just CombineInventory{} ->
w & hud . hudElement . subInventory %~ trybackspace (-1) ciFilter ciFilter ciSelection
& worldEventFlags . at InventoryChange ?~ ()
_ -> w
where
secfocus a b = fromMaybe False $ do
i <- di ^? diSelection . _Just . _1
return $ i == a || i == b
trybackspace x filtget filtset selset he = fromMaybe he $ do
str <- he ^? filtget . _Just
return $ case str of
(_ : _) ->
he & filtset . _Just %~ init
& selset ?~ (x, 0,mempty)
[] -> he & filtset .~ Nothing
di = w ^. hud . hudElement
updateEnterRegex :: World -> World
updateEnterRegex w = case w ^? hud . hudElement . subInventory of
Just NoSubInventory{}
| secfocus [-1,0,1] ->
w & hud . hudElement . diSelection ?~ (-1, 0,mempty)
& hud . hudElement . diInvFilter %~ enterregex
Just NoSubInventory{}
| secfocus [2,3] ->
w & hud . hudElement . diSelection ?~ (2, 0,mempty)
& hud . hudElement . diCloseFilter %~ enterregex
Just CombineInventory{} ->
w & hud . hudElement . subInventory . ciFilter %~ enterregex
& hud . hudElement . subInventory . ciSelection ?~ (-1, 0,mempty)
_ -> w
where
di = w ^. hud . hudElement
secfocus xs = fromMaybe False $ do
i <- di ^? diSelection . _Just . _1
return $ i `elem` xs
enterregex = (<|> Just "")
pauseGame :: Universe -> Universe
pauseGame u = u & uvScreenLayers .~ [pauseMenu u]
spaceAction :: World -> World
spaceAction w = case w ^. hud . hudElement of
DisplayCarte -> w & hud . carteCenter .~ theLoc
DisplayInventory{_subInventory = NoSubInventory{}} -> fromMaybe w $ do
cobj <- selCloseObj w
return $ case cobj of -- case Left <$> selectedCloseItem w of
(Left flit) -> pickUpItem 0 flit w
& worldEventFlags . at InventoryChange ?~ ()
(Right but) -> doButtonEvent (_btEvent but) but w
& worldEventFlags . at InventoryChange ?~ ()
DisplayInventory{_subInventory = DisplayTerminal{}} -> w
& hud . hudElement . subInventory .~ NoSubInventory
& worldEventFlags . at InventoryChange ?~ ()
_ -> w & hud . hudElement . subInventory .~ NoSubInventory
where
theLoc =
doWorldPos
(w ^?! cWorld . lWorld . seenLocations . ix (w ^. cWorld . lWorld . selLocation) . _1)
w
selCloseObj :: World -> Maybe (Either FloorItem Button)
selCloseObj w = selobj <|> firstcitem <|> firstcbut
where
selobj = do
(i,j,_) <- w ^? hud . hudElement . diSelection . _Just
case i of
3 -> do
NInt k <- w ^? hud . closeItems . ix j
fmap Left $ w ^? cWorld . lWorld . floorItems . unNIntMap . ix k
5 -> do
k <- w ^? hud . closeButtons . ix j
fmap Right $ w ^? cWorld . lWorld . buttons . ix k
_ -> Nothing
firstcitem = do
k' <- (w ^? hud . hudElement . diSections . ix 3 . ssItems) >>= (fmap fst . IM.lookupMin)
NInt k <- w ^? hud . closeItems . ix k'
fmap Left $ w ^? cWorld . lWorld . floorItems . unNIntMap . ix k
firstcbut = do
k <- w ^? hud . closeButtons . ix 0
fmap Right $ w ^? cWorld . lWorld . buttons . ix k
toggleMap :: Universe -> Universe
toggleMap u = case u ^. uvWorld . hud . hudElement of
DisplayCarte ->
u & uvWorld . hud . hudElement
.~ DisplayInventory
{ _subInventory = NoSubInventory
, _diSections = mempty
, _diSelection = Nothing
, _diInvFilter = mempty
, _diCloseFilter = mempty
}
_ -> u & uvWorld . hud . hudElement .~ DisplayCarte
toggleTweakInv :: World -> World
toggleTweakInv w = case w ^? hud . hudElement . subInventory of
Just ExamineInventory{} ->
w
& thepointer .~ NoSubInventory --MouseInvNothing
_ -> w & thepointer .~ ExamineInventory -- mi
where
thepointer = hud . hudElement . subInventory
tryCombine ::
(Int, Int) ->
World ->
World
tryCombine (i, j) w = fromMaybe w $ do
sss <- w ^? hud . hudElement . subInventory . ciSections
CombinableItem is it <- sss ^? ix i . ssItems . ix j . siPayload
p <- w ^? cWorld . lWorld . creatures . ix 0 . crPos
return $
snd (createItemYou it (foldr (destroyInvItem 0) w (sort is)))
& cWorld . lWorld . creatures . ix 0 . crHammerPosition .~ HammerDown
& soundStart InventorySound p wrench1S Nothing
& hud . hudElement . diSelection . _Just . _3 .~ mempty
maybeExitCombine :: World -> World
maybeExitCombine w
| ButtonRight `M.member` (w ^. input . mouseButtons) = w
| otherwise =
w & hud . hudElement . subInventory .~ NoSubInventory