{-# 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