Files
loop/src/Dodge/Event/Keyboard.hs
T

154 lines
6.4 KiB
Haskell

{- | Deals with keyboard events. -}
module Dodge.Event.Keyboard
( handleKeyboardEvent
, handleTextInput
, guardDisconnectedID
) where
import Dodge.Terminal.LeftButton
import Dodge.WorldPos
import Dodge.Button.Event
import Dodge.InputFocus
import Dodge.Base
import Dodge.Combine
import Dodge.Creature.Action
import Dodge.Data
import Dodge.Event.Menu
import Dodge.Event.Test
import Dodge.Inventory
import Dodge.Menu
import Dodge.Reloading
import Dodge.Save
import LensHelp
--import Color
--import Data.List
import qualified IntMapHelp as IM
import Data.Maybe
import qualified Data.Set as S
import SDL
--import Data.Text (unpack)
import qualified Data.Text as T
-- annoyingly, the text input event doesn't register backspace, so deletion has to be
-- dealt with using key presses (handlePressedKey)
-- also, note that this currently "doubles" the inputs to both terminals if both
-- are open
handleTextInput :: T.Text -> Universe -> Universe
handleTextInput text u = u
& menuLayers . ix 0 . scInput %~ updateText
& updateTerminalText
where
updateTerminalText = case u ^? uvWorld . cWorld . hud . hudElement . subInventory of
Just (DisplayTerminal tmid) | hasfocus tmid
-> uvWorld %~ \w -> guardDisconnectedID tmid w (w & cWorld . terminals . ix tmid . tmInput . tiText %~ updateText)
_ -> id
hasfocus tmid = fromMaybe False $ u ^? uvWorld . cWorld . terminals . ix tmid . tmInput . tiFocus
updateText s = case T.unpack text of
";" -> s
_ -> s `T.append` T.toUpper text
guardDisconnectedID :: Int -> World -> World -> World
guardDisconnectedID tmid w w' = case w ^? cWorld . terminals . ix tmid . tmStatus of
Just TerminalReady -> w'
_ -> w
{- | Handles keyboard press and release.
On release, remove scancode from the 'Set' of pressed keys.
On press, adds the scancode, and perhaps applies a direct effect:
see 'handlePressedKeyInGame'.
-}
handleKeyboardEvent :: KeyboardEventData -> Universe -> IO (Maybe Universe)
handleKeyboardEvent kev u = case keyboardEventKeyMotion kev of
Released -> return . Just $ u & uvWorld . cWorld . keys %~ S.delete scode
Pressed -> handlePressedKey (keyboardEventRepeat kev) scode
(u & uvWorld . cWorld . keys %~ S.insert scode)
where
scode = (keysymScancode . keyboardEventKeysym) kev
handlePressedKey :: Bool -> Scancode -> Universe -> IO (Maybe Universe)
handlePressedKey True ScancodeBackspace u
| _backspaceTimer (_cWorld $ _uvWorld u) <= 0 = handlePressedKey False ScancodeBackspace u
<&> _Just . uvWorld . cWorld . backspaceTimer .~ 0
| otherwise = return $ Just $ u & uvWorld . cWorld . backspaceTimer -~ 1
handlePressedKey True _ u = return $ Just u
handlePressedKey _ scode u = case scode of
ScancodeF5 -> return . Just $ doQuicksave u
ScancodeF9 -> return . Just $ loadSaveSlot QuicksaveSlot u
ScancodeSemicolon -> return . Just $ gotoTerminal u
_ | null (_menuLayers u) -> case u ^? uvWorld . cWorld . hud . hudElement . subInventory of
Just (DisplayTerminal tmid) | inTermFocus (_uvWorld u)
-> return $ uvWorld (Just . handlePressedKeyTerminal tmid scode) u
_ -> return $ (Just . handlePressedKeyInGame scode) u
_ -> handlePressedKeyInMenu (head $ _menuLayers u) scode u
handlePressedKeyInGame :: Scancode -> Universe -> Universe
handlePressedKeyInGame scode uv = case scode of
ScancodeEscape -> pauseGame $ over uvWorld escapeMap uv
ScancodeSpace -> over uvWorld spaceAction uv
ScancodeP -> pauseGame $ over uvWorld escapeMap uv
ScancodeF -> over uvWorld youDropItem uv
ScancodeM -> over uvWorld toggleMap uv
ScancodeR -> over uvWorld (crToggleReloading (you w)) uv
ScancodeT -> over uvWorld testEvent uv
ScancodeX -> uv & uvWorld . cWorld . hud . hudElement %~ toggleTweakInv
ScancodeC -> over uvWorld toggleCombineInv uv
ScancodeI -> uv & uvWorld . cWorld . hud . hudElement %~ toggleInspectInv
_ -> uv
where
w = _uvWorld uv
handlePressedKeyTerminal :: Int -> Scancode -> World -> World
handlePressedKeyTerminal tmid scode w = case scode of
ScancodeEscape -> w & cWorld . terminals . ix tmid . tmInput . tiFocus %~ const False
ScancodeReturn -> w & terminalReturnEffect (w ^?! cWorld . terminals . ix tmid)
ScancodeBackspace -> w
& cWorld . terminals . ix tmid . tmInput . tiText %~ doBackspace
& cWorld . backspaceTimer .~ 5
_ -> w
where
doBackspace t = case T.unsnoc t of
Nothing -> t
Just (t',_) -> t'
toggleTweakInv :: HUDElement -> HUDElement
toggleTweakInv he = case he of
DisplayInventory TweakInventory -> DisplayInventory NoSubInventory
_ -> DisplayInventory TweakInventory
toggleInspectInv :: HUDElement -> HUDElement
toggleInspectInv he = case he of
DisplayInventory InspectInventory -> DisplayInventory NoSubInventory
_ -> DisplayInventory InspectInventory
gotoTerminal :: Universe -> Universe
gotoTerminal w = case _menuLayers w of
(InputScreen {} : _) -> w
_ -> w & menuLayers .:~ InputScreen T.empty "Enter command"
spaceAction :: World -> World
spaceAction w = case _hudElement $ _hud (_cWorld w) of
DisplayCarte -> w & cWorld . hud . carteCenter .~ theLoc
DisplayInventory NoSubInventory -> case selectedCloseObject w of
Just (_,Left flit) -> pickUpItem 0 flit w
Just (_,Right but) -> doButtonEvent (_btEvent but) but w
_ -> w
DisplayInventory DisplayTerminal {} -> w & cWorld . hud . hudElement .~ DisplayInventory NoSubInventory
_ -> w & cWorld . hud . hudElement .~ DisplayInventory NoSubInventory
where
theLoc = doWorldPos (fst (_seenLocations (_cWorld w) IM.! _selLocation (_cWorld w))) w
-- updateTopCloseObject i w' = w' & closeObjects %~ ( Right (_buttons w' IM.! i) : ) . tail
pauseGame :: Universe -> Universe
pauseGame = menuLayers .~ [pauseMenu]
toggleMap :: World -> World
toggleMap w = case _hudElement $ _hud (_cWorld w) of
DisplayCarte -> w & cWorld . hud . hudElement .~ DisplayInventory NoSubInventory
_ -> w & cWorld . hud . hudElement .~ DisplayCarte
escapeMap :: World -> World
escapeMap w = case _hudElement $ _hud (_cWorld w) of
DisplayCarte -> w & cWorld . hud . hudElement .~ DisplayInventory NoSubInventory
_ -> w