module Dodge.Creature.YourControl ( yourControl, ) where import Dodge.Base.You import Dodge.Creature.Impulse.UseItem import Data.Foldable import qualified Data.Map.Strict as M import Data.Maybe import Dodge.Base.Coordinate import Dodge.Creature.Impulse.Movement import Dodge.Creature.Test import Dodge.Data.World import Dodge.InputFocus 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))) & pressedMBEffectsNoInventory pkeys where pkeys = w ^. input . mouseButtons intopinv = fromMaybe False $ do subinv <- w ^? hud . hudElement . subInventory Just $ case subinv of NoSubInventory -> True _ -> False --dimCreatureLight :: Creature -> World -> World --dimCreatureLight cr = cWorld . lWorld . tempLightSources .:~ tlsTimeRadColPos 1 300 0.1 (addZ 100 $ _crPos cr) -- note the order of operation, setting the posture first--this prevents the twist fire bug -- | Turn key presses into creature movement. 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 = noaimmove $ 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 let currenttwistamount = cr ^. crTwist case (astance,currenttwistamount) of ( TwoHandTwist, 0) -> return $ (crTwist .~ twistamount * pi) . (crDir -~ twistamount * pi) _ -> Nothing theMovement | movDir == V2 0 0 = id | otherwise = crMvAbsolute (speed *.* movAbs) noaimmove | movDir == V2 0 0 = id | otherwise = crMvForward speed theTurn cr' = creatureTurnTowardDir (_crMvAim cr') 0.2 cr' movDir = wasdDir w dir = fmap ((w ^. cWorld . camPos . camRot) +) (safeArgV movDir) movAbs = rotateV (w ^. cWorld . camPos . camRot) $ normalizeV movDir isAiming = _posture (_crStance cr) == Aiming mouseDir = fromMaybe (argV (_mousePos (_input w)) + (w ^. cWorld . camPos . camRot) ) $ do itRef <- cr ^? crManipulation . manObject . inInventory . ispItem _ <- cr ^? crInv . ix itRef . itScope . scopePos return . argV $ mouseWorldPos (w ^. input) (w ^. cWorld . camPos) -.- _crPos cr 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 wasdM :: SDL.Scancode -> Point2 wasdM scancode = case scancode of SDL.ScancodeW -> V2 0 1 SDL.ScancodeS -> V2 0 (-1) SDL.ScancodeD -> V2 1 0 SDL.ScancodeA -> V2 (-1) 0 _ -> V2 0 0 wasdDir :: World -> Point2 wasdDir = foldl' (flip $ (+.+) . wasdM) (V2 0 0) . M.keys . _pressedKeys . _input -- | Set posture according to mouse presses. mouseActionsCr :: M.Map SDL.MouseButton Bool -> Creature -> Creature mouseActionsCr pkeys cr | rbPressed && noaction = cr & crStance . posture .~ Aiming | otherwise = cr & crStance . posture .~ AtEase where rbPressed = SDL.ButtonRight `M.member` pkeys noaction = fromMaybe True $ do theaction <- cr ^? crManipulation . manObject . inInventory . iselAction return $ theaction == NoInvSelAction pressedMBEffectsNoInventory :: M.Map SDL.MouseButton Bool -> World -> World pressedMBEffectsNoInventory pkeys w | isDown SDL.ButtonLeft && isDown SDL.ButtonRight && inTopInv = useItem (you w) w | isDown SDL.ButtonLeft && inTopInv = useLeftItem 0 w | isDown SDL.ButtonMiddle = w & cWorld . camPos . camRot -~ rotation & input . clickMousePos .~ _mousePos (_input w) | otherwise = w where inTopInv = case w ^. hud . hudElement of DisplayInventory {_subInventory = NoSubInventory} -> True _ -> False isDown but = but `M.member` pkeys rotation = angleBetween (_mousePos (_input w)) (_clickMousePos (_input w))