Files
loop/src/Dodge/Creature/YourControl.hs
T

221 lines
7.6 KiB
Haskell

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)