module Dodge.Creature.YourControl ( yourControl, ) where import Control.Monad import Data.Foldable import qualified Data.Map.Strict as M import Data.Maybe import Dodge.Base.Coordinate import Dodge.Base.You import Dodge.Creature.Impulse.Movement import Dodge.Creature.Impulse.UseItem import Dodge.Data.World import Dodge.Hotkey import Dodge.InputFocus import Dodge.WASD import Geometry import LensHelp import qualified SDL -- | The AI equivalent for your control. yourControl :: Creature -> World -> World yourControl cr w | inInputFocus w = w | not intopinv = w & cWorld . lWorld . creatures . ix (_crID cr) %~ wasdWithAiming w (_mvSpeed $ _crMvType cr) | otherwise = w & cWorld . lWorld . creatures . ix (_crID cr) %~ (wasdWithAiming w (_mvSpeed $ _crMvType cr) . mouseActionsCr (_mouseButtons (_input w))) & pressedMBEffectsTopInventory pkeys & handleHotkeys where pkeys = w ^. input . mouseButtons intopinv = fromMaybe False $ do subinv <- w ^? hud . hudElement . subInventory Just $ case subinv of NoSubInventory -> True _ -> False handleHotkeys :: World -> World handleHotkeys w | SDL.ButtonRight `M.member` _mouseButtons (_input w) = foldl' tryAssignHotkey w allHotkeys | otherwise = foldl' useHotKey w (M.intersection hotkeys (w ^. input . pressedKeys)) where hotkeys = M.mapKeys hotkeyToScancode $ w ^?! cWorld . lWorld . creatures . ix 0 . crHotkeys useHotKey :: World -> Int -> World useHotKey w invid = useItemHotkey 0 invid w allHotkeys :: [SDL.Scancode] allHotkeys = map hotkeyToScancode [minBound .. maxBound] hotkeyToScancode :: Hotkey -> SDL.Scancode hotkeyToScancode x = case x of HotkeyQ -> SDL.ScancodeQ HotkeyE -> SDL.ScancodeE Hotkey1 -> SDL.Scancode1 Hotkey2 -> SDL.Scancode2 Hotkey3 -> SDL.Scancode3 Hotkey4 -> SDL.Scancode4 Hotkey5 -> SDL.Scancode5 Hotkey6 -> SDL.Scancode6 Hotkey7 -> SDL.Scancode7 Hotkey8 -> SDL.Scancode8 Hotkey9 -> SDL.Scancode9 Hotkey0 -> SDL.Scancode0 scancodeToHotkey :: SDL.Scancode -> Hotkey scancodeToHotkey x = case x of SDL.ScancodeQ -> HotkeyQ SDL.ScancodeE -> HotkeyE SDL.Scancode1 -> Hotkey1 SDL.Scancode2 -> Hotkey2 SDL.Scancode3 -> Hotkey3 SDL.Scancode4 -> Hotkey4 SDL.Scancode5 -> Hotkey5 SDL.Scancode6 -> Hotkey6 SDL.Scancode7 -> Hotkey7 SDL.Scancode8 -> Hotkey8 SDL.Scancode9 -> Hotkey9 SDL.Scancode0 -> Hotkey0 _ -> undefined tryAssignHotkey :: World -> SDL.Scancode -> World tryAssignHotkey w sc = fromMaybe w $ do pt <- w ^? input . pressedKeys . ix sc guard (pt == InitialPress) cr <- w ^? cWorld . lWorld . creatures . ix 0 itid <- cr ^? crManipulation . manObject . inInventory . ispItem return $ w & cWorld . lWorld . creatures . ix 0 %~ assignHotkey itid (scancodeToHotkey sc) {- | Turn key presses into creature movement. | note the order of operation, setting the posture first--this prevents the twist fire bug -} --wasdWithAiming :: -- World -> -- -- | Base speed -- Float -> -- Creature -> -- Creature --wasdWithAiming w speed cr -- | isAiming = addAnyTwist $ aimTurn mouseDir $ theMovement $ setMvAim cr -- | crIsReloading cr && SDL.ButtonRight `M.member` _mouseButtons (_input w) = -- aimTurn mouseDir $ removeTwist $ theMovement $ setMvAim cr -- | otherwise = theMovement $ theTurn $ removeTwist $ setMvAim cr -- where -- setMvAim = maybe id (crMvAim .~) dir -- twistamount = 1.6 -- removeTwist cr' = -- cr' -- & crDir +~ _crTwist cr' -- & crTwist .~ 0 -- addAnyTwist = fromMaybe id $ do -- itRef <- cr ^? crManipulation . manObject . inInventory . ispItem -- astance <- cr ^? crInv . ix itRef . itUse . heldAim . aimStance -- case (astance, cr ^. crTwist) of -- (TwoHandUnder, 0) -> -- return $ (crTwist .~ twistamount * pi) . (crDir -~ twistamount * pi) -- (TwoHandOver, 0) -> -- return $ (crTwist .~ twistamount * pi) . (crDir -~ twistamount * pi) -- _ -> Nothing -- theMovement -- | movDir == V2 0 0 = id -- | otherwise = crMvAbsolute (speed *.* movAbs) -- theTurn cr' = creatureTurnTowardDir (_crMvAim cr') 0.2 cr' -- movDir = wasdDir (w ^. input) -- dir = fmap ((w ^. wCam . camRot) +) (safeArgV movDir) -- movAbs = rotateV (w ^. wCam . camRot) $ normalizeV movDir -- isAiming = _posture (_crStance cr) == Aiming -- mouseDir = argV $ mouseWorldPos (w ^. input) (w ^. wCam) - (cr ^. crPos) wasdWithAiming :: World -> -- | Base speed Float -> Creature -> Creature wasdWithAiming w speed = wasdAim inp cam . wasdTwist . wasdMovement inp cam speed where inp = w ^. input cam = w ^. wCam wasdAim :: Input -> Camera -> Creature -> Creature wasdAim inp cam cr | SDL.ButtonRight `M.member` _mouseButtons inp = aimTurn mouseDir cr | otherwise = theTurn cr where theTurn cr' = creatureTurnTowardDir (_crMvAim cr') 0.2 cr' mouseDir = argV $ mouseWorldPos inp cam - (cr ^. crPos) wasdTwist :: Creature -> Creature wasdTwist cr | _posture (_crStance cr) == Aiming = addAnyTwist cr | otherwise = removeTwist cr where twistamount = 1.6 removeTwist cr' = cr' & crDir +~ _crTwist cr' & crTwist .~ 0 addAnyTwist = fromMaybe id $ do itRef <- cr ^? crManipulation . manObject . inInventory . ispItem astance <- cr ^? crInv . ix itRef . itUse . heldAim . aimStance case (astance, cr ^. crTwist) of (TwoHandUnder, 0) -> return $ (crTwist .~ twistamount * pi) . (crDir -~ twistamount * pi) (TwoHandOver, 0) -> return $ (crTwist .~ twistamount * pi) . (crDir -~ twistamount * pi) _ -> Nothing wasdMovement :: Input -> Camera -> Float -> Creature -> Creature wasdMovement inp cam speed = theMovement . setMvAim where setMvAim = fromMaybe id $ do dir <- safeArgV movDir return $ crMvAim .~ (cam ^. camRot + dir) movDir = wasdDir inp movAbs = rotateV (cam ^. camRot) $ normalizeV movDir theMovement | movDir == V2 0 0 = id | otherwise = crMvAbsolute (speed *.* movAbs) aimTurn :: Float -> Creature -> Creature aimTurn a cr = creatureTurnTowardDir a (x * 0.2) cr where x = fromMaybe 1 $ do itRef <- cr ^? crManipulation . manObject . inInventory . ispItem cr ^? crInv . ix itRef . itUse . heldAim . aimTurnSpeed -- | Set posture according to mouse presses. mouseActionsCr :: M.Map SDL.MouseButton Int -> Creature -> Creature mouseActionsCr pkeys cr | SDL.ButtonRight `M.member` pkeys && noaction = cr & crStance . posture .~ Aiming | otherwise = cr & crStance . posture .~ AtEase where noaction = fromMaybe True $ do theaction <- cr ^? crManipulation . manObject . inInventory . iselAction return $ theaction == NoInvSelAction pressedMBEffectsTopInventory :: M.Map SDL.MouseButton Int -> World -> World pressedMBEffectsTopInventory pkeys w | isDown SDL.ButtonLeft && isDown SDL.ButtonRight && inTopInv = useItemRightClick (you w) w | isDown SDL.ButtonLeft && inTopInv = useItemLeftClick (you w) w | isDown SDL.ButtonMiddle = w & wCam . camRot -~ rotation | otherwise = w where inTopInv = case w ^. hud . hudElement of DisplayInventory{_subInventory = NoSubInventory} -> True _ -> False isDown but = but `M.member` pkeys theinput = w ^. input rotation = maybe 0 (angleBetween (theinput ^. mousePos)) (theinput ^. heldPos . at SDL.ButtonMiddle)