221 lines
7.6 KiB
Haskell
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)
|