Delete cruft, add Reader monad to some internal ai

This commit is contained in:
2021-05-16 21:42:11 +02:00
parent 0798cc0b0e
commit d7fcdbf550
69 changed files with 721 additions and 2894 deletions
+2 -2
View File
@@ -24,7 +24,7 @@ import Music
import Control.Concurrent import Control.Concurrent
import Control.Lens import Control.Lens
import Foreign (Word32) import Foreign (Word32)
import Control.Monad (when,void) import Control.Monad
import System.Random import System.Random
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.IntMap as IM import qualified Data.IntMap as IM
@@ -82,7 +82,7 @@ doPreload = do
checkForGlErrors :: IO () checkForGlErrors :: IO ()
checkForGlErrors = do checkForGlErrors = do
errs <- errors errs <- errors
when (length errs > 0) $ putStrLn $ "GLerror during doLoop: " ++ unwords (map show errs) unless (null errs) $ putStrLn $ "GLerror during doLoop: " ++ unwords (map show errs)
setWindowSize :: Int -> Int -> KeyConfigSDL-> World -> World setWindowSize :: Int -> Int -> KeyConfigSDL-> World -> World
setWindowSize x y z w = w setWindowSize x y z w = w
-104
View File
@@ -1,104 +0,0 @@
module Dodge.AIs
(
) where
import Dodge.Creature.Stance.Data
import Dodge.Creature.State.Data
import Dodge.Creature.Impulse.Data
import Dodge.Data hiding (Action (..), Impulse (..), Strategy (..))
import Dodge.Base
import Dodge.Path
import Dodge.SoundLogic
import Dodge.Creature.Action
import Dodge.Creature.Action.Movement
import Dodge.RandomHelp
import Dodge.WorldEvent
import Dodge.Creature.Picture
import Geometry
import Picture
import Data.List
import Data.Char
import Data.Maybe
import Data.Function
import Data.Graph.Inductive.Graph hiding ((&))
import Data.Graph.Inductive.PatriciaTree
import Data.Graph.Inductive.Query.SP
import qualified Data.ByteString as B
import qualified Data.Set as S
import qualified Data.IntMap.Strict as IM
import qualified Data.Map as M
import Control.Lens
import Control.Applicative
import Control.Monad
import Control.Monad.State
import Control.Concurrent
import System.Random
import Foreign.ForeignPtr
----
---- encircleAI' :: Int -> World -> World
---- encircleAI' cid w =
---- let cr = _creatures w IM.! cid
---- cpos = _crPos cr
---- damageYou = over (creatures . ix 0 . crHP) (\hp -> hp - 10) . soundOnce hitSound
---- ypos = _crPos $ you w
---- flockers = IM.filter (flip (canSeePoint cid) w . _crPos)
---- $ IM.filter (factionIs $ EncircleFlock)
---- $ _creatures w
---- tp | length flockers <= 1 = ypos
---- | otherwise = ypos +.+
---- f (max 0 (magV (ypos -.- cenp) - 30) )
---- *.* safeNormalizeV (cpos -.- cenp)
---- where f x = 150 * sigmoid (x-10)
---- cenp = (1 / fromIntegral (length flockers)) *.*
---- foldr1 (+.+)
---- (map _crPos $ IM.elems flockers)
---- combinedRad = _crRad cr + _crRad (you w)
---- replaceGoal newImpulses = over (creatures . ix cid . crState . goals)
---- (\gs -> newImpulses ++ tail gs)
---- addGoal newImpulses = over (creatures . ix cid . crState . goals)
---- (\gs -> newImpulses ++ gs)
---- replaceImpulse newActions = over (creatures . ix cid . crState . goals)
---- (\((_:as):ass) -> (newActions ++ as):ass)
---- addImpulse newActions = over (creatures . ix cid . crState . goals)
---- (\(as:ass) -> (newActions++as):ass)
---- in if _crHP cr <= 0 then killCr cid w else
---- case head $ _goals $ _crState cr of
---- [] | canSee cid (_yourID w) w
---- -> replaceGoal [[MoveToFor tp 10]] w
---- | otherwise -> w
---- (MoveToFor p x:_)
---- | dist ypos cpos < combinedRad + 5
---- && abs ((_crDir cr) - argV (ypos -.- cpos)) < pi/4 -- same error as above
---- && x == 0
---- -> over (creatures . ix cid . crPos)
---- (+.+ (12 *.* errorNormalizeVAI (ypos -.- cpos)))
---- $ replaceImpulse [MeleeAttack 5]
---- $ damageYou
---- w
---- | canSee cid (_yourID w) w && dist cpos ypos < 50
---- -> mvForward 2 cid $ turnTowardSpeed 0.5 ypos cid
---- $ replaceImpulse [MoveToFor ypos (max 0 (x-1))] w
---- | x == 0 && canSee cid (_yourID w) w
---- -> mvForward 2 cid $ turnTowardSpeed 0.5 p cid
---- $ replaceImpulse [MoveToFor tp 0] w
---- | x == 0 -> replaceImpulse [MoveToFor p 10] w
---- | canSee cid (_yourID w) w
---- -> mvForward 2 cid $ turnTowardSpeed 0.5 p cid
---- $ replaceImpulse [MoveToFor p (x-1)] w
---- | dist cpos p < 20 -> w
---- | otherwise -> mvForward 2 cid $ turnTowardSpeed 0.5 p cid w
---- (MeleeAttack x:_)
---- | x == 0 -> replaceImpulse [WaitFor 5] w
---- | otherwise -> replaceImpulse [MeleeAttack (x-1)] w
---- (WaitFor x:gls)| x == 0 -> replaceImpulse [] w
---- | canSee cid (_yourID w) w
---- -> turnTowardSpeed 0.02 ypos cid
---- $ replaceImpulse [WaitFor (x-1)] w
---- | otherwise -> replaceImpulse [WaitFor (x-1)] w
errorNormalizeVAI :: Point2 -> Point2
errorNormalizeVAI (0,0) = error "problem with function: errorNormalizeVAI in DodgeAIs"
errorNormalizeVAI p = normalizeV p
----------------
File diff suppressed because it is too large Load Diff
+17 -10
View File
@@ -45,9 +45,9 @@ midPadL i x xs ys = take j (xs ++ repeat x) ++ ys
j = i - length ys j = i - length ys
takeUntil :: (a -> Bool) -> [a] -> [a] takeUntil :: (a -> Bool) -> [a] -> [a]
takeUntil f ps = case span (not . f) ps of takeUntil f ps = case break f ps of
(xs,[]) -> xs (xs,[]) -> xs
(xs,(y:_)) -> xs ++ [y] (xs, y:_ ) -> xs ++ [y]
you :: World -> Creature you :: World -> Creature
you w = _creatures w IM.! _yourID w you w = _creatures w IM.! _yourID w
@@ -63,7 +63,7 @@ crItem w cid = _crInv cr IM.! _crInvSel cr
where where
cr = _creatures w IM.! cid cr = _creatures w IM.! cid
yourItemRef w = (creatures . ix (_yourID w) . crInv . ix (_crInvSel (you w))) yourItemRef w = creatures . ix (_yourID w) . crInv . ix (_crInvSel (you w))
wallNormal :: Wall -> Point2 wallNormal :: Wall -> Point2
wallNormal wl = normalizeV . vNormal $ a -.- b wallNormal wl = normalizeV . vNormal $ a -.- b
@@ -73,22 +73,21 @@ wallNormal wl = normalizeV . vNormal $ a -.- b
wallsOnLine :: Point2 -> Point2 -> IM.IntMap Wall -> [Wall] wallsOnLine :: Point2 -> Point2 -> IM.IntMap Wall -> [Wall]
wallsOnLine p1 p2 ws = hitWalls wallsOnLine p1 p2 ws = hitWalls
where where
hitPoint w = intersectSegSeg' p1 p2 (fst $ _wlLine w) (snd $ _wlLine w) hitPoint w = uncurry (intersectSegSeg' p1 p2) (_wlLine w)
hitWalls = filter (isJust . hitPoint) (IM.elems ws) hitWalls = filter (isJust . hitPoint) (IM.elems ws)
wallOnLine :: Point2 -> Point2 -> IM.IntMap Wall -> Maybe Wall wallOnLine :: Point2 -> Point2 -> IM.IntMap Wall -> Maybe Wall
wallOnLine p1 p2 ws wallOnLine p1 p2 ws
= listToMaybe $ sortBy f hitWalls = listToMaybe $ sortBy f hitWalls
where where
hitPoint w = intersectSegSeg' p1 p2 (fst $ _wlLine w) (snd $ _wlLine w) hitPoint w = uncurry (intersectSegSeg' p1 p2) (_wlLine w)
hitWalls = filter (isJust . hitPoint) (IM.elems ws) hitWalls = filter (isJust . hitPoint) (IM.elems ws)
f w1 w2 = compare (magV (p1 -.- fromJust (hitPoint w1))) (magV (p1 -.- fromJust (hitPoint w2))) f w1 w2 = compare (magV (p1 -.- fromJust (hitPoint w1))) (magV (p1 -.- fromJust (hitPoint w2)))
wallsOnCirc :: Point2 -> Float -> IM.IntMap Wall -> [Wall] wallsOnCirc :: Point2 -> Float -> IM.IntMap Wall -> IM.IntMap Wall
wallsOnCirc p r wls = IM.elems $ IM.filter f wls wallsOnCirc p r = IM.filter f
where where
f wl = circOnSeg (fst $ _wlLine wl) (snd $ _wlLine wl) p r f wl = uncurry circOnSeg (_wlLine wl) p r
allWalls :: World -> IM.IntMap Wall allWalls :: World -> IM.IntMap Wall
allWalls w = IM.unions $ concatMap IM.elems $ IM.elems $ _wallsZone w allWalls w = IM.unions $ concatMap IM.elems $ IM.elems $ _wallsZone w
@@ -301,7 +300,7 @@ collidePointWallsCol p1 p2 ws
. sortOn f . sortOn f
. IM.elems . IM.elems
$ IM.mapMaybe ( (\(m, c) -> m <&> (, c)) $ IM.mapMaybe ( (\(m, c) -> m <&> (, c))
. (\w -> (intersectSegSeg' p1 p2 (fst $ _wlLine w) (snd $ _wlLine w), _wlColor w))) ws . (\w -> (uncurry (intersectSegSeg' p1 p2) (_wlLine w), _wlColor w))) ws
where where
f (a,_) = magV (p1 -.- a) f (a,_) = magV (p1 -.- a)
{- | Looks for first collision of a point with walls. {- | Looks for first collision of a point with walls.
@@ -507,3 +506,11 @@ isAnimate cr = case _crActionPlan cr of
_ -> True _ -> True
sigmoid x = x/sqrt(1+x^2) sigmoid x = x/sqrt(1+x^2)
{- | In order to force a list, apply with seq. -}
forceSpine :: [a] -> ()
forceSpine = foldr (const id) ()
forceList :: [a] -> [a]
forceList l = seq (forceSpine l) l
+13 -18
View File
@@ -13,9 +13,7 @@ import Control.Lens
hasLOS :: Point2 -> Point2 -> World -> Bool hasLOS :: Point2 -> Point2 -> World -> Bool
{-# INLINE hasLOS #-} {-# INLINE hasLOS #-}
hasLOS p1 p2 w = (not $ pointHitsWalls p1 p2 nearbyWalls) hasLOS p1 p2 w = not $ pointHitsWalls p1 p2 $ wallsAlongLine p1 p2 w
where
nearbyWalls = wallsAlongLine p1 p2 w
-- | looks for first collision of a point with walls -- | looks for first collision of a point with walls
-- if found, gives point and reflection velocity -- if found, gives point and reflection velocity
reflectPointWalls :: Point2 -> Point2 -> IM.IntMap Wall -> Maybe (Point2,Point2) reflectPointWalls :: Point2 -> Point2 -> IM.IntMap Wall -> Maybe (Point2,Point2)
@@ -56,11 +54,11 @@ reflectPointWallsDamped dfact p1 p2 ws
-- | Test if a point collides with walls -- | Test if a point collides with walls
pointHitsWalls :: Point2 -> Point2 -> IM.IntMap Wall -> Bool pointHitsWalls :: Point2 -> Point2 -> IM.IntMap Wall -> Bool
pointHitsWalls p1 p2 pointHitsWalls p1 p2
= any $ isJust . ( \(x,y) -> intersectSegSeg' p1 p2 x y) . _wlLine = any $ isJust . uncurry (intersectSegSeg' p1 p2) . _wlLine
-- | Test if there something blocking a walk -- | Test if there something blocking a walk
collidePointWalkable :: Point2 -> Point2 -> IM.IntMap Wall -> Bool collidePointWalkable :: Point2 -> Point2 -> IM.IntMap Wall -> Bool
collidePointWalkable p1 p2 ws collidePointWalkable p1 p2 ws
= any (isJust . ( \(x,y) -> intersectSegSeg' p1 p2 x y) . _wlLine) = any (isJust . uncurry (intersectSegSeg' p1 p2) . _wlLine)
$ IM.filter (fromMaybe True . (^? doorPathable)) ws $ IM.filter (fromMaybe True . (^? doorPathable)) ws
furthestPointWalkable :: Point2 -> Point2 -> IM.IntMap Wall -> Point2 furthestPointWalkable :: Point2 -> Point2 -> IM.IntMap Wall -> Point2
@@ -69,7 +67,7 @@ furthestPointWalkable p1 p2 ws
. listToMaybe . listToMaybe
. sortOn (dist p1) . sortOn (dist p1)
. IM.elems . IM.elems
$ IM.mapMaybe ( ( \(x,y) -> intersectSegSeg' p1 p2 x y) . _wlLine) ws $ IM.mapMaybe ( uncurry (intersectSegSeg' p1 p2) . _wlLine) ws
collidePointIndirect :: Point2 -> Point2 -> IM.IntMap Wall -> Maybe Point2 collidePointIndirect :: Point2 -> Point2 -> IM.IntMap Wall -> Maybe Point2
{-# INLINE collidePointIndirect #-} {-# INLINE collidePointIndirect #-}
@@ -77,7 +75,7 @@ collidePointIndirect p1 p2 ws
= listToMaybe = listToMaybe
. sortOn (dist p1) . sortOn (dist p1)
. IM.elems . IM.elems
. IM.mapMaybe ( ( \(x,y) -> intersectSegSeg' p1 p2 x y) . _wlLine) . IM.mapMaybe ( uncurry (intersectSegSeg' p1 p2) . _wlLine)
$ IM.filter (not . _wlIsSeeThrough) ws $ IM.filter (not . _wlIsSeeThrough) ws
{- | Checks to see whether someone can fire bullets effectively between two points. {- | Checks to see whether someone can fire bullets effectively between two points.
- Not sure if this needs vision as well, need to make this uniform. -} - Not sure if this needs vision as well, need to make this uniform. -}
@@ -86,13 +84,13 @@ collidePointFire p1 p2 ws
= listToMaybe = listToMaybe
. sortOn (dist p1) . sortOn (dist p1)
. IM.elems . IM.elems
. IM.mapMaybe ( ( \(x,y) -> intersectSegSeg' p1 p2 x y) . _wlLine ) . IM.mapMaybe ( uncurry (intersectSegSeg' p1 p2) . _wlLine )
$ IM.filter (\wl -> not (_wlIsSeeThrough wl && isJust (wl ^? blHP))) ws $ IM.filter (\wl -> not (_wlIsSeeThrough wl && isJust (wl ^? blHP))) ws
{- | Checks to see whether someone can fire bullets effectively between two points. {- | Checks to see whether someone can fire bullets effectively between two points.
- Not sure if this needs vision as well, need to make this uniform. -} - Not sure if this needs vision as well, need to make this uniform. -}
collidePointFireVision :: Point2 -> Point2 -> IM.IntMap Wall -> Bool collidePointFireVision :: Point2 -> Point2 -> IM.IntMap Wall -> Bool
collidePointFireVision p1 p2 ws collidePointFireVision p1 p2 ws
= any ( isJust . ( \(x,y) -> intersectSegSeg' p1 p2 x y) . _wlLine) = any ( isJust . uncurry (intersectSegSeg' p1 p2) . _wlLine)
$ IM.filter notBlockWindow ws $ IM.filter notBlockWindow ws
where where
notBlockWindow wl = case wl ^? blHP of notBlockWindow wl = case wl ^? blHP of
@@ -125,15 +123,14 @@ canSeePoint i p w = hasLOS p1 p w
pathToPointFireable :: Int -> Point2 -> World -> Bool pathToPointFireable :: Int -> Point2 -> World -> Bool
pathToPointFireable i p w pathToPointFireable i p w
= not = not
. pointHitsWalls (_crPos (_creatures w IM.! i)) p . pointHitsWalls (_crPos $ _creatures w IM.! i) p
$ IM.filter (not . isJust . \wl -> wl ^? blHP) $ wallsAlongLine p1 p w $ IM.filter (isNothing . (^? blHP) ) $ wallsAlongLine p1 p w
where where
p1 = _crPos (_creatures w IM.! i) p1 = _crPos (_creatures w IM.! i)
canSeePointAll :: Int -> Point2 -> World -> Bool canSeePointAll :: Int -> Point2 -> World -> Bool
canSeePointAll i targPos w canSeePointAll i targPos w
= and = all (flip (canSeePoint i) w . (\p -> targPos +.+ radius *.* p)) [(1,0),(0,1),(-1,0),(0,-1)]
$ map (flip (canSeePoint i) w . (\p -> (targPos +.+ radius *.* p))) [(1,0),(0,1),(-1,0),(0,-1)]
where where
cr = _creatures w IM.! i cr = _creatures w IM.! i
cpos = _crPos cr cpos = _crPos cr
@@ -141,8 +138,7 @@ canSeePointAll i targPos w
canSeeAny :: Int -> Int -> World -> Bool canSeeAny :: Int -> Int -> World -> Bool
canSeeAny fromID toID w canSeeAny fromID toID w
= or = any (flip (canSeePoint fromID) w . (\p -> cpos +.+ radius *.* p)) [(1,0),(0,1),(-1,0),(0,-1)]
$ map (flip (canSeePoint fromID) w . (\p -> (cpos +.+ radius *.* p))) [(1,0),(0,1),(-1,0),(0,-1)]
where where
cr = _creatures w IM.! toID cr = _creatures w IM.! toID
cpos = _crPos cr cpos = _crPos cr
@@ -150,8 +146,7 @@ canSeeAny fromID toID w
canSeeAll :: Int -> Int -> World -> Bool canSeeAll :: Int -> Int -> World -> Bool
canSeeAll fromID toID w canSeeAll fromID toID w
= and = all (flip (canSeePoint fromID) w . (\p -> cpos +.+ radius *.* p)) [(1,0),(0,1),(-1,0),(0,-1)]
$ map (flip (canSeePoint fromID) w . (\p -> (cpos +.+ radius *.* p))) [(1,0),(0,1),(-1,0),(0,-1)]
where where
cr = _creatures w IM.! toID cr = _creatures w IM.! toID
cpos = _crPos cr cpos = _crPos cr
@@ -164,7 +159,7 @@ canWalk i j w = not $ collidePointWalkable ipos jpos $ wallsAlongLine ipos jpos
jpos = _crPos (_creatures w IM.! j) jpos = _crPos (_creatures w IM.! j)
canSeeIndirect :: Int -> Int -> World -> Bool canSeeIndirect :: Int -> Int -> World -> Bool
canSeeIndirect i j w = not . isJust . collidePointIndirect ipos jpos $ wallsAlongLine ipos jpos w canSeeIndirect i j w = isNothing . collidePointIndirect ipos jpos $ wallsAlongLine ipos jpos w
where where
ipos = _crPos (_creatures w IM.! i) ipos = _crPos (_creatures w IM.! i)
jpos = _crPos (_creatures w IM.! j) jpos = _crPos (_creatures w IM.! j)
+1 -1
View File
@@ -7,7 +7,7 @@ import Foreign.C.Types
import GHC.Generics import GHC.Generics
import qualified GHC.Int import qualified GHC.Int
import qualified SDL import qualified SDL
import SDL.Internal.Numbered as SDL.Internal.Numbered import qualified SDL.Internal.Numbered
import System.Directory import System.Directory
+10 -66
View File
@@ -9,10 +9,8 @@ module Dodge.Creature
where where
import Dodge.Creature.Stance.Data import Dodge.Creature.Stance.Data
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Dodge.Creature.Impulse.Data
import Dodge.Creature.ImpulseRat import Dodge.Creature.ImpulseRat
import Dodge.Creature.ActionRat import Dodge.Creature.ActionRat
import Dodge.Creature.Rationality.Data
import Dodge.Creature.AlertLevel import Dodge.Creature.AlertLevel
import Dodge.Creature.SetTarget import Dodge.Creature.SetTarget
import Dodge.Creature.Test import Dodge.Creature.Test
@@ -21,7 +19,6 @@ import Dodge.Creature.PistolCrit
import Dodge.Creature.LtAutoCrit import Dodge.Creature.LtAutoCrit
import Dodge.Creature.SpreadGunCrit import Dodge.Creature.SpreadGunCrit
import Dodge.Data import Dodge.Data
import Dodge.AIs
import Dodge.Default import Dodge.Default
import Dodge.Base import Dodge.Base
import Dodge.Item.Weapon import Dodge.Item.Weapon
@@ -35,7 +32,6 @@ import Dodge.Creature.Rationality
import Dodge.Creature.ChooseTarget import Dodge.Creature.ChooseTarget
import Dodge.Item import Dodge.Item
import Dodge.Picture.Layer import Dodge.Picture.Layer
import Dodge.Creature.Picture
import Picture import Picture
import Geometry import Geometry
@@ -63,7 +59,6 @@ spawnerCrit = defaultCreature
{ --_crUpdate = stateUpdate $ spawnerAI chaseCrit { --_crUpdate = stateUpdate $ spawnerAI chaseCrit
_crHP = 300 _crHP = 300
, _crPict = basicCrPict blue , _crPict = basicCrPict blue
, _crState = defaultState {_goals = [[WaitFor 0]] }
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)] , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
} }
smallChaseCrit :: Creature smallChaseCrit :: Creature
@@ -78,10 +73,11 @@ smallChaseCrit = defaultCreature
} }
chaseCrit :: Creature chaseCrit :: Creature
chaseCrit = defaultCreature chaseCrit = defaultCreature
{ _crUpdate = stateUpdate $ impulsiveAI $ composeInternalAIs { _crUpdate = stateUpdate $ impulsiveAIR $
[ chaseTarget targetYouLOS chaseTargetR targetYouLOS <=<
, \ _ -> crMeleeCooldown . _Just %~ (max 0 . subtract 1) overrideMeleeCloseTargetR <=<
] basicPerceptionUpdateR [0] <=<
return . (crMeleeCooldown . _Just %~ (max 0 . subtract 1))
, _crHP = 300 , _crHP = 300
, _crPict = basicCrPict green , _crPict = basicCrPict green
, _crInv = IM.empty , _crInv = IM.empty
@@ -93,7 +89,6 @@ armourChaseCrit = defaultCreature
{ _crUpdate = stateUpdate $ meleeCooldown $ impulsiveAI $ chaseTarget targetYouLOS { _crUpdate = stateUpdate $ meleeCooldown $ impulsiveAI $ chaseTarget targetYouLOS
, _crHP = 300 , _crHP = 300
, _crPict = basicCrPict green , _crPict = basicCrPict green
, _crState = defaultState {_goals = [[Wait]]}
, _crInv = IM.fromList , _crInv = IM.fromList
[(0,frontArmour) [(0,frontArmour)
,(1,medkit 200) ,(1,medkit 200)
@@ -139,7 +134,6 @@ longCrit = defaultCreature
, _crInv = IM.fromList [(0,longGun),(1,medkit 100)] , _crInv = IM.fromList [(0,longGun),(1,medkit 100)]
, _crInvSel = 0 , _crInvSel = 0
, _crRad = 10 , _crRad = 10
, _crState = defaultState {_goals = [[InitGuard]]}
, _crHP = 300 , _crHP = 300
} }
multGunCrit :: Creature multGunCrit :: Creature
@@ -149,7 +143,6 @@ multGunCrit = defaultCreature
, _crInv = IM.fromList [(0,multGun),(1,medkit 100)] , _crInv = IM.fromList [(0,multGun),(1,medkit 100)]
, _crInvSel = 0 , _crInvSel = 0
, _crRad = 10 , _crRad = 10
, _crState = defaultState {_goals = [[InitGuard]]}
, _crHP = 300 , _crHP = 300
, _crUpdate = stateUpdate $ impulsiveAI $ composeInternalAIs , _crUpdate = stateUpdate $ impulsiveAI $ composeInternalAIs
[ performActions [ performActions
@@ -197,68 +190,21 @@ autoCrit = defaultCreature
, _crInv = IM.fromList [(0,autoGun),(1,medkit 100)] , _crInv = IM.fromList [(0,autoGun),(1,medkit 100)]
, _crInvSel = 0 , _crInvSel = 0
, _crRad = 10 , _crRad = 10
, _crState = defaultState {_goals = [[InitGuard]]}
, _crHP = 300 , _crHP = 300
} }
addArmour :: Creature -> Creature addArmour :: Creature -> Creature
addArmour = over crInv insarmour addArmour = over crInv insarmour
where where
insarmour xs = IM.insert (newKey xs) frontArmour xs insarmour xs = IM.insert (newKey xs) frontArmour xs
{- | The creature you control.
--packCrits :: (Int -> World -> World) -> [Int] -> [Creature] ID 0. -}
--packCrits ai is = [(defaultCreature i)
-- { _crPos = (150,10+20*fromIntegral i)
-- , _crPict = swarmPict
-- , _crUpdate = ai i
-- --, _crUpdate = swarmAI is i
-- , _crRad = 3
-- , _crHP = 1
-- , _crMass = 2
-- }
-- | i <- is]
--queenBeeCrit :: Int -> Creature
--queenBeeCrit cID = (defaultCreature cID)
-- { _crRad = 20
-- , _crCorpse = color (greyN 0.5) $ circleSolid 20
-- , _crPict = const $ pictures [color black $ circSolid 20
-- ,color yellow $ circLine 20
-- ]
-- , _crUpdate = checkDead cID . makeStateAI queenBeeAI cID
-- , _crState = QueenBee 0 20
-- , _crMass = 20
-- }
--antCrit :: Int -> Creature
--antCrit cID = (defaultCreature cID)
-- { _crPos = (0,100 + 3 * fromIntegral cID)
-- , _crUpdate = checkDead cID . makeStateAI (antAI 2) cID
-- , _crState = AntMove 50
-- , _crPict = antPic
-- , _crRad = 3
-- , _crHP = 1
-- , _crMass = 2
-- , _crCorpse = color (greyN 0.5) $ circSolid 3
-- }
-- where i = evalState (state (randomR (1::Int,100))) (mkStdGen cID)
--antPic = const $ pictures [ translate (-1) 0 $ circleSolid 2
-- , translate (2) 0 $ circleSolid 1
-- , translate (1) 0 $ circleSolid 1
-- , line [(3,3),(-3,-3)]
-- , line [(-3,3),(3,-3)]
-- , line [(0,-3),(0,3)]
-- ]
{- |
The creature you control.
ID 0.
-}
startCr :: Creature startCr :: Creature
startCr = defaultCreature startCr = defaultCreature
{ _crPos = (0,0) { _crPos = (0,0)
, _crOldPos = (0,0) , _crOldPos = (0,0)
, _crDir = 0 , _crDir = 0
, _crID = 0 , _crID = 0
, _crPict = basicCrPict $ black , _crPict = basicCrPict black
, _crUpdate = stateUpdate yourControl , _crUpdate = stateUpdate yourControl
, _crRad = 10 , _crRad = 10
, _crMass = 10 , _crMass = 10
@@ -268,9 +214,7 @@ startCr = defaultCreature
, _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ pictures [color (greyN 0.8) $ circleSolid 10, circLine 10] , _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ pictures [color (greyN 0.8) $ circleSolid 10, circLine 10]
, _crFaction = PlayerFaction , _crFaction = PlayerFaction
} }
{- | {- | Items you start with. -}
Items you start with.
-}
startInventory = IM.fromList (zip [0..20] startInventory = IM.fromList (zip [0..20]
( (
[bezierGun [bezierGun
@@ -298,5 +242,5 @@ startInventory = IM.fromList (zip [0..20]
++ ++
repeat NoItem)) repeat NoItem))
smokeGenGun = effectGun "smoke" $ \_ -> spawnSmokeAtCursor smokeGenGun = effectGun "smoke" $ const spawnSmokeAtCursor
-11
View File
@@ -1,11 +0,0 @@
module Dodge.Creature.AI
where
import Dodge.Data
import Control.Lens
import System.Random
insectAI
:: ( World -> StdGen -> Creature -> (World -> World, StdGen, Creature) )
-> World -> (World -> World,StdGen) -> Creature -> ((World -> World,StdGen), Maybe Creature)
insectAI = undefined
-12
View File
@@ -1,12 +0,0 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StrictData #-}
module Dodge.Creature.AI.Data
where
import Dodge.Creature.State.Data
import Dodge.Creature.Impulse.Data
import Control.Lens
data Intelligence
= Zombie { _crImpulse :: Impulse }
| Inanimate
+10 -13
View File
@@ -1,6 +1,5 @@
{- | Actions performed by creatures within the world {- | Actions performed by creatures within the world
-} -}
{-# LANGUAGE BangPatterns #-}
module Dodge.Creature.Action module Dodge.Creature.Action
( module Dodge.Creature.Action ( module Dodge.Creature.Action
, module Dodge.Creature.Action.UseItem , module Dodge.Creature.Action.UseItem
@@ -36,9 +35,9 @@ crStrafeLeft
-> Creature -> Creature
crStrafeLeft speed cr = advanceStepCounter s2 $ over crPos (+.+ p) cr crStrafeLeft speed cr = advanceStepCounter s2 $ over crPos (+.+ p) cr
where where
p = (*.*) s2 $ unitVectorAtAngle $ (_crDir cr + pi/2) p = s2 *.* unitVectorAtAngle (_crDir cr + pi/2)
equipFactor = product $ map equipSpeed $ IM.elems $ _crInv cr equipFactor = product $ map equipSpeed $ IM.elems $ _crInv cr
s2 = (speed * equipFactor) s2 = speed * equipFactor
crStrafeRight crStrafeRight
:: Float -- ^ Speed :: Float -- ^ Speed
@@ -46,9 +45,9 @@ crStrafeRight
-> Creature -> Creature
crStrafeRight speed cr = advanceStepCounter s2 $ over crPos (+.+ p) cr crStrafeRight speed cr = advanceStepCounter s2 $ over crPos (+.+ p) cr
where where
p = (*.*) s2 $ unitVectorAtAngle $ (_crDir cr - pi/2) p = s2 *.* unitVectorAtAngle (_crDir cr - pi/2)
equipFactor = product $ map equipSpeed $ IM.elems $ _crInv cr equipFactor = product $ map equipSpeed $ IM.elems $ _crInv cr
s2 = (speed * equipFactor) s2 = speed * equipFactor
turnTo turnTo
:: Point2 -- ^ Target point :: Point2 -- ^ Target point
@@ -239,7 +238,7 @@ blinkAction n w
cp = _crPos $ _creatures w IM.! n cp = _crPos $ _creatures w IM.! n
p2 = reflectPointWalls cp p1 $ wallsAlongLine cp p1 w p2 = reflectPointWalls cp p1 $ wallsAlongLine cp p1 w
r = 1.5 * _crRad (_creatures w IM.! n) r = 1.5 * _crRad (_creatures w IM.! n)
p3 = fromMaybe p1 (fmap ((\p -> moveAmountToward p r cp) . fst) p2) p3 = maybe p1 ((\p -> moveAmountToward p r cp) . fst) p2
blinkShockwave blinkShockwave
:: Int -- ^ Blinking creature ID. :: Int -- ^ Blinking creature ID.
@@ -317,7 +316,6 @@ pickUpItem cid flit w = case maybeInvSlot of
updateItLocation invid w' = case _itID it of updateItLocation invid w' = case _itID it of
Nothing -> w' Nothing -> w'
Just j -> w' & itemPositions . ix j .~ InInv 0 invid Just j -> w' & itemPositions . ix j .~ InInv 0 invid
{- | Creature attempts to moves under its own steam. {- | Creature attempts to moves under its own steam.
The idea is that this may or may not work, depending on the status of the creature. The idea is that this may or may not work, depending on the status of the creature.
For now, though, this cannot fail. -} For now, though, this cannot fail. -}
@@ -329,8 +327,8 @@ crMvBy p' cr = advanceStepCounter (magV p) $ over crPos (+.+ p) cr
where where
p = (*.*) (equipFactor * aimingFactor) $ rotateV (_crDir cr) p' p = (*.*) (equipFactor * aimingFactor) $ rotateV (_crDir cr) p'
equipFactor = product $ map equipSpeed $ IM.elems $ _crInv cr equipFactor = product $ map equipSpeed $ IM.elems $ _crInv cr
aimingFactor | (_posture $ _crStance cr) == Aiming aimingFactor
= fromMaybe 1 $ it ^? itAimingSpeed | _posture (_crStance cr) == Aiming = fromMaybe 1 $ it ^? itAimingSpeed
| otherwise = 1 | otherwise = 1
it = _crInv cr IM.! _crInvSel cr it = _crInv cr IM.! _crInvSel cr
@@ -338,16 +336,15 @@ crMvForward
:: Float -- ^ Speed :: Float -- ^ Speed
-> Creature -> Creature
-> Creature -> Creature
crMvForward speed cr = crMvBy (speed,0) cr crMvForward speed = crMvBy (speed,0)
advanceStepCounter advanceStepCounter
:: Float -- ^ Speed :: Float -- ^ Speed
-> Creature -> Creature
-> Creature -> Creature
advanceStepCounter speed cr = over (crStance . carriage) f cr advanceStepCounter speed = crStance . carriage %~ f
where where
f (w@Walking {}) = w {_stepToAdd = ceiling speed} f w@Walking{} = w{_stepToAdd = ceiling speed}
f s = s f s = s
creatureTurn :: Float -> Creature -> Creature creatureTurn :: Float -> Creature -> Creature
+1 -1
View File
@@ -9,7 +9,7 @@ import Control.Lens
strafeTo :: Float -> Point2 -> Int -> World -> World strafeTo :: Float -> Point2 -> Int -> World -> World
strafeTo speed targPos cid w = over (creatures . ix cid . crPos) (+.+ q) w strafeTo speed targPos cid w = over (creatures . ix cid . crPos) (+.+ q) w
where q = (*.*) (speed * equipFactor * wpFactor) where q = (*.*) (speed * equipFactor * wpFactor)
$ safeNormalizeV $ (targPos -.- _crPos cr) $ safeNormalizeV $ targPos -.- _crPos cr
equipFactor = product $ map equipSpeed $ IM.elems $ _crInv $ _creatures w IM.! cid equipFactor = product $ map equipSpeed $ IM.elems $ _crInv $ _creatures w IM.! cid
cr = _creatures w IM.! cid cr = _creatures w IM.! cid
wpFactor = _itAimingSpeed (_crInv cr IM.! _crInvSel cr) wpFactor = _itAimingSpeed (_crInv cr IM.! _crInvSel cr)
+8 -11
View File
@@ -7,10 +7,13 @@ import Dodge.Inventory
import qualified Data.IntMap as IM import qualified Data.IntMap as IM
import Control.Lens import Control.Lens
import Data.Maybe (fromMaybe) import Data.Maybe (maybe)
useItem :: Int -> World -> World useItem :: Int -> World -> World
useItem n w = equippedItemEffect n w useItem n w = itemEffect n it w
where
c = _creatures w IM.! n
it = _crInv c IM.! _crInvSel c
crUseItem :: Creature -> World -> World crUseItem :: Creature -> World -> World
--crUseItem cr = itemEffect (_crID cr) (_crInv cr IM.! _crInvSel cr) --crUseItem cr = itemEffect (_crID cr) (_crInv cr IM.! _crInvSel cr)
@@ -24,18 +27,12 @@ tryUseItem cid w = case w ^? creatures . ix cid of
Just cr -> itemEffect cid (_crInv cr IM.! _crInvSel cr) w Just cr -> itemEffect cid (_crInv cr IM.! _crInvSel cr) w
Nothing -> w Nothing -> w
equippedItemEffect :: Int -> World -> World
equippedItemEffect n w = itemEffect n it w
where
c = _creatures w IM.! n
it = _crInv c IM.! _crInvSel c
itemEffect itemEffect
:: Int -- ^ Creature id (I am almost certain) :: Int -- ^ Creature id (I am almost certain)
-> Item -> Item
-> World -> World
-> World -> World
itemEffect n (Consumable {_cnEffect=eff }) w = fromMaybe w $ rmSelectedInvItem n <$> eff n w itemEffect n Consumable{_cnEffect=eff } w = maybe w (rmSelectedInvItem n) (eff n w)
itemEffect n (Weapon {_wpFire=eff}) w = eff n w itemEffect n Weapon{_wpFire=eff} w = eff n w
itemEffect n (Throwable {_twFire = eff}) w = eff n w itemEffect n Throwable{_twFire = eff} w = eff n w
itemEffect _ _ w = w itemEffect _ _ w = w
+3 -4
View File
@@ -20,7 +20,6 @@ import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.Base.Collide import Dodge.Base.Collide
import Dodge.Creature.ChooseTarget import Dodge.Creature.ChooseTarget
import Dodge.Creature.Rationality.Data
import Dodge.Creature.Stance.Data import Dodge.Creature.Stance.Data
import Dodge.Creature.Test import Dodge.Creature.Test
import Geometry import Geometry
@@ -216,7 +215,7 @@ applyNewStrategies
applyNewStrategies w cr = case cr ^? crActionPlan . crStrategy of applyNewStrategies w cr = case cr ^? crActionPlan . crStrategy of
Just (StrategyActions strat acs) -> cr & crActionPlan . crAction .~ acs Just (StrategyActions strat acs) -> cr & crActionPlan . crAction .~ acs
& crActionPlan . crStrategy .~ strat & crActionPlan . crStrategy .~ strat
otherwise -> cr _ -> cr
doStrategyActions doStrategyActions
:: World :: World
@@ -225,7 +224,7 @@ doStrategyActions
doStrategyActions w cr = case cr ^? crActionPlan . crStrategy of doStrategyActions w cr = case cr ^? crActionPlan . crStrategy of
Just (StrategyActions strat acs) -> cr & crActionPlan . crAction .~ acs Just (StrategyActions strat acs) -> cr & crActionPlan . crAction .~ acs
& crActionPlan . crStrategy .~ strat & crActionPlan . crStrategy .~ strat
otherwise -> cr _ -> cr
updateShoot updateShoot
:: World :: World
@@ -270,7 +269,7 @@ watchUpdateStrat
-> Creature -> Creature
watchUpdateStrat fs w cr = case cr ^? crActionPlan . crStrategy of watchUpdateStrat fs w cr = case cr ^? crActionPlan . crStrategy of
Just WatchAndWait -> cr Just WatchAndWait -> cr
& crActionPlan . crStrategy .~ listGuard (fs, (\_ _ -> WatchAndWait)) (w, cr) w cr & crActionPlan . crStrategy .~ listGuard (fs, \_ _ -> WatchAndWait) (w, cr) w cr
_ -> cr _ -> cr
listGuard :: ([(a -> Bool, b)] , b) -> a -> b listGuard :: ([(a -> Bool, b)] , b) -> a -> b
+14 -6
View File
@@ -3,11 +3,12 @@ module Dodge.Creature.AlertLevel
where where
import Dodge.Data import Dodge.Data
import Dodge.Creature.AlertLevel.Data import Dodge.Creature.AlertLevel.Data
import Dodge.Base.Collide import Dodge.Base
--import Dodge.Base.Collide
import Control.Lens import Control.Lens
import Control.Monad.Reader
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
{- | Ties together (currently) an awareness and attention update -} {- | Ties together (currently) an awareness and attention update -}
basicPerceptionUpdate basicPerceptionUpdate
:: [Int] -- ^ List of creature ids that may direct attention and awareness :: [Int] -- ^ List of creature ids that may direct attention and awareness
@@ -15,13 +16,20 @@ basicPerceptionUpdate
-> Creature -> Creature
-> Creature -> Creature
basicPerceptionUpdate is w cr basicPerceptionUpdate is w cr
= basicAwarenessUpdate w $ = basicAwarenessUpdate w $ basicAttentionUpdate is w cr
basicAttentionUpdate is w cr
basicPerceptionUpdateR
:: [Int] -- ^ List of creature ids that may direct attention and awareness
-> Creature
-> Reader World Creature
basicPerceptionUpdateR is cr = reader $ \w ->
basicAwarenessUpdate w $ basicAttentionUpdate is w cr
{- | Update a creatures awareness based upon the creatures current direction {- | Update a creatures awareness based upon the creatures current direction
of attention -} of attention -}
basicAwarenessUpdate basicAwarenessUpdate
:: World -> Creature -> Creature :: World -> Creature -> Creature
basicAwarenessUpdate w cr = case _crAttentionDir cr of basicAwarenessUpdate _ cr = case _crAttentionDir cr of
AttentiveTo is -> cr & crAwarenessLevel %~ updateAwareness is AttentiveTo is -> cr & crAwarenessLevel %~ updateAwareness is
Fixated i -> cr & crAwarenessLevel Fixated i -> cr & crAwarenessLevel
%~ ( IM.insert i (Cognizant 100) . IM.mapMaybe decreaseAwareness) %~ ( IM.insert i (Cognizant 100) . IM.mapMaybe decreaseAwareness)
@@ -54,4 +62,4 @@ basicAttentionUpdate
-> Creature -> Creature
-> Creature -> Creature
basicAttentionUpdate cids w cr = cr & crAttentionDir .~ basicAttentionUpdate cids w cr = cr & crAttentionDir .~
AttentiveTo (filter (\cid -> canSee (_crID cr) cid w) cids) AttentiveTo (forceList $ filter (\cid -> canSee (_crID cr) cid w) cids)
+7 -2
View File
@@ -1,5 +1,8 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StrictData #-}
module Dodge.Creature.AlertLevel.Data module Dodge.Creature.AlertLevel.Data
where where
import Control.Lens
data AwakeLevel data AwakeLevel
= Comatose = Comatose
@@ -9,9 +12,11 @@ data AwakeLevel
| Overstrung | Overstrung
data AttentionDir data AttentionDir
= AttentiveTo [Int] = AttentiveTo {_unAttentiveTo :: [Int]}
| Fixated Int | Fixated {_unFixated :: Int }
data AwarenessLevel data AwarenessLevel
= AwarenessInt Int = AwarenessInt Int
| Cognizant Int | Cognizant Int
makeLenses ''AttentionDir
-5
View File
@@ -1,5 +0,0 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StrictData #-}
module Dodge.Creature.Data
where
import Control.Lens
-58
View File
@@ -1,58 +0,0 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StrictData #-}
module Dodge.Creature.Impulse.Data
where
import Dodge.Creature.Stance.Data
import Geometry.Data
import Control.Lens
data Impulse
= MoveTo Point2
| MoveToFor Point2 Int
| MoveFire Point2 Point2
| PathTo Point2
| PathAlong [Point2]
| SubPathTo Point2 Int Point2
| Wait
| WaitFor Int
| WaitForID Int Int
| FireAt Point2
| FireAtID Int Point2
| Fire
| Reload
| IncreaseAlert Int
| Guard Point2 Point2
| Search Int
| SearchNear Point2
| AimAt Point2 Int
| InitGuard
| Init
| MeleeAttack Int
| InitTrackYou
| TrackYou
| Track Int
| TrackFor Int Int
| TurnByFor Float Int
| TurnTo Point2
| TurnToward Point2
| TurnTowardAngle Float
| StrafeLeftAround Int Point2
| StrafeRightAround Int Point2
| StrafeLeftFor Int
| StrafeRightFor Int
| StrafeLeftForSpeed Int Float
| StrafeRightForSpeed Int Float
| StrafeLeftFire
| StrafeRightFire
| MoveForwardFor Int
| MoveForwardFire
| MoveBackwardFor Int
| MoveByFor Point2 Int
| MoveBackwardFire
| ImpulseID Int Impulse
| AtRange Float
| AtRanges Float Float
| RepeatAction Int Impulse
| MakeJudgement
| SetPosture Posture
deriving (Eq,Show)
+58 -15
View File
@@ -4,23 +4,22 @@ import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.Creature.ChooseTarget import Dodge.Creature.ChooseTarget
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Dodge.Creature.Rationality.Data
import Geometry import Geometry
import qualified Data.IntMap as IM import qualified Data.IntMap as IM
import Control.Lens import Control.Lens
import Control.Monad.Reader
encircle :: Creature -> IM.IntMap Creature -> Creature -> Point2 encircle :: Creature -> IM.IntMap Creature -> Creature -> Point2
encircle tcr crs cr encircle tcr crs cr
| length crs <= 1 = ypos | length crs <= 1 = ypos
| otherwise = ypos +.+ f (max 0 (magV (ypos -.- cenp) - 30) ) *.* safeNormalizeV (cpos -.- cenp) | otherwise = ypos +.+ f (max 0 (magV (ypos -.- cenp) - 80) ) *.* safeNormalizeV (cpos -.- cenp)
where where
cpos = _crPos cr cpos = _crPos cr
ypos = _crPos tcr ypos = _crPos tcr
f x = 150 * sigmoid (x-10) f x = 150 * sigmoid (x-10)
cenp = (1 / fromIntegral (length crs)) *.* foldr1 (+.+) (map _crPos $ IM.elems crs) cenp = (1 / fromIntegral (length crs)) *.* foldr1 (+.+) (map _crPos $ IM.elems crs)
lineOrth :: Creature -> IM.IntMap Creature -> Creature -> Point2 lineOrth :: Creature -> IM.IntMap Creature -> Creature -> Point2
lineOrth tcr crs cr = p lineOrth tcr crs cr = p
where where
@@ -64,6 +63,19 @@ spreadOut ycr crs cr = p
| dist ypos cpos > 90 = 1 | dist ypos cpos > 90 = 1
| otherwise = 1.5 | otherwise = 1.5
swarmUsingCenter
:: (Creature -> Point2 -> Creature -> Creature)
-> (Point2 -> Creature -> Creature)
-> World
-> Creature
-> Creature
swarmUsingCenter updT upd w cr = case _crTarget cr of
Nothing -> upd cenp cr
Just tcr -> updT tcr cenp cr
where
cid = _crID cr
cenp = _crGroupCenter $ _creatureGroups w IM.! (_crGroupID $ _crGroup $ _creatures w IM.! cid)
flockChaseTarget flockChaseTarget
:: (Creature -> IM.IntMap Creature -> Creature -> Creature) -- ^ Update with target :: (Creature -> IM.IntMap Creature -> Creature -> Creature) -- ^ Update with target
-> (IM.IntMap Creature -> Creature -> Creature) -- ^ Update without target -> (IM.IntMap Creature -> Creature -> Creature) -- ^ Update without target
@@ -100,16 +112,51 @@ chaseTarget targFunc w cr = case targFunc cr w of
Nothing -> cr Nothing -> cr
Just crTarg -> cr & crActionPlan . crImpulse .~ chaseTarg cr crTarg Just crTarg -> cr & crActionPlan . crImpulse .~ chaseTarg cr crTarg
chaseTargetR
:: (Creature -> World -> Maybe Creature) -- ^ Function for determining target
-> Creature
-> Reader World Creature
chaseTargetR targFunc cr = reader $ \w -> case targFunc cr w of
Nothing -> cr
Just crTarg -> cr & crActionPlan . crImpulse .~ chaseTarg cr crTarg
overrideMeleeCloseTarget :: World -> Creature -> Creature
overrideMeleeCloseTarget w cr = case _crTarget cr of
Nothing -> cr
Just tcr
| _crMeleeCooldown cr == Just 0
&& dist (_crPos tcr) cpos < _crRad cr + _crRad tcr + 5
&& abs (_crDir cr - argV (_crPos tcr -.- cpos)) < pi/4
-> cr & crActionPlan . crStrategy .~ StrategyActions MeleeStrike [DoImpulses [Melee (_crID tcr)]]
| otherwise -> cr
where
cpos = _crPos cr
overrideMeleeCloseTargetR
:: Creature
-> Reader World Creature
overrideMeleeCloseTargetR cr = reader $ \w -> case _crTarget cr of
Nothing -> cr
Just tcr
| _crMeleeCooldown cr == Just 0
&& dist (_crPos tcr) cpos < _crRad cr + _crRad tcr + 5
&& abs (_crDir cr - argV (_crPos tcr -.- cpos)) < pi/4
-> cr & crActionPlan . crStrategy .~ StrategyActions MeleeStrike [DoImpulses [Melee (_crID tcr)]]
| otherwise -> cr
where
cpos = _crPos cr
chaseTarg' :: Point2 -> Creature -> Creature -> [Impulse] chaseTarg' :: Point2 -> Creature -> Creature -> [Impulse]
chaseTarg' p cr crT chaseTarg' p cr crT
| dist tpos cpos < combinedRad + 5 | dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4 && abs (_crDir cr - argV (tpos -.- cpos)) < pi/4
&& _crMeleeCooldown cr == Just 0 && _crMeleeCooldown cr == Just 0
= [Melee (_crID crT)] = [Melee (_crID crT)]
| dist tpos cpos < combinedRad + 5 | dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4 && abs (_crDir cr - argV (tpos -.- cpos)) < pi/4
= [ TurnToward tpos 0.05 ] = [ TurnToward tpos 0.05 ]
| abs ((_crDir cr) - argV (p -.- cpos)) < pi/4 | abs (_crDir cr - argV (p -.- cpos)) < pi/4
= [MoveForward 2.5 , TurnToward p 0.2 , RandomTurn 0.2 ] = [MoveForward 2.5 , TurnToward p 0.2 , RandomTurn 0.2 ]
| otherwise = [MoveForward 2.5 , TurnToward p 0.05, RandomTurn 0.2 ] | otherwise = [MoveForward 2.5 , TurnToward p 0.05, RandomTurn 0.2 ]
where where
@@ -120,13 +167,9 @@ chaseTarg' p cr crT
chaseTarg :: Creature -> Creature -> [Impulse] chaseTarg :: Creature -> Creature -> [Impulse]
chaseTarg cr crT chaseTarg cr crT
| dist tpos cpos < combinedRad + 5 | dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4 && abs (_crDir cr - argV (tpos -.- cpos)) < pi/4
&& _crMeleeCooldown cr == Just 0
= [Melee (_crID crT)]
| dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4
= [ TurnToward tpos 0.05 ] = [ TurnToward tpos 0.05 ]
| abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4 | abs (_crDir cr - argV (tpos -.- cpos)) < pi/4
= [MoveForward 2.5 , TurnToward tpos 0.2, RandomTurn 0.2 ] = [MoveForward 2.5 , TurnToward tpos 0.2, RandomTurn 0.2 ]
| otherwise = [MoveForward 2.5 , TurnToward tpos 0.05, RandomTurn 0.2 ] | otherwise = [MoveForward 2.5 , TurnToward tpos 0.05, RandomTurn 0.2 ]
where where
@@ -146,13 +189,13 @@ impulseShootAtTarget targFunc w cr = case targFunc cr w of
impulseShootAtTarg :: Creature -> Creature -> [Impulse] impulseShootAtTarg :: Creature -> Creature -> [Impulse]
impulseShootAtTarg cr crT impulseShootAtTarg cr crT
| dist tpos cpos < combinedRad + 5 | dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4 && abs (_crDir cr - argV (tpos -.- cpos)) < pi/4
&& _crMeleeCooldown cr == Just 0 && _crMeleeCooldown cr == Just 0
= [Melee (_crID crT)] = [Melee (_crID crT)]
| dist tpos cpos < combinedRad + 5 | dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4 && abs (_crDir cr - argV (tpos -.- cpos)) < pi/4
= [ TurnToward tpos 0.05 ] = [ TurnToward tpos 0.05 ]
| abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4 | abs (_crDir cr - argV (tpos -.- cpos)) < pi/4
= [MoveForward 2.5 , TurnToward tpos 0.2, RandomTurn 0.2 ] = [MoveForward 2.5 , TurnToward tpos 0.2, RandomTurn 0.2 ]
| otherwise = [MoveForward 2.5 , TurnToward tpos 0.05, RandomTurn 0.2 ] | otherwise = [MoveForward 2.5 , TurnToward tpos 0.05, RandomTurn 0.2 ]
where where
+2 -5
View File
@@ -6,7 +6,6 @@ module Dodge.Creature.Inanimate
import Dodge.Data import Dodge.Data
import Dodge.Creature.Stance.Data import Dodge.Creature.Stance.Data
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Dodge.Creature.Impulse.Data
import Dodge.Base import Dodge.Base
import Dodge.Picture.Layer import Dodge.Picture.Layer
import Dodge.Default import Dodge.Default
@@ -59,8 +58,7 @@ barrel = defaultInanimate
, color (greyN 0.5) $ circleSolid 8 , color (greyN 0.5) $ circleSolid 8
] ]
, _crState = defaultState , _crState = defaultState
{_goals = [[Wait]] {_crSpState = Barrel []
,_crSpState = Barrel []
} }
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)] , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
} }
@@ -74,8 +72,7 @@ explosiveBarrel = defaultInanimate
, color orange $ circleSolid 10 , color orange $ circleSolid 10
] ]
, _crState = defaultState , _crState = defaultState
{_goals = [[Wait]] {_crSpState = Barrel []
,_crSpState = Barrel []
} }
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)] , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
,_crApplyDamage = \_ c -> (id, c) ,_crApplyDamage = \_ c -> (id, c)
+2 -2
View File
@@ -52,7 +52,7 @@ launcherCrit = defaultCreature
} }
retreatFire :: Action retreatFire :: Action
retreatFire = ImpulsesList ( [ [ UseItem ] ] ++ replicate 20 [ Turn 0.16 ]) retreatFire = ImpulsesList ( [ UseItem ] : replicate 20 [ Turn 0.16 ])
`DoActionThen` `DoActionThen`
HolsterWeapon HolsterWeapon
`DoActionThen` `DoActionThen`
@@ -60,7 +60,7 @@ retreatFire = ImpulsesList ( [ [ UseItem ] ] ++ replicate 20 [ Turn 0.16 ])
`DoActionThen` `DoActionThen`
DrawWeapon DrawWeapon
`DoActionThen` `DoActionThen`
ImpulsesList ( [[UseItem]] ++ replicate 20 [ Turn $ negate 0.16 ] ) ImpulsesList ( [UseItem] : replicate 20 [ Turn $ negate 0.16 ] )
`DoActionThen` `DoActionThen`
HolsterWeapon HolsterWeapon
`DoActionThen` `DoActionThen`
+1 -1
View File
@@ -72,4 +72,4 @@ chooseMovement cr w
tcr = _creatures w IM.! 0 tcr = _creatures w IM.! 0
p = _crPos tcr p = _crPos tcr
v = vNormal $ p -.- cpos v = vNormal $ p -.- cpos
p' = p +.+ 0.5 *.* (v -.- 20 *.* (normalizeV v)) p' = p +.+ 0.5 *.* (v -.- 20 *.* normalizeV v)
+3 -3
View File
@@ -33,17 +33,17 @@ basicCrPict col cr = pictures
| pdam > 99 = color white $ circleSolid $ _crRad cr | pdam > 99 = color white $ circleSolid $ _crRad cr
| otherwise = pictures [color col' $ circleSolid $ _crRad cr, circLine $ _crRad cr] | otherwise = pictures [color col' $ circleSolid $ _crRad cr, circLine $ _crRad cr]
pastDams = _crPastDamage $ _crState cr pastDams = _crPastDamage $ _crState cr
pdam = sum $ concatMap (map _dmAmount) $ pastDams pdam = sum $ concatMap (map _dmAmount) pastDams
col' = light . light . light $ light col col' = light . light . light $ light col
bluntDam :: Maybe Point2 bluntDam :: Maybe Point2
bluntDam = find isBluntDam (concat pastDams) >>= (\dm -> (-.-) <$> dm ^? dmFrom <*> dm ^? dmTo) bluntDam = find isBluntDam (concat pastDams) >>= (\dm -> (-.-) <$> dm ^? dmFrom <*> dm ^? dmTo)
bluntScale = case fmap argV bluntDam of bluntScale = case fmap argV bluntDam of
Just a -> rotate (a + cdir) . scale 0.8 1.2 . rotate (negate $ cdir + a) Just a -> rotate (a + cdir) . scale 0.8 1.2 . rotate (negate $ cdir + a)
_ -> id _ -> id
isBluntDam (Blunt {}) = True isBluntDam Blunt{} = True
isBluntDam _ = False isBluntDam _ = False
piercingDam = find isPiercingDam (concat pastDams) >>= (\dm -> (-.-) <$> dm ^? dmFrom <*> dm ^? dmTo) piercingDam = find isPiercingDam (concat pastDams) >>= (\dm -> (-.-) <$> dm ^? dmFrom <*> dm ^? dmTo)
isPiercingDam (Piercing {}) = True isPiercingDam Piercing{} = True
isPiercingDam _ = False isPiercingDam _ = False
piercingMod = case fmap argV piercingDam of piercingMod = case fmap argV piercingDam of
Just a -> rotate (a + cdir) . scale 0.8 1.2 . rotate (negate $ cdir + a) Just a -> rotate (a + cdir) . scale 0.8 1.2 . rotate (negate $ cdir + a)
+2 -2
View File
@@ -93,8 +93,8 @@ chooseMovement' cr w = takeOneWeighted [chargeProb,retreatProb,strafeProb,strafe
3 3
`DoReplicate` `DoReplicate`
ImpulsesList (replicate 9 [Move (0,-3)] ++ [[Move (0,-3),UseItem]]) ImpulsesList (replicate 9 [Move (0,-3)] ++ [[Move (0,-3),UseItem]])
yposl = ypos -.- 100 *.* (vNormal $ normalizeV $ ypos -.- cpos) yposl = ypos -.- 100 *.* vNormal (normalizeV $ ypos -.- cpos)
yposr = ypos +.+ 100 *.* (vNormal $ normalizeV $ ypos -.- cpos) yposr = ypos +.+ 100 *.* vNormal (normalizeV $ ypos -.- cpos)
retreatActions :: Creature -> Creature -> Action retreatActions :: Creature -> Creature -> Action
retreatActions tcr cr = retreatActions tcr cr =
+28 -2
View File
@@ -2,7 +2,6 @@ module Dodge.Creature.Rationality
where where
import Dodge.Data import Dodge.Data
import Dodge.Base.Collide import Dodge.Base.Collide
import Dodge.Creature.Rationality.Data
import Dodge.Creature.Action import Dodge.Creature.Action
import Dodge.Creature.Action.UseItem import Dodge.Creature.Action.UseItem
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
@@ -14,6 +13,7 @@ import Data.Maybe
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import System.Random import System.Random
import Control.Lens import Control.Lens
import Control.Monad.Reader
-- Alternatives would probably be a very good fit for actions... -- Alternatives would probably be a very good fit for actions...
@@ -24,6 +24,14 @@ composeInternalAIs
-> Creature -> Creature
composeInternalAIs fs w c = foldr ($ w) c fs composeInternalAIs fs w c = foldr ($ w) c fs
impulsiveAIR
:: (Creature -> Reader World Creature)
-> World
-> (World -> World, StdGen)
-> Creature
-> ((World -> World, StdGen) , Maybe Creature)
impulsiveAIR impf w (f,g) cr = followImpulses w (f,g) . ($ w) . runReader . impf $ cr
impulsiveAI impulsiveAI
:: (World -> Creature -> Creature) -- ^ Internal AI update, should determine impulses :: (World -> Creature -> Creature) -- ^ Internal AI update, should determine impulses
-> World -> World
@@ -84,7 +92,7 @@ followImpulse cr w imp = case imp of
rr a = fst $ randomR (-a,a) $ _randGen w rr a = fst $ randomR (-a,a) $ _randGen w
hitCr i = over (creatures . ix i . crState . crDamage) (addDam i) hitCr i = over (creatures . ix i . crState . crDamage) (addDam i)
. soundOnce (fromIntegral hitSound) . soundOnce (fromIntegral hitSound)
addDam i dams = (( Blunt 100 cpos (posFromID i) (posFromID i) ) : dams ) addDam i dams = Blunt 100 cpos (posFromID i) (posFromID i) : dams
actionUpdateAI actionUpdateAI
:: (World -> Creature -> Creature) -- ^ the function updating the actions :: (World -> Creature -> Creature) -- ^ the function updating the actions
@@ -93,6 +101,24 @@ actionUpdateAI
-> Creature -> Creature
actionUpdateAI actF w c = performActions w $ actF w c actionUpdateAI actF w c = performActions w $ actF w c
performActionR :: Creature -> Reader World Creature
performActionR cr = reader $ \w -> performActions w cr
watchUpdateStratR
:: [ ((World, Creature) -> Bool, World -> Creature -> Strategy) ]
-> Creature
-> Reader World Creature
watchUpdateStratR fs cr = case cr ^? crActionPlan . crStrategy of
Just WatchAndWait -> reader $ \w -> cr
& crActionPlan . crStrategy .~ listGuard (fs, \_ _ -> WatchAndWait) (w, cr) w cr
_ -> reader $ \_ -> cr
listGuard :: ([(a -> Bool, b)] , b) -> a -> b
listGuard ( (test,y):ps, z ) x
| test x = y
| otherwise = listGuard (ps, z) x
listGuard (_,z) _ = z
performActions :: World -> Creature -> Creature performActions :: World -> Creature -> Creature
performActions w cr = cr performActions w cr = cr
& crActionPlan . crImpulse .~ concat iss & crActionPlan . crImpulse .~ concat iss
-8
View File
@@ -1,8 +0,0 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StrictData #-}
module Dodge.Creature.Rationality.Data
where
import Dodge.Creature.Stance.Data
import Geometry.Data
import Control.Lens
+2 -1
View File
@@ -8,10 +8,11 @@ import Dodge.Creature.AlertLevel.Data
import Control.Lens import Control.Lens
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
{- | Assumes that you are id 0: if creature is cognizant of you, sets you as target -}
targetYouWhenCognizant targetYouWhenCognizant
:: World :: World
-> Creature -> Creature
-> Creature -> Creature
targetYouWhenCognizant w cr = case cr ^? crAwarenessLevel . ix 0 of targetYouWhenCognizant w cr = case cr ^? crAwarenessLevel . ix 0 of
Just (Cognizant _) -> cr & crTarget .~ Just (_creatures w IM.! 0) Just (Cognizant _) -> cr & crTarget ?~ _creatures w IM.! 0
_ -> cr & crTarget .~ Nothing _ -> cr & crTarget .~ Nothing
+26 -43
View File
@@ -2,7 +2,6 @@ module Dodge.Creature.State where
import Dodge.Data import Dodge.Data
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Dodge.Creature.Stance.Data import Dodge.Creature.Stance.Data
import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.SoundLogic import Dodge.SoundLogic
import Dodge.RandomHelp import Dodge.RandomHelp
@@ -16,16 +15,11 @@ import Data.List
import Data.Char import Data.Char
import Data.Maybe import Data.Maybe
import Data.Function import Data.Function
--import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Data.Graph.Inductive.Query.SP
import Codec.BMP
import qualified Data.ByteString as B
import Control.Lens import Control.Lens
import Control.Applicative import Control.Applicative
import Control.Monad.State import Control.Monad.State
import Control.Monad import Control.Monad
import qualified SDL as SDL import qualified SDL
import qualified SDL.Mixer as Mix import qualified SDL.Mixer as Mix
import System.Random import System.Random
import qualified Data.Set as S import qualified Data.Set as S
@@ -38,7 +32,6 @@ type CRUpdate = World -> (World -> World,StdGen) -> Creature -> ((World -> World
meleeCooldown :: CRUpdate -> CRUpdate meleeCooldown :: CRUpdate -> CRUpdate
meleeCooldown u w (f,g) cr = u w (f,g) $ cr & crMeleeCooldown . _Just %~ (max 0 . (\x -> x - 1)) meleeCooldown u w (f,g) cr = u w (f,g) $ cr & crMeleeCooldown . _Just %~ (max 0 . (\x -> x - 1))
-- | The movement is updated before the ai in order to correctly set the oldpos. -- | The movement is updated before the ai in order to correctly set the oldpos.
-- the whole of this update cycle could do with a rethink, it is becoming -- the whole of this update cycle could do with a rethink, it is becoming
-- convoluted -- convoluted
@@ -46,10 +39,10 @@ stateUpdate :: CRUpdate -> CRUpdate
stateUpdate u w (f,g) cr = stateUpdate u w (f,g) cr =
let (cr', g'') = updateMovement g cr let (cr', g'') = updateMovement g cr
in case u w (f,g'') cr' of in case u w (f,g'') cr' of
((f',g') , maybeCr) -> ( (invSideEff cr . movementSideEff cr . deathEff . f' ((f',g') , maybeCr) ->
( (invSideEff cr . movementSideEff cr . deathEff . f'
, g') , g')
, fmap (updateReloadCounter . doDamage . crAutoReload) , fmap (updateReloadCounter . doDamage . crAutoReload) $ crOrCorpse =<< maybeCr
$ crOrCorpse =<< maybeCr
) )
where where
crOrCorpse cr crOrCorpse cr
@@ -60,11 +53,11 @@ stateUpdate u w (f,g) cr =
| otherwise = stopSoundFrom (CrWeaponSound (_crID cr)) | otherwise = stopSoundFrom (CrWeaponSound (_crID cr))
. over decorations addCorpse . over decorations addCorpse
. dropByState cr . dropByState cr
crBeforeDeath = colCrWall w $ cr crBeforeDeath = colCrWall w cr
addCorpse = insertNewKey $ uncurry translate (_crOldPos cr) addCorpse = insertNewKey
$ uncurry translate (_crOldPos cr)
$ rotate (_crDir cr) $ rotate (_crDir cr)
(_crCorpse cr) (_crCorpse cr)
-- | Drop items according to the creature state. -- | Drop items according to the creature state.
dropByState :: Creature -> World -> World dropByState :: Creature -> World -> World
dropByState cr w = foldr (copyItemToFloor cr) w is dropByState cr w = foldr (copyItemToFloor cr) w is
@@ -75,10 +68,8 @@ dropByState cr w = foldr (copyItemToFloor cr) w is
DropSpecific xs -> xs DropSpecific xs -> xs
DropAmount n -> take n $ evalState (shuffle $ IM.keys $ _crInv cr) (_randGen w) DropAmount n -> take n $ evalState (shuffle $ IM.keys $ _crInv cr) (_randGen w)
setOldPos :: Creature -> Creature setOldPos :: Creature -> Creature
setOldPos cr = set crOldPos (_crPos cr) cr setOldPos cr = set crOldPos (_crPos cr) cr
{- | {- |
Given a creature and a velocity, applies friction to that creature and evaluates a Given a creature and a velocity, applies friction to that creature and evaluates a
velocity to carry across frames. velocity to carry across frames.
@@ -86,17 +77,12 @@ velocity to carry across frames.
crFriction :: Creature -> Point2 -> Point2 crFriction :: Creature -> Point2 -> Point2
crFriction cr vel = (0,0) crFriction cr vel = (0,0)
{- | In order to force a list, apply with seq. -}
forceSpine :: [a] -> ()
forceSpine = foldr (const id) ()
doDamage :: Creature -> Creature doDamage :: Creature -> Creature
doDamage cr = set (crState . crDamage) [] doDamage cr = set (crState . crDamage) []
$ over (crState . crPastDamage) (f . take 20 . (dams :) ) damagedCr $ over (crState . crPastDamage) (forceList . take 20 . (dams :) ) damagedCr
where where
f l = seq (forceSpine l) l
dams = _crDamage $ _crState cr dams = _crDamage $ _crState cr
damagedCr = snd $ (_crApplyDamage cr) dams cr damagedCr = snd $ _crApplyDamage cr dams cr
sumDamage :: Creature -> DamageType -> Int -> Int sumDamage :: Creature -> DamageType -> Int -> Int
sumDamage cr dm x = x + _dmAmount dm sumDamage cr dm x = x + _dmAmount dm
@@ -107,7 +93,7 @@ movementSideEff cr w
= case cr ^? crStance . carriage of = case cr ^? crStance . carriage of
Just (Boosting v) Just (Boosting v)
-> makeFlameletTimed -> makeFlameletTimed
(oldPos +.+ (_crRad cr + 3) *.* (unitVectorAtAngle $ _crDir cr + pi)) (oldPos +.+ (_crRad cr + 3) *.* unitVectorAtAngle (_crDir cr + pi))
(momentum +.+ 1 *.* rotateV randDir (vInverse v)) (momentum +.+ 1 *.* rotateV randDir (vInverse v))
Nothing Nothing
1 1
@@ -128,9 +114,6 @@ movementSideEff cr w
(randDir,g) = randomR (-0.5,0.5) $ _randGen w (randDir,g) = randomR (-0.5,0.5) $ _randGen w
(randAng,_) = randomR (0,2*pi) $ _randGen w (randAng,_) = randomR (0,2*pi) $ _randGen w
(v1:v2:v3:_) = fst $ runState ((sequence . repeat . randInCirc) 0.1) $ _randGen w
(r1:r2:r3:_) = map ((*.*) 100) (v2:v3:v1:[])
crHasMoved = dist (_crPos cr) (_crOldPos cr) > 0.5 crHasMoved = dist (_crPos cr) (_crOldPos cr) > 0.5
takeStep x y | crHasMoved && x < 20 && x + y >= 20 = soundMultiFrom footor 22 3 0 takeStep x y | crHasMoved && x < 20 && x + y >= 20 = soundMultiFrom footor 22 3 0
| crHasMoved && x < 80 && x + y >= 80 = soundMultiFrom footor 23 3 0 | crHasMoved && x < 80 && x + y >= 80 = soundMultiFrom footor 23 3 0
@@ -139,15 +122,16 @@ movementSideEff cr w
invSideEff :: Creature -> World -> World invSideEff :: Creature -> World -> World
invSideEff cr w = weaponReloadSounds cr $ IM.foldrWithKey f w (_crInv cr) invSideEff cr w = weaponReloadSounds cr $ IM.foldrWithKey f w (_crInv cr)
where f i it w' = case it ^? itEffect . itInvEffect of where
f i it w' = case it ^? itEffect . itInvEffect of
Nothing -> w' Nothing -> w'
Just g -> g cr i w' Just g -> g cr i w'
weaponReloadSounds :: Creature -> World -> World weaponReloadSounds :: Creature -> World -> World
weaponReloadSounds cr w = case _crInv cr IM.!? _crInvSel cr of weaponReloadSounds cr w = case _crInv cr IM.!? _crInvSel cr of
Just (Weapon {_wpReloadState = 0}) -> w Just Weapon{_wpReloadState = 0} -> w
Just (Weapon {_wpReloadState = 1}) -> stopSoundFrom (CrReloadSound cid) w Just Weapon{_wpReloadState = 1} -> stopSoundFrom (CrReloadSound cid) w
Just (Weapon {}) -> soundFrom (CrReloadSound cid) reloadSound (1) 0 w Just Weapon{} -> soundFrom (CrReloadSound cid) reloadSound 1 0 w
_ -> w _ -> w
where where
cid = _crID cr cid = _crID cr
@@ -171,7 +155,7 @@ updateMovement g cr
isFrictionless :: Creature -> Bool isFrictionless :: Creature -> Bool
isFrictionless cr = case cr ^? crStance . carriage of isFrictionless cr = case cr ^? crStance . carriage of
Just (Boosting _) -> True Just (Boosting _) -> True
Just (Floating) -> True Just Floating -> True
_ -> False _ -> False
updateReloadCounter :: Creature -> Creature updateReloadCounter :: Creature -> Creature
@@ -212,12 +196,11 @@ updateExpBarrel w (f,g) cr
damages = _crDamage $ _crState cr damages = _crDamage $ _crState cr
pierceSparks :: [World -> World] pierceSparks :: [World -> World]
pierceSparks pierceSparks
= zipWith4 (\p a colid time-> (createBarrelSpark time colid (_crPos cr +.+ p) (a + argV p)) = zipWith4 (\p a -> createBarrelSpark (_crPos cr +.+ p) (a + argV p) (Just $ _crID cr))
(Just $ _crID cr)) poss as times colids
poss as colids times as = randomRs (-0.7,0.7) g
as = randomRs (-0.7,0.7) $ g colids = randomRs (0,11) g
colids = randomRs (0,11) $ g times = randomRs (2,5) g
times = randomRs (2,5) $ g
(g',_) = split g (g',_) = split g
poss = _piercedPoints $ _crSpState $ _crState cr poss = _piercedPoints $ _crSpState $ _crState cr
--newCr = Just $ doDamage $ applyFuseDamage cr -- $ foldr perforate cr damages --newCr = Just $ doDamage $ applyFuseDamage cr -- $ foldr perforate cr damages
@@ -229,7 +212,7 @@ updateExpBarrel w (f,g) cr
applyFuseDamage cr = over crHP (\hp -> hp - length (_piercedPoints applyFuseDamage cr = over crHP (\hp -> hp - length (_piercedPoints
$ _crSpState $ _crState cr)) $ _crSpState $ _crState cr))
cr cr
hiss | poss == [] = id hiss | null poss = id
| otherwise = soundMultiFrom [BarrelHiss 0,BarrelHiss 1] 41 50 1 | otherwise = soundMultiFrom [BarrelHiss 0,BarrelHiss 1] 41 50 1
stopSounds = stopSoundFrom (BarrelHiss 0) . stopSoundFrom (BarrelHiss 1) stopSounds = stopSoundFrom (BarrelHiss 0) . stopSoundFrom (BarrelHiss 1)
@@ -237,14 +220,14 @@ damToExpBarrel :: [DamageType] -> Creature -> Creature
damToExpBarrel ds cr = foldr damToExpBarrel' (foldr damToExpBarrel' cr pierceDam) otherDam damToExpBarrel ds cr = foldr damToExpBarrel' (foldr damToExpBarrel' cr pierceDam) otherDam
where where
(pierceDam,otherDam) = partition isPierce ds (pierceDam,otherDam) = partition isPierce ds
isPierce (Piercing {}) = True isPierce Piercing{} = True
isPierce _ = False isPierce _ = False
damToExpBarrel' :: DamageType -> Creature -> Creature damToExpBarrel' :: DamageType -> Creature -> Creature
damToExpBarrel' (Piercing amount sp int ep) cr damToExpBarrel' (Piercing amount sp int ep) cr
= over (crState . crSpState . piercedPoints) ((:) $ int -.- _crPos cr) = over (crState . crSpState . piercedPoints) ((:) $ int -.- _crPos cr)
$ over crHP (\hp -> hp - div amount 200) cr $ over crHP (\hp -> hp - div amount 200) cr
damToExpBarrel' (PoisonDam {}) cr = cr damToExpBarrel' PoisonDam {} cr = cr
damToExpBarrel' (SparkDam {}) cr = cr damToExpBarrel' SparkDam {} cr = cr
damToExpBarrel' (PushDam {_dmPushBack = v}) cr = cr Control.Lens.& crPos %~ (+.+) (1 / _crMass cr *.* v) damToExpBarrel' PushDam{_dmPushBack = v} cr = cr Control.Lens.& crPos %~ (+.+) (1 / _crMass cr *.* v)
damToExpBarrel' dt cr = cr Control.Lens.& crHP -~ _dmAmount dt damToExpBarrel' dt cr = cr Control.Lens.& crHP -~ _dmAmount dt
+6 -11
View File
@@ -4,31 +4,25 @@ module Dodge.Creature.State.Data
where where
import Geometry import Geometry
import Dodge.Data.DamageType import Dodge.Data.DamageType
import Dodge.Creature.Impulse.Data
import Dodge.Creature.Stance.Data import Dodge.Creature.Stance.Data
import Picture.Data import Picture.Data
import Control.Lens import Control.Lens
import qualified Data.IntSet as IS import qualified Data.IntSet as IS
data CreatureState = CrSt data CreatureState = CrSt
{ _goals :: [[Impulse]] { _crDamage :: [DamageType]
, _crDamage :: [DamageType]
, _crPastDamage :: [[DamageType]] , _crPastDamage :: [[DamageType]]
, _crSpState :: CrSpState , _crSpState :: CrSpState
, _crDropsOnDeath :: CreatureDropType , _crDropsOnDeath :: CreatureDropType
} }
data CreatureDropType data CreatureDropType
= DropAll = DropAll
| DropAmount Int | DropAmount Int
| DropSpecific [Int] | DropSpecific [Int]
data CrSpState data CrSpState
= Barrel { _piercedPoints :: [Point2]} = Barrel { _piercedPoints :: [Point2]}
| GenCr | GenCr
deriving (Eq,Show,Ord) deriving (Eq,Show,Ord)
data Faction data Faction
= GenericFaction Int = GenericFaction Int
| ZombieFaction | ZombieFaction
@@ -39,11 +33,12 @@ data Faction
| ColorFaction Color | ColorFaction Color
| PlayerFaction | PlayerFaction
deriving (Eq,Show) deriving (Eq,Show)
data CrGroup data CrGroup
= LoneWolf = LoneWolf
| Swarm { _swarm :: IS.IntSet } | Swarm
{ _swarm :: IS.IntSet
, _crGroupID :: Int
}
| CrGroupID { _crGroupID :: Int }
makeLenses ''CreatureState makeLenses ''CreatureState
makeLenses ''CrSpState makeLenses ''CrSpState
makeLenses ''Impulse
+4 -3
View File
@@ -32,14 +32,15 @@ swarmCrit = defaultCreature
{ _crUpdate = stateUpdate $ impulsiveAI $ composeInternalAIs { _crUpdate = stateUpdate $ impulsiveAI $ composeInternalAIs
[ flockPointTarget encircle targetYouLOS [ flockPointTarget encircle targetYouLOS
, \ _ -> crMeleeCooldown . _Just %~ (max 0 . subtract 1) , \ _ -> crMeleeCooldown . _Just %~ (max 0 . subtract 1)
, basicPerceptionUpdate [0]
-- , doStrategyActions
-- , targetYouWhenCognizant
] ]
, _crHP = 1 , _crHP = 1
, _crRad = 2 , _crRad = 2
, _crMass = 2
, _crPict = basicCrPict yellow , _crPict = basicCrPict yellow
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
, _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ circleSolid 2 , _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ circleSolid 2
, _crFaction = ColorFaction yellow , _crFaction = ColorFaction yellow
, _crMeleeCooldown = Just 0 , _crMeleeCooldown = Just 0
} }
+39
View File
@@ -16,6 +16,7 @@ import Data.List (find)
import Data.Maybe import Data.Maybe
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import Control.Lens import Control.Lens
import Control.Monad.Reader
andTest :: (a -> Bool) -> (a -> Bool) -> a -> Bool andTest :: (a -> Bool) -> (a -> Bool) -> a -> Bool
andTest f g a = f a && g a andTest f g a = f a && g a
@@ -28,31 +29,61 @@ crIsReloading (w,cr) = case cr ^? crInv . ix (_crInvSel cr) . wpReloadState of
Just t -> t > 0 Just t -> t > 0
_ -> False _ -> False
crIsReloadingR :: Creature -> Reader World Bool
crIsReloadingR cr = return $ case cr ^? crInv . ix (_crInvSel cr) . wpReloadState of
Just t -> t > 0
_ -> False
crCanSeeCr :: Creature -> (World, Creature) -> Bool crCanSeeCr :: Creature -> (World, Creature) -> Bool
crCanSeeCr tcr (w,cr) = hasLOS (_crPos cr) (_crPos tcr) w crCanSeeCr tcr (w,cr) = hasLOS (_crPos cr) (_crPos tcr) w
crCanSeeR :: Creature -> Creature -> Reader World Bool
crCanSeeR tcr cr = reader $ \w -> hasLOS (_crPos cr) (_crPos tcr) w
crCanSeeCID :: Int -> (World, Creature) -> Bool crCanSeeCID :: Int -> (World, Creature) -> Bool
crCanSeeCID cid (w,cr) = hasLOS (_crPos cr) (_crPos $ _creatures w IM.! cid) w crCanSeeCID cid (w,cr) = hasLOS (_crPos cr) (_crPos $ _creatures w IM.! cid) w
crCanSeeCIDR :: Int -> Creature -> Reader World Bool
crCanSeeCIDR cid cr = reader $ \w -> hasLOS (_crPos cr) (_crPos $ _creatures w IM.! cid) w
crIsAiming :: (World,Creature) -> Bool crIsAiming :: (World,Creature) -> Bool
crIsAiming (_,cr) = _posture (_crStance cr) == Aiming crIsAiming (_,cr) = _posture (_crStance cr) == Aiming
crIsAimingR :: Creature -> Reader World Bool
crIsAimingR cr = return $ _posture (_crStance cr) == Aiming
crHasTarget :: (World,Creature) -> Bool crHasTarget :: (World,Creature) -> Bool
crHasTarget (_,cr) = isJust $ cr ^? crTarget . _Just crHasTarget (_,cr) = isJust $ cr ^? crTarget . _Just
crHasTargetR :: Creature -> Reader World Bool
crHasTargetR cr = return $ isJust $ cr ^? crTarget . _Just
crHasTargetLOS :: (World,Creature) -> Bool crHasTargetLOS :: (World,Creature) -> Bool
crHasTargetLOS (w,cr) = case cr ^? crTarget . _Just of crHasTargetLOS (w,cr) = case cr ^? crTarget . _Just of
Just i -> crCanSeeCr i (w,cr) Just i -> crCanSeeCr i (w,cr)
Nothing -> False Nothing -> False
crHasTargetLOSR :: Creature -> Reader World Bool
crHasTargetLOSR cr = reader $ \w -> case cr ^? crTarget . _Just of
Just i -> crCanSeeCr i (w,cr)
Nothing -> False
crSafeDistFromTarg :: Float -> (World,Creature) -> Bool crSafeDistFromTarg :: Float -> (World,Creature) -> Bool
crSafeDistFromTarg d (w,cr) = case cr ^? crTarget . _Just of crSafeDistFromTarg d (w,cr) = case cr ^? crTarget . _Just of
Just tcr -> dist (_crPos cr) (_crPos tcr) > d Just tcr -> dist (_crPos cr) (_crPos tcr) > d
Nothing -> True Nothing -> True
crSafeDistFromTargR :: Float -> Creature -> Reader World Bool
crSafeDistFromTargR d cr = reader $ \w -> case cr ^? crTarget . _Just of
Just tcr -> dist (_crPos cr) (_crPos tcr) > d
Nothing -> True
crStratConMatches :: Strategy -> (World,Creature) -> Bool crStratConMatches :: Strategy -> (World,Creature) -> Bool
crStratConMatches strat (_,cr) = eqConstr strat (_crStrategy $ _crActionPlan cr) crStratConMatches strat (_,cr) = eqConstr strat (_crStrategy $ _crActionPlan cr)
crStratConMatchesR :: Strategy -> Creature -> Reader World Bool
crStratConMatchesR strat cr = return $ eqConstr strat (_crStrategy $ _crActionPlan cr)
crAwayFromPost :: (World,Creature) -> Bool crAwayFromPost :: (World,Creature) -> Bool
crAwayFromPost (_,cr) = case find sentinelGoal $ _crGoal $ _crActionPlan cr of crAwayFromPost (_,cr) = case find sentinelGoal $ _crGoal $ _crActionPlan cr of
Just (SentinelAt p dir) -> dist p (_crPos cr) > 15 Just (SentinelAt p dir) -> dist p (_crPos cr) > 15
@@ -60,3 +91,11 @@ crAwayFromPost (_,cr) = case find sentinelGoal $ _crGoal $ _crActionPlan cr of
where where
sentinelGoal (SentinelAt p dir) = True sentinelGoal (SentinelAt p dir) = True
sentinelGoal _ = False sentinelGoal _ = False
crAwayFromPostR :: Creature -> Reader World Bool
crAwayFromPostR cr = return $ case find sentinelGoal $ _crGoal $ _crActionPlan cr of
Just (SentinelAt p dir) -> dist p (_crPos cr) > 15
_ -> False
where
sentinelGoal (SentinelAt p dir) = True
sentinelGoal _ = False
-1
View File
@@ -1,4 +1,3 @@
{-# LANGUAGE BangPatterns #-}
module Dodge.Creature.Update module Dodge.Creature.Update
where where
import Dodge.Data import Dodge.Data
+17 -10
View File
@@ -16,10 +16,8 @@ module Dodge.Data
, soundTime , soundTime
) where ) where
import Dodge.Picture.Layer.Data import Dodge.Picture.Layer.Data
import Dodge.Creature.Data
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Dodge.Creature.Stance.Data import Dodge.Creature.Stance.Data
import Dodge.Creature.Rationality.Data
import Dodge.Creature.AlertLevel.Data import Dodge.Creature.AlertLevel.Data
import Dodge.Data.Menu import Dodge.Data.Menu
import Dodge.Data.SoundOrigin import Dodge.Data.SoundOrigin
@@ -42,6 +40,7 @@ import Data.Data
import Data.Graph.Inductive import Data.Graph.Inductive
import Data.Int (Int16) import Data.Int (Int16)
import qualified Data.Set as S import qualified Data.Set as S
import qualified Data.IntSet as IS
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.DList as DL import qualified Data.DList as DL
@@ -58,6 +57,7 @@ data World = World
, _cameraViewFrom :: !Point2 , _cameraViewFrom :: !Point2
, _creatures :: IM.IntMap Creature , _creatures :: IM.IntMap Creature
, _creaturesZone :: IM.IntMap (IM.IntMap (IM.IntMap Creature)) , _creaturesZone :: IM.IntMap (IM.IntMap (IM.IntMap Creature))
, _creatureGroups :: IM.IntMap CrGroupParams
, _itemPositions :: IM.IntMap ItemPos , _itemPositions :: IM.IntMap ItemPos
, _clouds :: IM.IntMap Cloud , _clouds :: IM.IntMap Cloud
, _cloudsZone :: IM.IntMap (IM.IntMap (IM.IntMap Cloud)) , _cloudsZone :: IM.IntMap (IM.IntMap (IM.IntMap Cloud))
@@ -65,7 +65,7 @@ data World = World
, _particles :: ![Particle] , _particles :: ![Particle]
, _staticWalls :: [Wall] , _staticWalls :: [Wall]
, _walls :: !(IM.IntMap Wall) , _walls :: !(IM.IntMap Wall)
, _wallsZone :: (IM.IntMap (IM.IntMap (IM.IntMap Wall))) , _wallsZone :: IM.IntMap (IM.IntMap (IM.IntMap Wall))
, _forceFields :: IM.IntMap ForceField , _forceFields :: IM.IntMap ForceField
, _floorItems :: IM.IntMap FloorItem , _floorItems :: IM.IntMap FloorItem
, _randGen :: StdGen , _randGen :: StdGen
@@ -105,6 +105,12 @@ data World = World
, _sideEffects :: [PreloadData SoundOrigin -> IO (PreloadData SoundOrigin)] , _sideEffects :: [PreloadData SoundOrigin -> IO (PreloadData SoundOrigin)]
, _doneSideEffects :: [PreloadData SoundOrigin -> IO (PreloadData SoundOrigin)] , _doneSideEffects :: [PreloadData SoundOrigin -> IO (PreloadData SoundOrigin)]
} }
data CrGroupParams = CrGroupParams
{ _crGroupParamID :: Int
, _crGroupIDs :: IS.IntSet
, _crGroupCenter :: Point2
, _crGroupUpdate :: World -> CrGroupParams -> Maybe CrGroupParams
}
data Corpse = Corpse data Corpse = Corpse
{ _cpPos :: Point2 { _cpPos :: Point2
, _cpPict :: Picture , _cpPict :: Picture
@@ -380,8 +386,7 @@ data Particle
, _btMaxTime' :: Int , _btMaxTime' :: Int
, _btTimer' :: Int , _btTimer' :: Int
} }
type HitEffect = Particle -> [(Point2, (Either3 Creature Wall ForceField))] -> World type HitEffect = Particle -> [(Point2, Either3 Creature Wall ForceField)] -> World -> (World,Maybe Particle)
-> (World,Maybe Particle)
data Projectile data Projectile
= Projectile = Projectile
{ _pjPos :: Point2 { _pjPos :: Point2
@@ -540,26 +545,26 @@ data Action
,_waitThenAction :: Action ,_waitThenAction :: Action
} }
| DoActionWhile | DoActionWhile
{_doActionWhileCondition :: ( (World, Creature) -> Bool) {_doActionWhileCondition :: (World, Creature) -> Bool
,_doActionWhileAction :: Action ,_doActionWhileAction :: Action
} }
| DoActionWhilePartial | DoActionWhilePartial
{_doActionWhilePartial :: Action {_doActionWhilePartial :: Action
,_doActionWhileCondition :: ( (World, Creature) -> Bool) ,_doActionWhileCondition :: (World, Creature) -> Bool
,_doActionWhileAction :: Action ,_doActionWhileAction :: Action
} }
| DoActionIf | DoActionIf
{_doActionIfCondition :: ( (World, Creature) -> Bool) {_doActionIfCondition :: (World, Creature) -> Bool
,_doActionIfAction :: Action ,_doActionIfAction :: Action
} }
| DoActionIfElse | DoActionIfElse
{_doActionIfElseIfAction :: Action {_doActionIfElseIfAction :: Action
,_doActionIfElseCondition :: ( (World, Creature) -> Bool) ,_doActionIfElseCondition :: (World, Creature) -> Bool
,_doActionIfElseElseAction :: Action ,_doActionIfElseElseAction :: Action
} }
| DoActionWhileThen | DoActionWhileThen
{_doActionWhileThenDo :: Action {_doActionWhileThenDo :: Action
,_doActionWhileThenCondition :: ( (World, Creature) -> Bool) ,_doActionWhileThenCondition :: (World, Creature) -> Bool
,_doActionWhileThenThen :: Action ,_doActionWhileThenThen :: Action
} }
| DoActions | DoActions
@@ -619,6 +624,7 @@ data Strategy
| GetTo Point2 | GetTo Point2
| Reload | Reload
| Flee | Flee
| MeleeStrike
deriving (Generic) deriving (Generic)
-- deriving (Eq,Ord,Show) -- deriving (Eq,Ord,Show)
data Goal data Goal
@@ -646,6 +652,7 @@ makeLenses ''Button
makeLenses ''ActionPlan makeLenses ''ActionPlan
makeLenses ''Impulse makeLenses ''Impulse
makeLenses ''Action makeLenses ''Action
makeLenses ''CrGroupParams
numColor :: Int -> Color numColor :: Int -> Color
numColor 0 = (1,0,0,1) numColor 0 = (1,0,0,1)
+11 -17
View File
@@ -1,4 +1,3 @@
{-# LANGUAGE BangPatterns #-}
{- | {- |
Module : Dodge.Default Module : Dodge.Default
Description : Instances of data structures Description : Instances of data structures
@@ -10,7 +9,6 @@ import Dodge.Item.Weapon.ExtraEffect
import Dodge.Data import Dodge.Data
import Dodge.Creature.Stance.Data import Dodge.Creature.Stance.Data
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Dodge.Creature.Rationality.Data
import Dodge.Creature.AlertLevel.Data import Dodge.Creature.AlertLevel.Data
import Dodge.Data.Menu import Dodge.Data.Menu
import Dodge.SoundLogic import Dodge.SoundLogic
@@ -45,15 +43,13 @@ defaultCrystalWall = Wall
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = True , _wlIsSeeThrough = True
} }
{- Door that opens on approach.
{-
Door that opens on approach.
Pathable. -} Pathable. -}
defaultAutoDoor = Door defaultAutoDoor = Door
{ _wlLine = ((0,0),(50,0)) { _wlLine = ((0,0),(50,0))
, _wlID = 0 , _wlID = 0
, _doorMech = id , _doorMech = id
, _wlColor = light $ dim $ dim $ dim $ yellow , _wlColor = light $ dim $ dim $ dim yellow
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
, _doorPathable = True , _doorPathable = True
@@ -66,7 +62,7 @@ defaultDoor = Door
{ _wlLine = ((0,0),(50,0)) { _wlLine = ((0,0),(50,0))
, _wlID = 0 , _wlID = 0
, _doorMech = id , _doorMech = id
, _wlColor = light $ dim $ dim $ dim $ yellow , _wlColor = light $ dim $ dim $ dim yellow
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
, _doorPathable = False , _doorPathable = False
@@ -101,8 +97,7 @@ defaultCreature = Creature
, _crGroup = LoneWolf , _crGroup = LoneWolf
} }
defaultState = CrSt defaultState = CrSt
{ _goals = [] { _crDamage = []
, _crDamage = []
, _crPastDamage = [] , _crPastDamage = []
, _crSpState = GenCr , _crSpState = GenCr
, _crDropsOnDeath = DropAmount 1 , _crDropsOnDeath = DropAmount 1
@@ -143,7 +138,7 @@ defaultApplyDamage :: [DamageType] -> Creature -> (World -> World, Creature)
defaultApplyDamage ds cr = (id, doPoisonDam $ foldr (\d c -> snd $ applyIndividualDamage d c) cr ds') defaultApplyDamage ds cr = (id, doPoisonDam $ foldr (\d c -> snd $ applyIndividualDamage d c) cr ds')
where where
(ps,ds') = partition isPoison ds (ps,ds') = partition isPoison ds
isPoison (PoisonDam {}) = True isPoison PoisonDam{} = True
isPoison _ = False isPoison _ = False
poisonDam = quot (max 0 (sum (map _dmAmount ps))) 10 poisonDam = quot (max 0 (sum (map _dmAmount ps))) 10
doPoisonDam = over crHP (\hp -> hp - poisonDam) doPoisonDam = over crHP (\hp -> hp - poisonDam)
@@ -174,7 +169,7 @@ defaultIt = Consumable
, _itName = "defaultIt" , _itName = "defaultIt"
, _itMaxStack = 3 , _itMaxStack = 3
, _itAmount = 2 , _itAmount = 2
, _cnEffect = \ _ -> return , _cnEffect = const return
, _itFloorPict = onLayer FlItLayer $ polygon [(-3,-3),(-3,3),(3,3),(3,-3)] , _itFloorPict = onLayer FlItLayer $ polygon [(-3,-3),(-3,3),(3,3),(3,-3)]
, _itEquipPict = \cr _ -> blank , _itEquipPict = \cr _ -> blank
, _itID = Nothing , _itID = Nothing
@@ -187,8 +182,8 @@ defaultButton = Button
{ _btPict = onLayer WlLayer $ color red $ polygon $ rectNSEW 5 (-5) 10 (-10) { _btPict = onLayer WlLayer $ color red $ polygon $ rectNSEW 5 (-5) 10 (-10)
, _btPos = (0,0) , _btPos = (0,0)
, _btRot = 0 , _btRot = 0
, _btEvent = \b w -> set (buttons . ix (_btID b) . btPict) , _btEvent = \b w ->
(onLayer WlLayer $ color red $ polygon $ rectNSEW (-4) (-5) 10 (-10)) set (buttons . ix (_btID b) . btPict) (onLayer WlLayer $ color red $ polygon $ rectNSEW (-4) (-5) 10 (-10))
. set (buttons . ix (_btID b) . btState) BtNoLabel . set (buttons . ix (_btID b) . btState) BtNoLabel
. soundOnce 1 $ w . soundOnce 1 $ w
, _btID = 0 , _btID = 0
@@ -204,15 +199,13 @@ defaultPT = Projectile
, _pjUpdate = id , _pjUpdate = id
} }
defaultPP = PressPlate defaultPP = PressPlate
{ _ppPict = onLayer PressPlateLayer $ color (dim $ dim $ bright $ blue) $ circleSolid 5 { _ppPict = onLayer PressPlateLayer $ color (dim $ dim $ bright blue) $ circleSolid 5
, _ppPos = (0,0) , _ppPos = (0,0)
, _ppRot = 0 , _ppRot = 0
, _ppEvent = \pp -> id , _ppEvent = const id
, _ppID = -1 , _ppID = -1
, _ppText = "Pressure plate" , _ppText = "Pressure plate"
} }
-- }}}
defaultWorld = World defaultWorld = World
{ _keys = S.empty { _keys = S.empty
, _mouseButtons = S.empty , _mouseButtons = S.empty
@@ -222,6 +215,7 @@ defaultWorld = World
, _cameraViewFrom = (0,0) , _cameraViewFrom = (0,0)
, _creatures = IM.empty , _creatures = IM.empty
, _creaturesZone = IM.empty , _creaturesZone = IM.empty
, _creatureGroups = IM.empty
, _clouds = IM.empty , _clouds = IM.empty
, _cloudsZone = IM.empty , _cloudsZone = IM.empty
, _itemPositions = IM.empty , _itemPositions = IM.empty
+6 -6
View File
@@ -108,12 +108,12 @@ wheelUpEvent w = case _carteDisplay w of
wheelDownEvent :: World -> World wheelDownEvent :: World -> World
wheelDownEvent w = case _carteDisplay w of wheelDownEvent w = case _carteDisplay w of
True | rbDown -> w & carteZoom .~ max 0.05 (z-(0.1*z)) True
| otherwise -> w & selLocation %~ (`mod` numLocs) . (\i -> i + 1) | rbDown -> w & carteZoom .~ max 0.05 (z-(0.1*z))
False | rbDown -> fromMaybe (closeObjScrollDown w) | otherwise -> w & selLocation %~ (`mod` numLocs) . (+ 1)
$ (yourItem w ^? itScrollDown) False
<*> pure (_crInvSel (you w)) | rbDown -> fromMaybe (closeObjScrollDown w)
<*> pure w $ (yourItem w ^? itScrollDown) <*> pure (_crInvSel (you w)) <*> pure w
| lbDown -> w {_cameraZoom = max (_cameraZoom w - 0.1) 0.01} | lbDown -> w {_cameraZoom = max (_cameraZoom w - 0.1) 0.01}
| otherwise -> downInvPos w | otherwise -> downInvPos w
where where
-2
View File
@@ -25,7 +25,6 @@ import qualified Data.Set as S
import Control.Lens import Control.Lens
import Picture import Picture
{- | Handles keyboard press and release. {- | Handles keyboard press and release.
On release, remove scancode from the 'Set' of pressed keys. On release, remove scancode from the 'Set' of pressed keys.
On press, adds the scancode, and perhaps applies a direct effect: On press, adds the scancode, and perhaps applies a direct effect:
@@ -58,7 +57,6 @@ handlePressedKey True _ w = Just w
handlePressedKey _ scode w handlePressedKey _ scode w
| null (_menuLayers w) = handlePressedKeyInGame scode w | null (_menuLayers w) = handlePressedKeyInGame scode w
| otherwise = handlePressedKeyInMenu (head $ _menuLayers w) scode w | otherwise = handlePressedKeyInMenu (head $ _menuLayers w) scode w
handlePressedKey _ _ w = Just w
debugKey :: Scancode -> World -> Maybe World debugKey :: Scancode -> World -> Maybe World
debugKey scancode w debugKey scancode w
+8 -7
View File
@@ -40,8 +40,7 @@ import Control.Lens
import Control.Monad.State import Control.Monad.State
import Control.Monad.Loops import Control.Monad.Loops
import System.Random import System.Random
{- | {- | A test level tree. -}
A test level tree. -}
roomTreex :: RandomGen g => State g (Maybe [Room]) roomTreex :: RandomGen g => State g (Maybe [Room])
roomTreex = do roomTreex = do
struct' <- aTreeStrut struct' <- aTreeStrut
@@ -51,16 +50,19 @@ roomTreex = do
t = treeFromTrunk t = treeFromTrunk
[[StartRoom] [[StartRoom]
,[Corridor] ,[Corridor]
,[SpecificRoom . pure . pure . Right $ roomGlassOctogon 400
& rmPS %~ ([sPS (0,50) 0 $ PutCrit chaseCrit ]++)
]
,[Corridor]
,[SpecificRoom . pure . pure . Right $ roomGlassOctogon 400 ,[SpecificRoom . pure . pure . Right $ roomGlassOctogon 400
& rmPS %~ ([swarmPS 0 (x,y) 0 swarmCrit | x <- [-20,-19.5.. 20] , y <- [200] ]++) & rmPS %~ ([swarmPS 0 (x,y) 0 swarmCrit | x <- [-20,-19.5.. 20] , y <- [200] ]++)
] ]
,[Corridor] ,[Corridor]
,[Corridor] ,[Corridor]
,[SpecificRoom . fmap (pure . Right) $ twinSlowDoorChasers 30] ,[SpecificRoom $ pure . Right <$> twinSlowDoorChasers 30]
,[Corridor] ,[Corridor]
,[DoorAno] ,[DoorAno]
,[SpecificRoom $ fmap (pure . Right) ,[SpecificRoom $ pure . Right <$> centerVaultExplosiveExit 50]
$ centerVaultExplosiveExit 50]
,[SpecificRoom blockedCorridor] ,[SpecificRoom blockedCorridor]
,[OrAno [[DoorAno] ,[OrAno [[DoorAno]
,[Corridor] ,[Corridor]
@@ -82,8 +84,7 @@ roomTreex = do
,[TreasureAno [addArmour autoCrit,addArmour autoCrit] [launcher]] ,[TreasureAno [addArmour autoCrit,addArmour autoCrit] [launcher]]
] ]
t' t'
fmap (shiftExpandTree . expandTreeBy id) $ mapM annoToRoomTree t shiftExpandTree . expandTreeBy id <$> mapM annoToRoomTree t
levx :: RandomGen g => State g [Room] levx :: RandomGen g => State g [Room]
levx = untilJust roomTreex levx = untilJust roomTreex
+7 -5
View File
@@ -1,18 +1,20 @@
module Dodge.Graph module Dodge.Graph
where where
import Data.Function (on) import Data.Function (on)
import Data.List import Data.List.Extra
import Data.Bifunctor (first)
import Data.Graph import Data.Graph
import Data.Maybe
pairsToIncidence :: (Eq a,Ord a) => [(a,a)] -> [(a,[a])] pairsToIncidence :: (Eq a,Ord a) => [(a,a)] -> [(a,[a])]
pairsToIncidence = map ((\(xs,ys) -> (head xs,ys)) . unzip) pairsToIncidence
. groupBy ( (==) `on` fst) = map (first head . unzip)
. groupOn fst
. sort . sort
incidenceToFunction :: Eq a => [(a,[a])] -> a -> [a] incidenceToFunction :: Eq a => [(a,[a])] -> a -> [a]
incidenceToFunction xs a = case lookup a xs of Just ys -> ys incidenceToFunction xs a = fromMaybe [] $ lookup a xs
Nothing -> []
mkNode :: (a,[a]) -> (a,a,[a]) mkNode :: (a,[a]) -> (a,a,[a])
mkNode (x,xs) = (x,x,xs) mkNode (x,xs) = (x,x,xs)
+10 -15
View File
@@ -2,22 +2,19 @@ module Dodge.Inventory
where where
import Dodge.Data import Dodge.Data
import Dodge.Base import Dodge.Base
--import Dodge.SoundLogic
import Geometry import Geometry
import Data.Maybe import Data.Maybe
import Data.List import Data.List
import Data.Function (on) import Data.Function (on)
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import System.Random import System.Random
import Control.Lens import Control.Lens
checkInvSlotsYou' :: Maybe Item -> World -> Maybe Int checkInvSlotsYou' :: Maybe Item -> World -> Maybe Int
checkInvSlotsYou' it w = fmap fst $ find cond invListSelFirst checkInvSlotsYou' it w = fst <$> find cond invListSelFirst
where cond (_,NoItem) = True where
cond (_,NoItem) = True
cond (_,it' ) = itNotFull it' && fmap _itName it == Just (_itName it') cond (_,it' ) = itNotFull it' && fmap _itName it == Just (_itName it')
youCr = you w youCr = you w
youSel = _crInvSel youCr youSel = _crInvSel youCr
@@ -25,7 +22,7 @@ checkInvSlotsYou' it w = fmap fst $ find cond invListSelFirst
invListSelFirst = (youSel , invList IM.! youSel) : IM.toList invList invListSelFirst = (youSel , invList IM.! youSel) : IM.toList invList
checkInvSlotsYou :: Item -> World -> Maybe Int checkInvSlotsYou :: Item -> World -> Maybe Int
checkInvSlotsYou it w = fmap fst $ find cond invListSelFirst checkInvSlotsYou it w = fst <$> find cond invListSelFirst
where where
cond (_,NoItem) = True cond (_,NoItem) = True
cond (_,it' ) = itNotFull it' && _itName it == _itName it' cond (_,it' ) = itNotFull it' && _itName it == _itName it'
@@ -36,7 +33,8 @@ checkInvSlotsYou it w = fmap fst $ find cond invListSelFirst
checkInvSlots :: Item -> IM.IntMap Item -> Maybe Int checkInvSlots :: Item -> IM.IntMap Item -> Maybe Int
checkInvSlots it its = fmap fst $ find cond $ IM.toList its checkInvSlots it its = fmap fst $ find cond $ IM.toList its
where cond (_,NoItem) = True where
cond (_,NoItem) = True
cond (_,it' ) = itNotFull it' && _itName it == _itName it' cond (_,it' ) = itNotFull it' && _itName it == _itName it'
addItem :: Item -> Item -> Item addItem :: Item -> Item -> Item
@@ -67,20 +65,17 @@ rmInvItem n i w =
Equipment {_itAmount = x} -> over (itRef . itAmount) (\y-> y-1) w Equipment {_itAmount = x} -> over (itRef . itAmount) (\y-> y-1) w
Throwable {_itAmount = x} -> over (itRef . itAmount) (\y-> y-1) w Throwable {_itAmount = x} -> over (itRef . itAmount) (\y-> y-1) w
_ -> set itRef NoItem w _ -> set itRef NoItem w
{- Delete a creature's selected item, the item will no longer exist. -}
{-
Delete a creature's selected item, the item will no longer exist.
-}
rmSelectedInvItem rmSelectedInvItem
:: Int -- ^ Creature id :: Int -- ^ Creature id
-> World -> World
-> World -> World
rmSelectedInvItem cid w = rmInvItem cid (_crInvSel (_creatures w IM.! cid)) w rmSelectedInvItem cid w = rmInvItem cid (_crInvSel (_creatures w IM.! cid)) w
-- for now, left are floor items, right are buttons -- for now, left are floor items, right are buttons
closestActiveObject :: World -> Maybe (Either FloorItem Button) closestActiveObject :: World -> Maybe (Either FloorItem Button)
closestActiveObject w = listToMaybe $ sortBy (compare `on` dist ypos . pos) $ actObjs closestActiveObject w = listToMaybe $ sortOn (dist ypos . pos) actObjs
where ypos = _crPos $ you w where
ypos = _crPos $ you w
actObjs = filter (\obj -> dist ypos (pos obj) < 40 && hasLOS ypos (pos obj) w) actObjs = filter (\obj -> dist ypos (pos obj) < 40 && hasLOS ypos (pos obj) w)
$ map Left (IM.elems $ _floorItems w) ++ activeButtons -- map Right (IM.elems $ _buttons w) $ map Left (IM.elems $ _floorItems w) ++ activeButtons -- map Right (IM.elems $ _buttons w)
pos (Right x) = _btPos x pos (Right x) = _btPos x
+2 -2
View File
@@ -13,7 +13,7 @@ keyToken n = defaultEquipment
, _itName = "KEYTOKEN "++show n , _itName = "KEYTOKEN "++show n
, _itMaxStack = 5 , _itMaxStack = 5
, _itAmount = 1 , _itAmount = 1
, _itFloorPict = setDepth 0.5 $ keyPic , _itFloorPict = setDepth 0.5 keyPic
, _itEquipPict = \cr _ -> setDepth 0 $ translate (-5) (-5) $ rotate (pi/2.5) keyPic , _itEquipPict = \cr _ -> setDepth 0 $ translate (-5) (-5) $ rotate (pi/2.5) keyPic
, _itEffect = NoItEffect , _itEffect = NoItEffect
, _itHammer = HammerUp , _itHammer = HammerUp
@@ -36,7 +36,7 @@ latchkey n = defaultEquipment
, _itName = "KEY "++show n , _itName = "KEY "++show n
, _itMaxStack = 1 , _itMaxStack = 1
, _itAmount = 1 , _itAmount = 1
, _itFloorPict = setDepth 0.5 $ latchkeyPic , _itFloorPict = setDepth 0.5 latchkeyPic
, _itEquipPict = \cr _ -> setDepth 0 $ translate (-5) (-5) $ rotate (pi/2.5) latchkeyPic , _itEquipPict = \cr _ -> setDepth 0 $ translate (-5) (-5) $ rotate (pi/2.5) latchkeyPic
, _itEffect = NoItEffect , _itEffect = NoItEffect
, _itHammer = HammerUp , _itHammer = HammerUp
+1 -2
View File
@@ -29,6 +29,5 @@ heal25 :: Int -> World -> Maybe World
heal25 = heal 25 heal25 = heal 25
heal :: Int -> Int -> World -> Maybe World heal :: Int -> Int -> World -> Maybe World
heal hp n w | _crHP (_creatures w IM.! n) >= 10000 = Nothing heal hp n w | _crHP (_creatures w IM.! n) >= 10000 = Nothing
| otherwise = Just $ soundOnce healSound | otherwise = Just $ soundOnce healSound w & creatures . ix n . crHP %~ min 10000 . (+ hp)
$ over (creatures . ix n . crHP) ((min 10000) . (+ hp) ) w
+2 -5
View File
@@ -1,8 +1,5 @@
{- | {- | Definitions of weapons.
Definitions of weapons. In progress: move out effects into other modules. -}
In progress: move out effects into other modules.
-}
{-# LANGUAGE BangPatterns #-}
module Dodge.Item.Weapon module Dodge.Item.Weapon
( module Dodge.Item.Weapon ( module Dodge.Item.Weapon
) )
+6 -6
View File
@@ -145,7 +145,7 @@ bulHitWall' bt p x w = damageBlocks x
spid = newKey $ _projectiles w spid = newKey $ _projectiles w
reflectDir wall = a + argV (reflectIn (uncurry (-.-) (_wlLine wall)) (p -.- sp) ) reflectDir wall = a + argV (reflectIn (uncurry (-.-) (_wlLine wall)) (p -.- sp) )
damageBlocks wall w = case wall ^? blHP of damageBlocks wall w = case wall ^? blHP of
Just hp -> foldr (\j -> (walls . ix j . blHP -~ 5)) w (_blIDs wall) Just hp -> foldr (\j -> walls . ix j . blHP -~ 5) w (_blIDs wall)
_ -> w _ -> w
{- | Bounce off walls, do damage to blocks. -} {- | Bounce off walls, do damage to blocks. -}
bulBounceWall' :: Particle -> Point2 -> Wall -> World -> World bulBounceWall' :: Particle -> Point2 -> Wall -> World -> World
@@ -155,7 +155,7 @@ bulBounceWall' bt p wl w = damageBlocks wl $ over worldEvents addBouncer w
pOut = p +.+ safeNormalizeV (sp -.- p) pOut = p +.+ safeNormalizeV (sp -.- p)
damageBlocks wall w damageBlocks wall w
= case wall ^? blHP of = case wall ^? blHP of
Just hp -> foldr (\j -> (walls . ix j . blHP -~ 5)) w (_blIDs wall) Just hp -> foldr (\j -> walls . ix j . blHP -~ 5) w (_blIDs wall)
_ -> w _ -> w
bouncer = (aGenBulAt' Nothing (_btColor' bt) pOut reflectVel bouncer = (aGenBulAt' Nothing (_btColor' bt) pOut reflectVel
(_btHitEffect' bt) (_btWidth' bt) (_btHitEffect' bt) (_btWidth' bt)
@@ -180,7 +180,7 @@ bulIncWall' bt p wl w = damageBlocks wl $ incFlamelets w
pOut = p +.+ safeNormalizeV (sp -.- p) pOut = p +.+ safeNormalizeV (sp -.- p)
damageBlocks wall w damageBlocks wall w
= case wall ^? blHP of = case wall ^? blHP of
Just hp -> foldr (\j -> (walls . ix j . blHP -~ 5)) w (_blIDs wall) Just hp -> foldr (\j -> walls . ix j . blHP -~ 5) w (_blIDs wall)
_ -> w _ -> w
wallV = uncurry (-.-) (_wlLine wl) wallV = uncurry (-.-) (_wlLine wl)
reflectVel = safeNormalizeV $ reflectIn wallV (_btVel' bt) reflectVel = safeNormalizeV $ reflectIn wallV (_btVel' bt)
@@ -198,9 +198,9 @@ bulConWall' bt p wl w = damageBlocks wl $ mkwave w
pOut = p +.+ safeNormalizeV (sp -.- p) pOut = p +.+ safeNormalizeV (sp -.- p)
damageBlocks wall w damageBlocks wall w
= case wall ^? blHP of = case wall ^? blHP of
Just hp -> foldr (\j -> (walls . ix j . blHP -~ 5)) w (_blIDs wall) Just hp -> foldr (\j -> walls . ix j . blHP -~ 5) w (_blIDs wall)
_ -> w _ -> w
mkwave = over worldEvents ((makeShockwaveAt [] p 15 4 1 white) . ) mkwave = over worldEvents ( makeShockwaveAt [] p 15 4 1 white . )
hvBulHitWall' hvBulHitWall'
:: Particle :: Particle
@@ -218,7 +218,7 @@ hvBulHitWall' bt p x w = damageBlocks x $ set randGen g $ foldr ($) w (sparks p
argV (reflectIn (uncurry (-.-) (_wlLine wall)) (p -.- sp) ) argV (reflectIn (uncurry (-.-) (_wlLine wall)) (p -.- sp) )
sv = unitVectorAtAngle $ reflectDir x sv = unitVectorAtAngle $ reflectDir x
damageBlocks wall w = case wall ^? blHP of damageBlocks wall w = case wall ^? blHP of
Just hp -> foldr (\j -> (walls . ix j . blHP -~ 20)) w (_blIDs wall) Just hp -> foldr (\j -> walls . ix j . blHP -~ 20) w (_blIDs wall)
_ -> w _ -> w
cs = take 10 $ randomRs (0,11) $ _randGen w cs = take 10 $ randomRs (0,11) $ _randGen w
ds = randomRs (-0.7,0.7) $ _randGen w ds = randomRs (-0.7,0.7) $ _randGen w
+1 -1
View File
@@ -370,7 +370,7 @@ spreadNumVelWthHiteff spread num vel wth eff cid w = over particles (newbuls ++)
poss dirs colids poss dirs colids
poss = map ((+.+) $ _crPos cr +.+ _crRad cr *.* unitVectorAtAngle (_crDir cr)) poss = map ((+.+) $ _crPos cr +.+ _crRad cr *.* unitVectorAtAngle (_crDir cr))
$ (replicateM num . randInCirc) 5 & evalState $ _randGen w $ (replicateM num . randInCirc) 5 & evalState $ _randGen w
dirs = map ((_crDir cr) +) $ zipWith (+) dirs = map (_crDir cr +) $ zipWith (+)
[-spread,-spread+(2*spread/fromIntegral num)..] [-spread,-spread+(2*spread/fromIntegral num)..]
(randomRs (0,spread/5) (_randGen w)) (randomRs (0,spread/5) (_randGen w))
colids = take num $ randomRs (0,11) (_randGen w) colids = take num $ randomRs (0,11) (_randGen w)
+1 -1
View File
@@ -96,7 +96,7 @@ mvRadar x p w pt =
) )
where where
pic = onLayerL [levLayer ShadowLayer, 1] $ pictures sweepPics pic = onLayerL [levLayer ShadowLayer, 1] $ pictures sweepPics
putBlips = over worldEvents ( ( over particles (blips ++) ) . ) putBlips = over worldEvents ( over particles (blips ++) . )
blips = map (\p -> blipAt p (withAlpha (0.5*globalAlpha) red) 50) circPoints blips = map (\p -> blipAt p (withAlpha (0.5*globalAlpha) red) 50) circPoints
circPoints = mapMaybe (\wl -> uncurry collidePointCircCorrect (_wlLine wl) r p) circPoints = mapMaybe (\wl -> uncurry collidePointCircCorrect (_wlLine wl) r p)
$ map (over wlLine swp) (IM.elems $ wallsAlongCirc p r w) $ map (over wlLine swp) (IM.elems $ wallsAlongCirc p r w)
+9 -9
View File
@@ -25,7 +25,7 @@ import Data.Maybe
import Data.Tree import Data.Tree
import Data.Either import Data.Either
import Data.Function import Data.Function
import Data.Graph.Inductive.Graph import Data.Graph.Inductive.Graph hiding ((&))
import Data.Graph.Inductive.Basic import Data.Graph.Inductive.Basic
import Data.Graph.Inductive.PatriciaTree import Data.Graph.Inductive.PatriciaTree
import Data.Graph.Inductive.NodeMap import Data.Graph.Inductive.NodeMap
@@ -61,16 +61,17 @@ generateFromTree t w = updateWallZoning $ placeSpots plmnts
updateWallZoning :: World -> World updateWallZoning :: World -> World
updateWallZoning w = set wallsZone (IM.foldr wallInZone IM.empty (_walls w)) w updateWallZoning w = set wallsZone (IM.foldr wallInZone IM.empty (_walls w)) w
where where
wallInZone wl | uncurry dist (_wlLine wl) <= 2*zoneSize wallInZone wl
= insertIMInZone x y wlid wl | uncurry dist (_wlLine wl) <= 2*zoneSize = insertIMInZone x y wlid wl
| otherwise = flip (foldr (\(a,b) -> insertIMInZone a b wlid wl)) ips | otherwise = flip (foldr (\(a,b) -> insertIMInZone a b wlid wl)) ips
where (x,y) = zoneOfPoint $ (uncurry pHalf (_wlLine wl)) where
(x,y) = zoneOfPoint $ uncurry pHalf (_wlLine wl)
wlid = _wlID wl wlid = _wlID wl
ips = map zoneOfPoint $ uncurry (divideLine (2*zoneSize)) (_wlLine wl) ips = map zoneOfPoint $ uncurry (divideLine (2*zoneSize)) (_wlLine wl)
makePath :: Tree Room -> [(Point2,Point2)] makePath :: Tree Room -> [(Point2,Point2)]
makePath = concat . map _rmPath . flatten makePath = concatMap _rmPath . flatten
-- consider nubbing walls after dividing them -- consider nubbing walls after dividing them
wallsFromTree :: Tree Room -> IM.IntMap Wall wallsFromTree :: Tree Room -> IM.IntMap Wall
@@ -81,7 +82,7 @@ wallsFromTree t =
. removeInverseWalls . removeInverseWalls
. foldr cutWalls [] -- map (map (g . roundPoint2)) . foldr cutWalls [] -- map (map (g . roundPoint2))
-- . map (map roundPoint2) -- . map (map roundPoint2)
$ (concatMap _rmPolys $ flatten t) $ concatMap _rmPolys (flatten t)
where where
assignKeys = IM.fromList . zip [0..] . zipWith f [0..] assignKeys = IM.fromList . zip [0..] . zipWith f [0..]
f i (x,y) = defaultWall {_wlLine = (x,y) , _wlID = i} f i (x,y) = defaultWall {_wlLine = (x,y) , _wlID = i}
@@ -98,9 +99,8 @@ wallsFromRooms =
divideWall :: Wall -> [Wall] divideWall :: Wall -> [Wall]
divideWall wl divideWall wl
= let (a,b) = _wlLine wl = let (a,b) = _wlLine wl
--ps = divideLine (zoneSize * 2) a b
ps = divideLine (zoneSize * 2) a b ps = divideLine (zoneSize * 2) a b
in map (\(x,y) -> wl {_wlLine = (x,y)}) $ zip (init ps) (tail ps) in zipWith (\ x y -> wl & wlLine .~ (x,y) ) (init ps) (tail ps)
divideWallIn :: Wall -> IM.IntMap Wall -> IM.IntMap Wall divideWallIn :: Wall -> IM.IntMap Wall -> IM.IntMap Wall
divideWallIn wl wls = divideWallIn wl wls =
@@ -130,7 +130,7 @@ shiftRoomTreeConstruction (Node t ts) = (Node t [] :) $ concat $
(_rmLinks t) (_rmLinks t)
ts ts
where where
f r = shiftRoomBy ((0,0) -.- (rotateV (pi-a) p),0) $ shiftRoomBy ((0,0),pi-a) r f r = shiftRoomBy ( (0,0) -.- rotateV (pi-a) p , 0) $ shiftRoomBy ((0,0),pi-a) r
where where
(p,a) = last $ _rmLinks r (p,a) = last $ _rmLinks r
+35 -35
View File
@@ -1,4 +1,3 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
-- | deals with placement of objects within the world -- | deals with placement of objects within the world
-- after they have had their coordinates set by the layout -- after they have had their coordinates set by the layout
@@ -8,9 +7,7 @@ module Dodge.LevelGen
, pairsToGraph , pairsToGraph
, makeButton , makeButton
, makeSwitch , makeSwitch
) ) where
where
import Dodge.Data import Dodge.Data
import Dodge.Base import Dodge.Base
import Dodge.Room.Data import Dodge.Room.Data
@@ -29,22 +26,24 @@ import System.Random
import Control.Monad.State import Control.Monad.State
import Control.Applicative import Control.Applicative
import Control.Lens import Control.Lens
import Data.List import Data.List.Extra
import Data.Function import Data.Function
import Data.Maybe import Data.Maybe
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import qualified Data.Set as S import qualified Data.Set as S
import qualified Data.Map as M import qualified Data.Map as M
placeSpots :: [Placement] -> World -> World placeSpots :: [Placement] -> World -> World
placeSpots pss w = foldr placeSpot w' $ map _placementSpot singlePlacements placeSpots pss w = foldr (placeSpot . _placementSpot) w' singlePlacements
where where
(singlePlacements, groupedPlacements) = partition isSPS pss (singlePlacements, groupedPlacements) = partition isSPS pss
isSPS (SinglePlacement {}) = True isSPS SinglePlacement{} = True
isSPS _ = False isSPS _ = False
gplmnts = groupBy ((==) `on` _groupPlacementID) $ sortOn _groupPlacementID groupedPlacements gplmnts :: [[Placement]]
w' = foldr updateGroup w gplmnts gplmnts = groupOn _groupPlacementID $ sortOn _groupPlacementID groupedPlacements
w' = foldr putGroup w gplmnts
putGroup :: [Placement] -> World -> World
putGroup gps w = (_groupUpdate $ head gps) w gps
{- | OK, this is perhaps slightly impenetrable. {- | OK, this is perhaps slightly impenetrable.
- The idea is that for a list of collected group placements, we first update - The idea is that for a list of collected group placements, we first update
@@ -53,20 +52,20 @@ placeSpots pss w = foldr placeSpot w' $ map _placementSpot singlePlacements
- After this, for each placement we apply the group placement function to - After this, for each placement we apply the group placement function to
- the psType using a zipWith, and taking all the pstypes as a paramenter, - the psType using a zipWith, and taking all the pstypes as a paramenter,
- then successively update the world using a foldr. -} - then successively update the world using a foldr. -}
updateGroup :: [Placement] -> World -> World --updateGroup :: [Placement] -> World -> World
updateGroup ps w = --updateGroup ps w =
let (w', psTypes) = mapAccumR updateSpot w $ map _placementSpot ps -- let (w', psTypes) = mapAccumR updateSpot w $ map _placementSpot ps
fs = zipWith (\gp pst -> _groupPlacementFunc gp psTypes pst) ps psTypes -- fs = zipWith (\gp pst -> _groupPlacementFunc gp psTypes pst) ps psTypes
in foldr ($) w' fs -- in foldr ($) w' fs
--{- | -}
updateSpot :: World -> PlacementSpot -> (World, PSType) --updateSpot :: World -> PlacementSpot -> (World, PSType)
updateSpot w ps = case _psType ps of --updateSpot w ps = case _psType ps of
PutButton bt -> undefined -- PutButton bt -> undefined
PutCrit cr -> placeUpdateCr cr p rot w -- PutCrit cr -> placeUpdateCr cr p rot w
where -- where
p = _psPos ps -- p = _psPos ps
rot = _psRot ps -- rot = _psRot ps
{- | -}
placeSpot :: PlacementSpot -> World -> World placeSpot :: PlacementSpot -> World -> World
placeSpot ps w = case _psType ps of placeSpot ps w = case _psType ps of
PutButton bt -> placeBt bt p rot w PutButton bt -> placeBt bt p rot w
@@ -134,7 +133,7 @@ addPane wl (p0,p1) wls = IM.insert (newKey wls) (wl
}) })
wls wls
placeBt bt p rot w = over buttons addBT w placeBt bt p rot = over buttons addBT
where where
addBT bts = IM.insert (newKey bts) (bt {_btPos = p, _btRot = rot, _btID = newKey bts}) bts addBT bts = IM.insert (newKey bts) (bt {_btPos = p, _btRot = rot, _btID = newKey bts}) bts
{- Creates a floor item at a given point. {- Creates a floor item at a given point.
@@ -155,7 +154,7 @@ placeFlIt itm p rot = floorItems %~
} }
) fis ) fis
placePressPlate pp p rot w = over pressPlates addPP w placePressPlate pp p rot = over pressPlates addPP
where where
addPP pps = IM.insert (newKey pps) (pp {_ppPos = p,_ppRot = rot}) pps addPP pps = IM.insert (newKey pps) (pp {_ppPos = p,_ppRot = rot}) pps
@@ -166,20 +165,21 @@ placeUpdateCr scr p rot w = (w & creatures %~ IM.insert cid cr, PutCrit cr)
cr = scr {_crPos = p,_crOldPos = p,_crDir = rot,_crID = cid} cr = scr {_crPos = p,_crOldPos = p,_crDir = rot,_crID = cid}
placeCr :: Creature -> Point2 -> Float -> World -> World placeCr :: Creature -> Point2 -> Float -> World -> World
placeCr crF p rot w = over creatures addCr w placeCr crF p rot = over creatures addCr
where where
addCr crs = IM.insert (newKey crs) addCr crs = IM.insert
(newKey crs)
(crF {_crPos = p,_crOldPos = p,_crDir = rot,_crID = newKey crs}) (crF {_crPos = p,_crOldPos = p,_crDir = rot,_crID = newKey crs})
crs crs
placeLS :: LightSource -> Picture -> Point2 -> Float -> World -> World placeLS :: LightSource -> Picture -> Point2 -> Float -> World -> World
placeLS ls dec p rot w = over lightSources addLS placeLS ls dec p rot w = over lightSources addLS $ over decorations addDec w
$ over decorations addDec w where
where addLS lss = IM.insert (newKey lss) addLS lss = IM.insert
(newKey lss)
(ls {_lsPos = p,_lsDir = rot,_lsID = newKey lss}) (ls {_lsPos = p,_lsDir = rot,_lsID = newKey lss})
lss lss
addDec decs = IM.insert (newKey decs) addDec decs = IM.insert
(uncurry translate p $ rotate (0 - rot) dec) (newKey decs)
(uncurry translate p $ rotate (negate rot) dec)
decs decs
+4 -4
View File
@@ -8,7 +8,6 @@ import Picture
import Control.Lens import Control.Lens
import Control.Monad.State import Control.Monad.State
import System.Random import System.Random
data PSType = PutCrit {_unPutCrit :: Creature} data PSType = PutCrit {_unPutCrit :: Creature}
| PutLS LightSource Picture | PutLS LightSource Picture
| PutButton Button | PutButton Button
@@ -34,12 +33,13 @@ data Placement
= SinglePlacement {_placementSpot :: PlacementSpot } = SinglePlacement {_placementSpot :: PlacementSpot }
| GroupedPlacement | GroupedPlacement
{_groupPlacementID :: Int {_groupPlacementID :: Int
,_groupPlacementFunc :: [PSType] -> PSType -> World -> World -- ,_groupPlacementUpdate :: World -> Placement -> (World, Placement)
,_groupUpdate :: World -> [Placement] -> World
-- ,_groupPlacementFunc :: [PSType] -> PSType -> World -> World
,_placementSpot :: PlacementSpot ,_placementSpot :: PlacementSpot
} }
sPS :: Point2 -> Float -> PSType -> Placement
sPS p a = SinglePlacement . PS p a sPS p a = SinglePlacement . PS p a
makeLenses ''PSType makeLenses ''PSType
makeLenses ''PlacementSpot makeLenses ''PlacementSpot
makeLenses ''Placement makeLenses ''Placement
+39 -8
View File
@@ -3,23 +3,54 @@ module Dodge.LevelGen.SwarmPlacement
) )
where where
import Dodge.Data import Dodge.Data
import Dodge.Base
import Dodge.LevelGen.Data import Dodge.LevelGen.Data
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Geometry
import Data.List
import qualified Data.IntSet as IS import qualified Data.IntSet as IS
import qualified Data.IntMap as IM
import Control.Lens import Control.Lens
swarmPS :: Int -> Point2 -> Float -> Creature -> Placement swarmPS :: Int -> Point2 -> Float -> Creature -> Placement
swarmPS i p a cr = GroupedPlacement swarmPS i p a cr = GroupedPlacement
{ _groupPlacementID = i { _groupPlacementID = i
, _groupPlacementFunc = setSwarm , _groupUpdate = setSwarm
-- , _groupPlacementFunc = setSwarm i
, _placementSpot = PS p a $ PutCrit cr , _placementSpot = PS p a $ PutCrit cr
} }
setSwarm :: World -> [Placement] -> World
setSwarm :: [PSType] -> PSType -> World -> World setSwarm w ps = updateCrs w' & creatureGroups %~ IM.insert gid theGroupParams
setSwarm psts (PutCrit cr) w
= w & creatures . ix cid . crGroup .~ theSwarm
where where
cid = _crID cr (w', crs) = mapAccumR updateCrit w ps
theSwarm = Swarm swarmSet is = IS.fromList $ map _crID crs
swarmSet = IS.fromList $ map (_crID . _unPutCrit) psts cpos = centroid $ map _crPos crs
gid = newKey (_creatureGroups w')
theGroupParams = CrGroupParams
{ _crGroupParamID = gid
, _crGroupIDs = is
, _crGroupCenter = cpos
, _crGroupUpdate = crGroupUpdateCenter
}
updateCrs w'' = IS.foldl' (\w''' cid -> w''' & creatures . ix cid %~ setSwarmStatus) w'' is
setSwarmStatus = crGroup .~ Swarm {_swarm = is, _crGroupID = gid}
crGroupUpdateCenter :: World -> CrGroupParams -> Maybe CrGroupParams
crGroupUpdateCenter w cgp
| IM.null crs = Nothing
| otherwise = Just $ cgp & crGroupCenter .~
centroid (IM.map _crPos crs)
where
crs = IM.restrictKeys (_creatures w) (_crGroupIDs cgp)
updateCrit :: World -> Placement -> (World, Creature)
updateCrit w pl = (w & creatures %~ IM.insert cid cr
, cr
)
where
p = _psPos $ _placementSpot pl
rot = _psRot $ _placementSpot pl
scr = _unPutCrit $ _psType $ _placementSpot pl
cid = newKey (_creatures w)
cr = scr {_crPos = p,_crOldPos = p,_crDir = rot,_crID = cid}
+1 -1
View File
@@ -50,4 +50,4 @@ tLightRad i rmax rmin p = TLS
, _tlsUpdate = \w _ -> (w, Just $ tLightRad (i-1) rmax rmin p) , _tlsUpdate = \w _ -> (w, Just $ tLightRad (i-1) rmax rmin p)
} }
tLightAt i p = tLightRad i 100 0 p tLightAt i = tLightRad i 100 0
+2 -6
View File
@@ -1,17 +1,13 @@
module Dodge.LoadSound where module Dodge.LoadSound where
-- imports {{{
import Dodge.Data import Dodge.Data
import Data.Maybe import Data.Maybe
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import qualified Data.Map as M import qualified Data.Map as M
import Control.Monad import Control.Monad
import Control.Lens import Control.Lens
import qualified SDL.Mixer as Mix import qualified SDL.Mixer as Mix
-- }}}
loadSounds :: IO (IM.IntMap Mix.Chunk) loadSounds :: IO (IM.IntMap Mix.Chunk)
loadSounds = do loadSounds = do
Mix.openAudio Mix.defaultAudio 128 Mix.openAudio Mix.defaultAudio 128
@@ -57,7 +53,7 @@ loadSounds = do
glass3' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A3.wav" glass3' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A3.wav"
glass4' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A4.wav" glass4' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A4.wav"
foamSpray' <- Mix.load "./data/sound/foamSprayLoop.wav" foamSpray' <- Mix.load "./data/sound/foamSprayLoop.wav"
return $ IM.fromList $ zip [0..] $ return $ IM.fromList $ zip [0..]
[ pFireSound [ pFireSound
, click , click
, reloadSound' , reloadSound'
@@ -105,6 +101,6 @@ loadSounds = do
loadMusic :: IO (IM.IntMap Mix.Music) loadMusic :: IO (IM.IntMap Mix.Music)
loadMusic = do loadMusic = do
undercity <- Mix.load "./data/music/firstCompo.mid" undercity <- Mix.load "./data/music/firstCompo.mid"
return $ IM.fromList $ zip [0..] $ return $ IM.fromList $ zip [0..]
[ undercity [ undercity
] ]
+44 -62
View File
@@ -41,31 +41,24 @@ type SearchedNodes = (HP.MinHeap (Float,(Float,[Point2])), [Point2])
stripRight :: Either a b -> b stripRight :: Either a b -> b
stripRight (Right x) = x stripRight (Right x) = x
stepPath :: (Point2 -> [Point2]) -> Point2 stepPath :: (Point2 -> [Point2]) -> Point2 -> SearchedNodes -> Either [Point2] SearchedNodes
-> SearchedNodes -> Either [Point2] SearchedNodes stepPath f p (nextNodes, seenNodes) = case HP.view nextNodes of
stepPath f p (nextNodes, seenNodes)
= case HP.view nextNodes of
Nothing -> Left [] Nothing -> Left []
Just ((_,(cost,(q:qs))), nextNodes') Just ((_,(cost,q:qs)), nextNodes')
| q == p -> Left (q:qs) | q == p -> Left (q:qs)
| otherwise -> let rs' = f q | otherwise ->
let rs' = f q
rs = rs' \\ seenNodes rs = rs' \\ seenNodes
newNodes = map (\r -> (cost + dist q r + dist r p newNodes = map (\r -> (cost + dist q r + dist r p , (cost + dist q r , r:q:qs))) rs
, (cost + dist q r in Right (foldr HP.insert nextNodes' newNodes , rs ++ seenNodes)
, (r:q:qs)
) stepPath' :: (Point2 -> [Point2]) -> Point2 -> SearchedNodes -> [Point2]
) stepPath' f p s = case stepPath f p s of
) rs Left ps -> ps
in Right $ (foldr HP.insert nextNodes' newNodes
, rs ++ seenNodes
)
stepPath' :: (Point2 -> [Point2]) -> Point2
-> SearchedNodes -> [Point2]
stepPath' f p s = case stepPath f p s of Left ps -> ps
Right s' -> stepPath' f p s' Right s' -> stepPath' f p s'
makePath' :: (Point2 -> [Point2]) -> Point2 -> Point2 -> [Point2] makePath' :: (Point2 -> [Point2]) -> Point2 -> Point2 -> [Point2]
makePath' f s e = stepPath' f e $ (HP.singleton (0,(0,[s])) , []) makePath' f s e = stepPath' f e (HP.singleton (0,(0,[s])) , [])
makeNode :: Point2 -> SearchedNodes makeNode :: Point2 -> SearchedNodes
makeNode e = (HP.singleton (0,(0,[e])) , []) makeNode e = (HP.singleton (0,(0,[e])) , [])
@@ -76,39 +69,36 @@ tp1 = (0,1)
tp2 = (0,20) tp2 = (0,20)
tp3 = (30,40) tp3 = (30,40)
f = incidenceToFunction $ pairsToIncidence [(tp1,tp2),(tp2,tp3) f = incidenceToFunction $ pairsToIncidence
[(tp1,tp2)
,(tp2,tp3)
,(tp2,tp1) ,(tp2,tp1)
,(tp1,tp3)] ,(tp1,tp3)
g = pairsToIncidence [(tp1,tp2),(tp2,tp3) ]
g = pairsToIncidence
[(tp1,tp2)
,(tp2,tp3)
,(tp2,tp1) ,(tp2,tp1)
,(tp1,tp3)] ,(tp1,tp3)
]
pathBetween :: Point2 -> Point2 -> World -> Maybe [Point2] pathBetween :: Point2 -> Point2 -> World -> Maybe [Point2]
pathBetween a b w = makePath' <$> return (\p -> _pathInc w M.! p) <*> a' <*> b' pathBetween a b w = (makePath' $ \p -> _pathInc w M.! p) <$> a' <*> b'
where where
nsa :: [Point2] nsa :: [Point2]
nsa = map snd $ concat $ lookLookups (zoneAroundPoint a) (_pathPoints w) nsa = map snd $ concat $ lookLookups (zoneAroundPoint a) (_pathPoints w)
nsb = map snd $ concat $ lookLookups (zoneAroundPoint b) (_pathPoints w) nsb = map snd $ concat $ lookLookups (zoneAroundPoint b) (_pathPoints w)
--a' = listToMaybe $ sortBy (compare `on` dist a) $ ns a' = find (flip (isWalkable a) w) nsa
--b' = listToMaybe $ sortBy (compare `on` dist b) $ ns b' = find (flip (isWalkable b) w) nsb
a' = listToMaybe $ filter (flip (isWalkable a) w) nsa
b' = listToMaybe $ filter (flip (isWalkable b) w) nsb
----
makePathBetween :: Point2 -> Point2 -> World -> Maybe [Int] makePathBetween :: Point2 -> Point2 -> World -> Maybe [Int]
makePathBetween a b w = join $ sp <$> fmap fst a' <*> fmap fst b' <*> return g makePathBetween a b w = join $ sp <$> fmap fst a' <*> fmap fst b' <*> return g
where g = _pathGraph w where
g = _pathGraph w
nsa = concat $ lookLookups (zoneAroundPoint a) (_pathPoints w) nsa = concat $ lookLookups (zoneAroundPoint a) (_pathPoints w)
nsb = concat $ lookLookups (zoneAroundPoint b) (_pathPoints w) nsb = concat $ lookLookups (zoneAroundPoint b) (_pathPoints w)
-- a' = listToMaybe $ sortBy (compare `on` dist a . snd) $ filter (flip (isWalkable a) w . snd) ns a' = find (flip (isWalkable a) w . snd) nsa
-- b' = listToMaybe $ sortBy (compare `on` dist b . snd) $ filter (flip (isWalkable b) w . snd) ns b' = find (flip (isWalkable b) w . snd) nsb
a' = listToMaybe $ filter (flip (isWalkable a) w . snd) nsa
b' = listToMaybe $ filter (flip (isWalkable b) w . snd) nsb
ezipWith :: Monoid a => (b -> c -> d) -> Either a b -> Either a c -> Either a d ezipWith :: Monoid a => (b -> c -> d) -> Either a b -> Either a c -> Either a d
ezipWith f (Right x) (Right y) = Right (f x y) ezipWith f (Right x) (Right y) = Right (f x y)
@@ -116,46 +106,38 @@ ezipWith f (Left x) (Right _) = Left x
ezipWith f (Right _) (Left y) = Left y ezipWith f (Right _) (Left y) = Left y
ezipWith f (Left x) (Left y) = Left (mappend x y) ezipWith f (Left x) (Left y) = Left (mappend x y)
makePathBetween' :: Point2 -> Point2 -> World -> Either String [Int] makePathBetween' :: Point2 -> Point2 -> World -> Either String [Int]
makePathBetween' a b w = let g = _pathGraph w makePathBetween' a b w =
let g = _pathGraph w
ns = labNodes g ns = labNodes g
nsa = (_pathPoints w) `ixNZ` a nsa = _pathPoints w `ixNZ` a
nsb = (_pathPoints w) `ixNZ` b nsb = _pathPoints w `ixNZ` b
a' = case listToMaybe $ sortBy (compare `on` dist a . snd) a' = case listToMaybe $ sortBy (compare `on` dist a . snd) $ filter (flip (isWalkable a) w . snd) ns of
-- a' = case listToMaybe
$ filter (flip (isWalkable a) w . snd) ns of
Just p -> Right $ fst p Just p -> Right $ fst p
_ -> Left "FIRST POINT UNSEEN" _ -> Left "FIRST POINT UNSEEN"
b' = case listToMaybe $ sortBy (compare `on` dist b . snd) b' = case listToMaybe $ sortBy (compare `on` dist b . snd) $ filter (flip (isWalkable b) w . snd) ns of
-- b' = case listToMaybe
$ filter (flip (isWalkable b) w . snd) ns of
Just p -> Right $ fst p Just p -> Right $ fst p
_ -> Left $ "SECOND POINT UNSEEN" ++ show b _ -> Left $ "SECOND POINT UNSEEN" ++ show b
in case ezipWith (\x y -> sp x y g) a' b' of in case ezipWith (\x y -> sp x y g) a' b' of
Right (Just xs) -> Right xs Right (Just xs) -> Right xs
Right (Nothing) -> Left $ "NO PATH" ++ show a ++ show b ++ show a' ++ show b' Right Nothing -> Left $ "NO PATH" ++ show a ++ show b ++ show a' ++ show b'
Left m -> Left m Left m -> Left m
makePathBetweenPs :: Point2 -> Point2 -> World -> Maybe [Point2] makePathBetweenPs :: Point2 -> Point2 -> World -> Maybe [Point2]
--makePathBetweenPs a b = pathBetween a b makePathBetweenPs a b w = mapMaybe (lab g) <$> makePathBetween b a w
makePathBetweenPs a b w = fmap (mapMaybe (lab g)) $ makePathBetween b a w where
where g = _pathGraph w g = _pathGraph w
makePathBetweenPs' :: Point2 -> Point2 -> World -> Either String [Point2] makePathBetweenPs' :: Point2 -> Point2 -> World -> Either String [Point2]
makePathBetweenPs' a b w = fmap (mapMaybe (lab g)) $ makePathBetween' a b w makePathBetweenPs' a b w = mapMaybe (lab g) <$> makePathBetween' a b w
where g = _pathGraph w where
g = _pathGraph w
pointTowardsImpulse :: Point2 -> Point2 -> World -> Maybe Point2 pointTowardsImpulse :: Point2 -> Point2 -> World -> Maybe Point2
pointTowardsImpulse a b w = join $ fmap (listToMaybe . filter (flip (isWalkable a) w)) pointTowardsImpulse a b w = find (flip (isWalkable a) w) =<< makePathBetweenPs a b w
-- $ pathBetween a b w
$ makePathBetweenPs a b w
--
pointTowardsImpulse' :: Point2 -> Point2 -> World -> Either String Point2 pointTowardsImpulse' :: Point2 -> Point2 -> World -> Either String Point2
pointTowardsImpulse' a b w = join $ fmap (maybeToEither "NOSEEPATH" . listToMaybe . filter (flip (isWalkable a) w)) pointTowardsImpulse' a b w = (maybeToEither "NOSEEPATH" . find (flip (isWalkable a) w)) =<< makePathBetweenPs' b a w
$ makePathBetweenPs' b a w
maybeToEither :: a -> Maybe b -> Either a b maybeToEither :: a -> Maybe b -> Either a b
maybeToEither _ (Just x) = Right x maybeToEither _ (Just x) = Right x
+4 -4
View File
@@ -12,7 +12,7 @@ import Data.List
randomRanges :: (Random a,RandomGen g) => [a] -> State g a randomRanges :: (Random a,RandomGen g) => [a] -> State g a
randomRanges xs = join $ takeOne $ f xs randomRanges xs = join $ takeOne $ f xs
where where
f (x:y:ys) = (state (randomR (x,y))) : (f ys) f (x:y:ys) = state (randomR (x,y)) : f ys
f _ = [] f _ = []
takeOne :: RandomGen g => [a] -> State g a takeOne :: RandomGen g => [a] -> State g a
@@ -20,7 +20,7 @@ takeOne xs = state (randomR (0,length xs - 1)) >>= (\i -> return (xs !! i))
takeOneWeighted :: (RandomGen g, Random b, Ord b, Num b) => [b] -> [a] -> State g a takeOneWeighted :: (RandomGen g, Random b, Ord b, Num b) => [b] -> [a] -> State g a
takeOneWeighted ws xs = state (randomR (0, sum ws)) takeOneWeighted ws xs = state (randomR (0, sum ws))
>>= (\w -> return (xs !! (i w ws))) >>= (\w -> return (xs !! i w ws))
where where
i y (z:zs) i y (z:zs)
| y <= z = 0 | y <= z = 0
@@ -35,11 +35,11 @@ takeOneMore (xs,ys) = do
return (w:xs, zs ++ ws) return (w:xs, zs ++ ws)
takeNMore :: RandomGen g => Int -> ([a],[a]) -> State g ([a],[a]) takeNMore :: RandomGen g => Int -> ([a],[a]) -> State g ([a],[a])
takeNMore n p = foldr (const ((=<<) takeOneMore)) (return p) [1..n] takeNMore n p = foldr (const (>>= takeOneMore)) (return p) [1..n]
takeN :: RandomGen g => Int -> [a] -> State g [a] takeN :: RandomGen g => Int -> [a] -> State g [a]
takeN 0 xs = return [] takeN 0 xs = return []
takeN i xs = fmap fst $ takeNMore i ([],xs) takeN i xs = fst <$> takeNMore i ([],xs)
-- | Randomly shuffle a list. -- | Randomly shuffle a list.
shuffle :: RandomGen g => [a] -> State g [a] shuffle :: RandomGen g => [a] -> State g [a]
+1 -1
View File
@@ -38,7 +38,7 @@ import qualified SDL
Central drawing function. Central drawing function.
Returns a 'Word32' that should give the number of ticks it took to evaluate. Returns a 'Word32' that should give the number of ticks it took to evaluate.
-} -}
doDrawing :: RenderData -> World -> IO (Word32) doDrawing :: RenderData -> World -> IO Word32
doDrawing pdata w = do doDrawing pdata w = do
sTicks <- SDL.ticks sTicks <- SDL.ticks
clear [ColorBuffer,DepthBuffer] clear [ColorBuffer,DepthBuffer]
+4 -2
View File
@@ -169,8 +169,10 @@ ffToDraw w = filter (lineOnScreen w . _ffLine) $
_forceFields w _forceFields w
drawFF :: ForceField -> Picture drawFF :: ForceField -> Picture
drawFF (FF {_ffLine = l, _ffColor = col}) = pictures [color white $ line l, color col drawFF FF{_ffLine = l, _ffColor = col} = pictures
$ lineOfThickness 6 l ] [color white $ line l
, color col $ lineOfThickness 6 l
]
drawFFShadow :: World -> ForceField -> [Picture] drawFFShadow :: World -> ForceField -> [Picture]
drawFFShadow w ff drawFFShadow w ff
+61 -65
View File
@@ -84,10 +84,8 @@ roomPillars = over rmLinks init $ set rmPS plmnts $ roomRect 240 240 2 2
f a x b y = putBlockRect a x b y f a x b y = putBlockRect a x b y
g a b c d = f a b a b ++ f a b c d ++ f c d a b ++ f c d c d g a b c d = f a b a b ++ f a b c d ++ f c d a b ++ f c d c d
branchWith :: Room -> [Tree Room] -> Tree (Either Room Room) branchWith :: Room -> [Tree Room] -> Tree (Either Room Room)
branchWith r ts = Node (Left r) $ [return $ Right door] ++ fmap (fmap Left) ts branchWith r ts = Node (Left r) $ return (Right door) : fmap (fmap Left) ts
glassSwitchBack :: RandomGen g => State g Room glassSwitchBack :: RandomGen g => State g Room
glassSwitchBack = do glassSwitchBack = do
@@ -95,7 +93,8 @@ glassSwitchBack = do
hgt <- state $ randomR (400,600) hgt <- state $ randomR (400,600)
wllen <- state $ randomR (60,wth/2-40) wllen <- state $ randomR (60,wth/2-40)
let hf = hgt/5 let hf = hgt/5
let plmnts = [windowLine (wth-60, hf) (wllen,hf) let plmnts =
[windowLine (wth-60, hf) (wllen,hf)
,windowLine (wth-wllen,2*hf) (60, 2*hf) ,windowLine (wth-wllen,2*hf) (60, 2*hf)
,windowLine (wth-60, 3*hf) (wllen,3*hf) ,windowLine (wth-60, 3*hf) (wllen,3*hf)
,windowLine (wth-wllen,4*hf) (60, 4*hf) ,windowLine (wth-wllen,4*hf) (60, 4*hf)
@@ -103,7 +102,7 @@ glassSwitchBack = do
,blockLine (wth-wllen, 2*hf) ( wth,2*hf) ,blockLine (wth-wllen, 2*hf) ( wth,2*hf)
,blockLine ( 0, 3*hf) (wllen,3*hf) ,blockLine ( 0, 3*hf) (wllen,3*hf)
,blockLine (wth-wllen, 4*hf) ( wth,4*hf) ,blockLine (wth-wllen, 4*hf) ( wth,4*hf)
, sPS (wth/2,hgt/2) 0 $ putLamp , sPS (wth/2,hgt/2) 0 putLamp
] ]
return $ set rmPS plmnts $ roomRect wth hgt 2 6 return $ set rmPS plmnts $ roomRect wth hgt 2 6
@@ -112,19 +111,19 @@ manyDoors i = treeFromPost (replicate i (Left door)) $ Right door
glassLesson :: RandomGen g => State g (Tree (Either Room Room)) glassLesson :: RandomGen g => State g (Tree (Either Room Room))
glassLesson = do glassLesson = do
corridors <- sequence $ replicate 3 $ fmap Left $ randomiseOutLinks corridor corridors <- replicateM 3 $ Left <$> randomiseOutLinks corridor
return $ Node (Left $ botRoom) [deadRoom door,uppers, treeFromPost (Left door : corridors) $ Right door] return $ Node (Left botRoom) [deadRoom door,uppers, treeFromPost (Left door : corridors) $ Right door]
where uppers = Node (Left door) [deadRoom topRoom] where
botRoom = set rmPS botplmnts uppers = Node (Left door) [deadRoom topRoom]
$ roomRect 200 200 1 1 botRoom = set rmPS botplmnts $ roomRect 200 200 1 1
topRoom = set rmPS topplmnts topRoom = set rmPS topplmnts $ roomRect 200 200 1 1
$ roomRect 200 200 1 1 botplmnts =
botplmnts = [sPS (0,0) 0 $ PutWall (rectNSWE (200) 0 (90) (110)) [sPS (0,0) 0 $ PutWall (rectNSWE 200 0 90 110) defaultCrystalWall
$ defaultCrystalWall
,sPS (50,100) 0 $ PutCrit miniGunCrit ,sPS (50,100) 0 $ PutCrit miniGunCrit
,sPS (50,50) 0 putLamp ,sPS (50,50) 0 putLamp
] ]
topplmnts = [windowLine (100,200) (100,0) topplmnts =
[windowLine (100,200) (100,0)
,sPS (50,100) 0 $ PutCrit miniGunCrit ,sPS (50,100) 0 $ PutCrit miniGunCrit
,sPS (50,50) 0 putLamp ,sPS (50,50) 0 putLamp
] ]
@@ -145,7 +144,7 @@ miniRoom1 = do
,windowLine (wth-60, 40+3*hf) (wllen,40+3*hf) ,windowLine (wth-60, 40+3*hf) (wllen,40+3*hf)
,windowLine (wth-wllen,40+4*hf) (60,40+4*hf) ,windowLine (wth-wllen,40+4*hf) (60,40+4*hf)
,sPS (crx,cry) 0 $ PutCrit miniGunCrit ,sPS (crx,cry) 0 $ PutCrit miniGunCrit
,sPS (wth-20,hgt/2+40) 0 $ randC ,sPS (wth-20,hgt/2+40) 0 randC
,sPS (wth/2,hgt/2) 0 putLamp ,sPS (wth/2,hgt/2) 0 putLamp
,blockLine ( 0, 40+1*hf) (wllen,40+1*hf) ,blockLine ( 0, 40+1*hf) (wllen,40+1*hf)
,blockLine (wth-wllen, 40+2*hf) ( wth,40+2*hf) ,blockLine (wth-wllen, 40+2*hf) ( wth,40+2*hf)
@@ -155,9 +154,10 @@ miniRoom1 = do
return $ set rmPS plmnts $ shiftRoomBy ((0,40),0) $ roomRect wth hgt 2 4 return $ set rmPS plmnts $ shiftRoomBy ((0,40),0) $ roomRect wth hgt 2 4
miniTree2 :: RandomGen g => State g (Tree (Either Room Room)) miniTree2 :: RandomGen g => State g (Tree (Either Room Room))
miniTree2 = miniRoom1 >>= randomiseOutLinks >>= changeLinkTo (\p -> (snd . fst) p < 70) miniTree2 = miniRoom1
>>= return . flip branchWith (replicate 3 $ treeFromPost [door,corridor] >>= randomiseOutLinks
critInDeadEnd ) >>= changeLinkTo (\p -> (snd . fst) p < 70)
<&> flip branchWith (replicate 3 $ treeFromPost [door,corridor] critInDeadEnd)
miniRoom3 :: RandomGen g => State g (Tree (Either Room Room)) miniRoom3 :: RandomGen g => State g (Tree (Either Room Room))
miniRoom3 = do miniRoom3 = do
@@ -200,7 +200,7 @@ roomMiniIntro = fmap (g . expandTreeBy f) $ sequence $ treeFromPost
[return $ connectRoom door [return $ connectRoom door
,join $ takeOne [miniTree2,glassLesson] ,join $ takeOne [miniTree2,glassLesson]
] ]
$ fmap connectRoom $ randomiseOutLinks corridor $ connectRoom <$> randomiseOutLinks corridor
where where
f (Node (Right x) xs) = Node (Right (Right x)) $ map f xs f (Node (Right x) xs) = Node (Right (Right x)) $ map f xs
f (Node (Left x) xs) = Node (Left (Left x)) $ map f xs f (Node (Left x) xs) = Node (Left (Left x)) $ map f xs
@@ -245,7 +245,7 @@ allPairs xs = [(x,y) | x <- xs, y <- xs, x /= y]
randomCorridorFrom :: RandomGen g => [a] -> State g (Tree (Either a a)) randomCorridorFrom :: RandomGen g => [a] -> State g (Tree (Either a a))
randomCorridorFrom xs = do randomCorridorFrom xs = do
rooms <- sequence $ replicate 5 $ takeOne xs rooms <- replicateM 5 $ takeOne xs
return $ treeFromTrunk (map Left $ init rooms) (Node (Right (last rooms)) []) return $ treeFromTrunk (map Left $ init rooms) (Node (Right (last rooms)) [])
{- Probabilites of the type of the first floor weapon. -} {- Probabilites of the type of the first floor weapon. -}
randFirstWeapon :: State StdGen PSType randFirstWeapon :: State StdGen PSType
@@ -264,23 +264,25 @@ weaponEmptyRoom :: RandomGen g => State g (Tree (Either Room Room))
weaponEmptyRoom = do weaponEmptyRoom = do
w <- state $ randomR (220,300) w <- state $ randomR (220,300)
h <- state $ randomR (220,300) h <- state $ randomR (220,300)
let plmnts = [sPS (w/2,h-40) 0 $ RandPS randFirstWeapon let plmnts =
,sPS (20,20) (pi/2) $ randC1 [sPS (w/2,h-40) 0 $ RandPS randFirstWeapon
,sPS (w-20,20) (pi/2) $ randC1 ,sPS (20,20) (pi/2) randC1
,sPS (w/2,h/2) 0 $ putLamp ,sPS (w-20,20) (pi/2) randC1
,sPS (w/2,h/2) 0 putLamp
] ]
(fmap connectRoom . randomiseOutLinks) =<< (changeLinkTo ((\p -> dist p (w/2,0) < 10) . fst) (fmap connectRoom . randomiseOutLinks) =<<
$ set rmPS plmnts $ roomRect w h 2 2) changeLinkTo ((\p -> dist p (w/2,0) < 10) . fst) (set rmPS plmnts $ roomRect w h 2 2)
weaponUnderCrits :: RandomGen g => State g (Tree (Either Room Room)) weaponUnderCrits :: RandomGen g => State g (Tree (Either Room Room))
weaponUnderCrits = do weaponUnderCrits = do
let plmnts = let plmnts =
[sPS (20,0) 0 $ RandPS randFirstWeapon [sPS (20,0) 0 $ RandPS randFirstWeapon
,sPS (20,0) (0-pi/2) $ randC1 ,sPS (20,0) (negate $ pi/2) randC1
,sPS (20,20) (0-pi/2) $ randC1 ,sPS (20,20) (negate $ pi/2) randC1
] ]
let continuationRoom = treeFromTrunk [Left corridorN,Left corridorN] let continuationRoom = treeFromTrunk
(connectRoom (set rmPS plmnts $ corridorN)) [Left corridorN,Left corridorN]
(connectRoom (set rmPS plmnts corridorN))
rcp' <- roomCenterPillar rcp' <- roomCenterPillar
let rcp = over rmPS ( sPS (120,80) 0 putLamp : ) rcp' let rcp = over rmPS ( sPS (120,80) 0 putLamp : ) rcp'
deadEndRoom <- takeOne [roomPillars,rcp] deadEndRoom <- takeOne [roomPillars,rcp]
@@ -295,14 +297,16 @@ weaponBehindPillar :: RandomGen g => State g (Tree (Either Room Room))
weaponBehindPillar = do weaponBehindPillar = do
crPos <- takeOne $ [(x,y) | x <- [20,220], y <- [20,220]] ++ [(120,160),(120,200)] crPos <- takeOne $ [(x,y) | x <- [20,220], y <- [20,220]] ++ [(120,160),(120,200)]
let d p = argV $ (120,80) -.- p let d p = argV $ (120,80) -.- p
let plmnts1 = [sPS (120,160) 0 $ RandPS randFirstWeapon let plmnts1 =
,sPS crPos (d crPos) $ randC1 [sPS (120,160) 0 $ RandPS randFirstWeapon
,sPS crPos (d crPos) randC1
] ]
rcp <- roomCenterPillar rcp <- roomCenterPillar
return $ treeFromTrunk [Left door return $ treeFromTrunk
,Left $ over rmLinks tail $ over rmPS (++ plmnts1) rcp] [Left door
(connectRoom $ set rmPS [sPS (20,60) (0-pi/2) $ randC1] ,Left $ over rmLinks tail $ over rmPS (++ plmnts1) rcp
$ corridorN) ]
(connectRoom $ set rmPS [sPS (20,60) (negate $ pi/2) randC1] corridorN)
weaponBetweenPillars :: RandomGen g => State g (Tree (Either Room Room)) weaponBetweenPillars :: RandomGen g => State g (Tree (Either Room Room))
weaponBetweenPillars = do weaponBetweenPillars = do
@@ -313,34 +317,31 @@ weaponBetweenPillars = do
d p = argV $ (120,120) -.- p d p = argV $ (120,120) -.- p
plmnts = plmnts =
[sPS wpPos 0 $ RandPS randFirstWeapon [sPS wpPos 0 $ RandPS randFirstWeapon
,sPS crPos1 (d crPos1) $ randC1 ,sPS crPos1 (d crPos1) randC1
,sPS crPos2 (d crPos2) $ randC1 ,sPS crPos2 (d crPos2) randC1
] ]
(fmap connectRoom . randomiseOutLinks) =<< (filterLinks f $ over rmPS (++plmnts) $ roomPillars) (fmap connectRoom . randomiseOutLinks) =<< filterLinks f (over rmPS (++plmnts) roomPillars)
where where
f (_,a) = a == 0 f (_,a) = a == 0
weaponLongCorridor :: RandomGen g => State g (Tree (Either Room Room)) weaponLongCorridor :: RandomGen g => State g (Tree (Either Room Room))
weaponLongCorridor = do weaponLongCorridor = do
root <- takeOne $ [tEast, tWest] root <- takeOne [tEast, tWest]
connectingRoom <- takeOne connectingRoom <- takeOne
[tEast & rmPS .~ [sPS (-40,60) 0 $ putLamp] [tEast & rmPS .~ [sPS (-40,60) 0 putLamp]
,tWest & rmPS .~ [sPS ( 40,60) 0 $ putLamp] ,tWest & rmPS .~ [sPS ( 40,60) 0 putLamp]
] ]
i1 <- state $ randomR (2,5) i1 <- state $ randomR (2,5)
i2 <- state $ randomR (2,5) i2 <- state $ randomR (2,5)
let branch1 = treeFromTrunk (replicate i1 $ Left corridorN) (connectRoom $ putCrs connectingRoom) let branch1 = treeFromTrunk (replicate i1 $ Left corridorN) (connectRoom $ putCrs connectingRoom)
let branch2 = treeFromTrunk (replicate i2 $ Left corridorN) (deadRoom $ putWp corridor) let branch2 = treeFromTrunk (replicate i2 $ Left corridorN) (deadRoom $ putWp corridor)
return $ Node (Left root) [branch1,branch2] return $ Node (Left root) [branch1,branch2]
where putCrs = over rmPS (++ [sPS (10,40) (-pi/2) $ randC where
,sPS (-10,40) (-pi/2) $ randC putCrs = over rmPS (++ [sPS (10,40) (-pi/2) randC ,sPS (-10,40) (-pi/2) randC ])
]) putWp = set rmPS [sPS (20,40) 0 $ RandPS randFirstWeapon ,sPS (20,60) 0 putLamp ]
putWp = set rmPS [sPS (20,40) 0 $ RandPS randFirstWeapon
,sPS (20,60) 0 $ putLamp
]
critInDeadEnd :: Room critInDeadEnd :: Room
critInDeadEnd = set rmPS [sPS (0,0) 0 $ randC] deadEndRoom critInDeadEnd = set rmPS [sPS (0,0) 0 randC] deadEndRoom
deadEndRoom :: Room deadEndRoom :: Room
deadEndRoom = Room deadEndRoom = Room
@@ -365,8 +366,8 @@ weaponRoom = join $ takeOne
roomCCrits :: RandomGen g => State g (Tree (Either Room Room)) roomCCrits :: RandomGen g => State g (Tree (Either Room Room))
roomCCrits = do roomCCrits = do
ps <- sequence $ replicate 20 $ randInCirc 9 ps <- replicateM 20 $ randInCirc 9
let plmnts = map (\p -> sPS p 0 $ randC) let plmnts = map (\p -> sPS p 0 randC)
$ zipWith (+.+) [(x,y) | x<-[110,130,150,170,190], y<- [70,90,110,130,150]] ps $ zipWith (+.+) [(x,y) | x<-[110,130,150,170,190], y<- [70,90,110,130,150]] ps
lamps = [sPS (50,100) 0 putLamp , sPS (175,100) 0 putLamp] lamps = [sPS (50,100) 0 putLamp , sPS (175,100) 0 putLamp]
return $ connectRoom $ over rmPS ((lamps ++) . (plmnts ++)) $ roomC 200 200 return $ connectRoom $ over rmPS ((lamps ++) . (plmnts ++)) $ roomC 200 200
@@ -384,28 +385,26 @@ longRoom = do
,rectNSWE (h-35) (h-135) 65 85 ,rectNSWE (h-35) (h-135) 65 85
] ]
let wsDefense = map (\ps -> sPS (0,0) 0 $ PutWall ps defaultCrystalWall) let wsDefense = map (\ps -> sPS (0,0) 0 $ PutWall ps defaultCrystalWall)
[rectNSWE (95) (70) 0 25 [rectNSWE 95 70 0 25
,rectNSWE (95) (70) 50 75 ,rectNSWE 95 70 50 75
] ]
brls <- fmap (map (\p -> sPS (p +.+ (10,200)) 0 $ PutCrit explosiveBarrel) ) brls <- fmap (map (\p -> sPS (p +.+ (10,200)) 0 $ PutCrit explosiveBarrel) )
$ sequence $ replicate 5 $ randInRect (w-20) 900 $ replicateM 5 $ randInRect (w-20) 900
let rm = roomRect w (h+70) 1 1 & rmPolys %~ ([rectNSWE h (h-165) (-45) (w+45)] ++) let rm = roomRect w (h+70) 1 1 & rmPolys %~ ([rectNSWE h (h-165) (-45) (w+45)] ++)
changeLinkTo cond $ set rmPS (ws ++ brls ++ wsDefense ++ changeLinkTo cond $ rm & rmPS .~ ws ++ brls ++ wsDefense ++
[sPS ( 12.5,h-25) 0 $ PutCrit longCrit [sPS ( 12.5,h-25) 0 $ PutCrit longCrit
,sPS ( 37.5,h-25) 0 $ PutCrit longCrit ,sPS ( 37.5,h-25) 0 $ PutCrit longCrit
,sPS ( 62.5,h-25) 0 $ PutCrit longCrit ,sPS ( 62.5,h-25) 0 $ PutCrit longCrit
,sPS ( 25, 20) 0 $ putLamp ,sPS ( 25, 20) 0 putLamp
,sPS ( 25, h-10) 0 $ putLamp ,sPS ( 25,h-10) 0 putLamp
] ]
)
$ rm
shooterRoom :: RandomGen g => State g Room shooterRoom :: RandomGen g => State g Room
shooterRoom = do shooterRoom = do
h <- state $ randomR (200,300) h <- state $ randomR (200,300)
let cond x = (snd . fst) x < h - 40 let cond x = (snd . fst) x < h - 40
changeLinkTo cond $ set rmPS ( [blockLine (50,50) (50,h) changeLinkTo cond $ roomRect 100 h 1 1 & rmPS .~
[blockLine (50,50) (50,h)
,sPS ( 25,h-25) 0 $ PutCrit $ addArmour autoCrit ,sPS ( 25,h-25) 0 $ PutCrit $ addArmour autoCrit
,sPS ( 75,h-30) 0 $ PutCrit explosiveBarrel ,sPS ( 75,h-30) 0 $ PutCrit explosiveBarrel
,sPS ( 75,h-60) 0 $ PutCrit explosiveBarrel ,sPS ( 75,h-60) 0 $ PutCrit explosiveBarrel
@@ -413,9 +412,6 @@ shooterRoom = do
,sPS ( 85,h-45) 0 $ PutCrit explosiveBarrel ,sPS ( 85,h-45) 0 $ PutCrit explosiveBarrel
,sPS ( 75,h-80) 0 putLamp ,sPS ( 75,h-80) 0 putLamp
] ]
)
$ roomRect 100 h 1 1
shootersRoom1 :: RandomGen g => State g Room shootersRoom1 :: RandomGen g => State g Room
shootersRoom1 = do shootersRoom1 = do
+4 -4
View File
@@ -70,13 +70,13 @@ resumeSound w = w
Consider replacing instances with 'soundOncePos'. Consider replacing instances with 'soundOncePos'.
-} -}
soundOnce :: Int -> World -> World soundOnce :: Int -> World -> World
soundOnce i = over soundQueue ((:) (i,0)) soundOnce i = soundQueue %~ ((i,0) : )
{-| Play a sound with a given position in the world. {-| Play a sound with a given position in the world.
Uses the angle between the given position and '_cameraViewFrom', taking into account '_cameraRot'. Uses the angle between the given position and '_cameraViewFrom', taking into account '_cameraRot'.
-} -}
soundOncePos :: Int -> Point2 -> World -> World soundOncePos :: Int -> Point2 -> World -> World
soundOncePos i pos w = over soundQueue ((:) (i,a)) w soundOncePos i pos w = w & soundQueue %~ ((i,a) :)
where where
a = soundAngle pos w a = soundAngle pos w
@@ -88,7 +88,7 @@ soundOnceOrigin
-> SoundOrigin -- ^ The \"creator\" of the sound -> SoundOrigin -- ^ The \"creator\" of the sound
-> Point2 -- ^ The position of the sound in the world -> Point2 -- ^ The position of the sound in the world
-> World -> World -> World -> World
soundOnceOrigin sType so p w = over sounds (M.insertWith (flip const) so theSound) w soundOnceOrigin sType so p w = w & sounds %~ M.insertWith (\ _ x -> x) so theSound
where where
theSound = Sound theSound = Sound
{ _soundChunkID = sType { _soundChunkID = sType
@@ -141,7 +141,7 @@ soundFrom
-> Int -- ^ Frames to play -> Int -- ^ Frames to play
-> Int -- ^ Fade out time (ms) -> Int -- ^ Fade out time (ms)
-> World -> World -> World -> World
soundFrom so sType time fadeTime w = over sounds (M.insertWith f so sound) w soundFrom so sType time fadeTime = sounds %~ M.insertWith f so sound
where where
sound = Sound sound = Sound
{ _soundChunkID = sType { _soundChunkID = sType
+11 -7
View File
@@ -9,7 +9,6 @@ import Dodge.Data
import Dodge.Data.Menu import Dodge.Data.Menu
import Dodge.World.Trigger.Data import Dodge.World.Trigger.Data
import Dodge.Config.Data import Dodge.Config.Data
import Dodge.Data.Menu
import Dodge.Base import Dodge.Base
import Dodge.WallCreatureCollisions import Dodge.WallCreatureCollisions
import Dodge.LevelGen.Block import Dodge.LevelGen.Block
@@ -67,6 +66,7 @@ update' w = case _menuLayers w of
. zoneClouds . zoneClouds
. updateClouds . updateClouds
. updateCreatures . updateCreatures
. updateCreatureGroups
. updateBlocks . updateBlocks
. updateSeenWalls . updateSeenWalls
. updateSoundQueue . updateSoundQueue
@@ -84,6 +84,10 @@ update' w = case _menuLayers w of
cid = _clID cr cid = _clID cr
doubleArgumentFor f x = f x x doubleArgumentFor f x = f x x
updateCreatureGroups :: World -> World
updateCreatureGroups w = w & creatureGroups %~
IM.mapMaybe (\cgp -> _crGroupUpdate cgp w cgp)
updateTriggers :: World -> World updateTriggers :: World -> World
updateTriggers w updateTriggers w
| ResetLevel 1 `S.member` _worldTriggers w = generateFromList levx $ initialWorld | ResetLevel 1 `S.member` _worldTriggers w = generateFromList levx $ initialWorld
@@ -119,7 +123,7 @@ updateCreatures w = f $ set randGen newG $ set creatures (IM.mapMaybe id crs) w
{- | {- |
Apply door mechanisms. -} Apply door mechanisms. -}
updateWalls :: World -> World updateWalls :: World -> World
updateWalls w = IM.foldr (maybe id id . (^? doorMech)) w (_walls w) updateWalls w = IM.foldr (fromMaybe id . (^? doorMech)) w (_walls w)
ppEvents :: World -> World ppEvents :: World -> World
ppEvents w = IM.foldr (\pp w -> _ppEvent pp pp w) w $ _pressPlates w ppEvents w = IM.foldr (\pp w -> _ppEvent pp pp w) w $ _pressPlates w
@@ -158,8 +162,8 @@ moveCloud c w = _clEffect c c . theUpdate $ w
oldPos = _clPos c oldPos = _clPos c
newPos = oldPos +.+ newVel newPos = oldPos +.+ newVel
hitWl = collideCircWalls' oldPos newPos 5 $ wallsNearPoint newPos w hitWl = collideCircWalls' oldPos newPos 5 $ wallsNearPoint newPos w
finalPos = fromMaybe newPos (fmap fst hitWl) finalPos = maybe newPos fst hitWl
finalVel = fromMaybe newVel (fmap snd hitWl) finalVel = maybe newVel snd hitWl
theUpdate w' = w' theUpdate w' = w'
& clouds . ix (_clID c) . clTimer %~ (\t -> t - 1) & clouds . ix (_clID c) . clTimer %~ (\t -> t - 1)
& clouds . ix (_clID c) . clVel .~ finalVel & clouds . ix (_clID c) . clVel .~ finalVel
@@ -168,7 +172,7 @@ moveCloud c w = _clEffect c c . theUpdate $ w
clClSpringVel :: Cloud -> World -> Cloud -> Point2 -> Point2 clClSpringVel :: Cloud -> World -> Cloud -> Point2 -> Point2
clClSpringVel a w b v clClSpringVel a w b v
| ida == idb = v | ida == idb = v
| dist pa pb < radDist = v +.+ 0.1 *.* (safeNormalizeV (pa -.- pb)) | dist pa pb < radDist = v +.+ 0.1 *.* safeNormalizeV (pa -.- pb)
| otherwise = v | otherwise = v
where where
ida = _clID a ida = _clID a
@@ -181,7 +185,7 @@ simpleCrSprings :: World -> World
simpleCrSprings w = IM.foldr' crSpring w $ _creatures w simpleCrSprings w = IM.foldr' crSpring w $ _creatures w
crSpring :: Creature -> World -> World crSpring :: Creature -> World -> World
crSpring c w = IM.foldr' (crCrSpring c) w $ cs crSpring c w = IM.foldr' (crCrSpring c) w cs
where where
cs = creaturesNearPoint (_crPos c) w cs = creaturesNearPoint (_crPos c) w
@@ -196,7 +200,7 @@ crCrSpring c1 c2 w
id1 = _crID c1 id1 = _crID c1
id2 = _crID c2 id2 = _crID c2
vec = _crPos c1 -.- _crPos c2 vec = _crPos c1 -.- _crPos c2
diff = magV $ vec diff = magV vec
comRad = _crRad c1 + _crRad c2 comRad = _crRad c1 + _crRad c2
overlap1 = ((comRad - diff) * _crMass c2 * 0.5 / massT) *.* errorNormalizeV 55 vec overlap1 = ((comRad - diff) * _crMass c2 * 0.5 / massT) *.* errorNormalizeV 55 vec
overlap2 = ((comRad - diff) * _crMass c1 * 0.5 / massT) *.* errorNormalizeV 56 vec overlap2 = ((comRad - diff) * _crMass c1 * 0.5 / massT) *.* errorNormalizeV 56 vec
+5 -5
View File
@@ -27,7 +27,7 @@ colCrWall w c
rad = _crRad c + wallBuffer rad = _crRad c + wallBuffer
p1 = _crOldPos c p1 = _crOldPos c
p2 = _crPos c p2 = _crPos c
ls = IM.elems $ fmap _wlLine $ wallsNearPoint p2 w ls = IM.elems $ _wlLine <$> wallsNearPoint p2 w
wallPoints = nub $ concatMap (\(x,y) -> [x,y]) ls wallPoints = nub $ concatMap (\(x,y) -> [x,y]) ls
-- colCrPushThrough :: World -> Creature -> Creature -- colCrPushThrough :: World -> Creature -> Creature
@@ -65,13 +65,13 @@ pushOrCrush :: [(Point2,Point2)] -> Creature -> Creature
pushOrCrush wls cr = case mapMaybe (pushOutFromWall (_crRad cr) cpos) wls of pushOrCrush wls cr = case mapMaybe (pushOutFromWall (_crRad cr) cpos) wls of
[] -> cr [] -> cr
[p] -> cr & crPos .~ p [p] -> cr & crPos .~ p
_ -> cr & crState . crDamage %~ ( (Blunt 50 cpos cpos cpos) :) _ -> cr & crState . crDamage %~ ( Blunt 50 cpos cpos cpos : )
where where
cpos = _crPos cr cpos = _crPos cr
-- assumes that the wall is orientated -- assumes that the wall is orientated
-- assumes wall points are different -- assumes wall points are different
pushOutFromWall :: Float -> Point2 -> (Point2,Point2) -> Maybe (Point2) pushOutFromWall :: Float -> Point2 -> (Point2,Point2) -> Maybe Point2
pushOutFromWall rad cp2 (wp1,wp2) pushOutFromWall rad cp2 (wp1,wp2)
| isOnWall = Just newP -- +.+ (1 *.* norm)) | isOnWall = Just newP -- +.+ (1 *.* norm))
| otherwise = Nothing | otherwise = Nothing
@@ -88,7 +88,7 @@ pushOutFromCorners :: World -> Creature -> Creature
pushOutFromCorners w cr = cr & crPos .~ newPos pushOutFromCorners w cr = cr & crPos .~ newPos
where where
newPos = foldr (intersectCirclePoint (_crRad cr)) (_crPos cr) ls newPos = foldr (intersectCirclePoint (_crRad cr)) (_crPos cr) ls
ls = nub . concatMap (\(x,y) -> [x,y]) . IM.elems $ fmap _wlLine $ wallsNearPoint (_crPos cr) w ls = nub . concatMap (\(x,y) -> [x,y]) . IM.elems $ _wlLine <$> wallsNearPoint (_crPos cr) w
collideCorners :: Float -> Point2 -> [Point2] -> Point2 -> Point2 collideCorners :: Float -> Point2 -> [Point2] -> Point2 -> Point2
collideCorners rad p1 ps p2 = foldr (intersectCirclePoint rad) p2 ps collideCorners rad p1 ps p2 = foldr (intersectCirclePoint rad) p2 ps
@@ -103,7 +103,7 @@ checkPushThroughs :: Float -> Point2 -> [(Point2,Point2)] -> Point2 -> Point2
checkPushThroughs rad cp1 walls cp2 checkPushThroughs rad cp1 walls cp2
= fromMaybe cp2 $ (listToMaybe.mapMaybe (checkPushThrough rad cp1 cp2)) walls = fromMaybe cp2 $ (listToMaybe.mapMaybe (checkPushThrough rad cp1 cp2)) walls
checkPushThrough :: Float -> Point2 -> Point2 -> (Point2,Point2) -> Maybe (Point2) checkPushThrough :: Float -> Point2 -> Point2 -> (Point2,Point2) -> Maybe Point2
checkPushThrough rad cp1 cp2 (wp1,wp2) checkPushThrough rad cp1 cp2 (wp1,wp2)
| isPushedThrough = intersectSegSeg' cp1 cp2 wp1 wp2 | isPushedThrough = intersectSegSeg' cp1 cp2 wp1 wp2
| otherwise = Nothing | otherwise = Nothing
+6 -6
View File
@@ -39,12 +39,12 @@ import Data.Function
import Data.List import Data.List
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
createBarrelSpark :: Int -> Int -> Point2 -> Float -> Maybe Int -> World -> World createBarrelSpark :: Point2 -> Float -> Maybe Int -> Int -> Int -> World -> World
createBarrelSpark time colid pos dir maycid w = over worldEvents createBarrelSpark pos dir maycid time colid w
((.) $ ( over particles ((:) spark) = over worldEvents (( over particles (spark :) . sparkFlashAt pos') . ) w
. sparkFlashAt pos') where
) w spark = Bul'
where spark = Bul' { _ptDraw = drawBul { _ptDraw = drawBul
, _ptUpdate' = mvGenBullet' , _ptUpdate' = mvGenBullet'
, _btVel' = rotateV dir (5,0) , _btVel' = rotateV dir (5,0)
, _btColor' = numColor colid , _btColor' = numColor colid
+1 -1
View File
@@ -72,7 +72,7 @@ mvShockwave is w pt
t = _btTimer' pt t = _btTimer' pt
tFraction = fromIntegral t / fromIntegral (_btMaxTime' pt) tFraction = fromIntegral t / fromIntegral (_btMaxTime' pt)
rad = r - (3/4) * r * tFraction rad = r - (3/4) * r * tFraction
dams = over creatures (IM.map damCr) . flip (foldr damageBlocks) hitBlocks dams = over creatures (IM.map damCr) . flip (IM.foldr damageBlocks) hitBlocks
hitBlocks = wallsOnCirc p rad $ wallsNearPoint p w hitBlocks = wallsOnCirc p rad $ wallsNearPoint p w
damageBlocks wall w damageBlocks wall w
= case wall ^? blHP of = case wall ^? blHP of
+4 -4
View File
@@ -17,17 +17,17 @@ left (DS (_,l,_)) = l
right (DS (_,_,r)) = r right (DS (_,_,r)) = r
pushL :: DS a -> DS a pushL :: DS a -> DS a
pushL (DS (x,xs,(y:ys))) = DS (y,(x:xs),ys) pushL (DS (x,xs, y:ys )) = DS (y, x:xs ,ys)
pushL ds = ds pushL ds = ds
pushR :: DS a -> DS a pushR :: DS a -> DS a
pushR (DS (y,(x:xs),ys)) = DS (x,xs,(y:ys)) pushR (DS (y, x:xs ,ys)) = DS (x,xs, y:ys )
pushR ds = ds pushR ds = ds
cycleL :: DS a -> Maybe (DS a) cycleL :: DS a -> Maybe (DS a)
cycleL (DS (x,xs,(y:ys))) = Just $ DS (y,(x:xs),ys) cycleL (DS (x,xs, y:ys )) = Just $ DS (y, x:xs ,ys)
cycleL _ = Nothing cycleL _ = Nothing
cycleR :: DS a -> Maybe (DS a) cycleR :: DS a -> Maybe (DS a)
cycleR (DS (y,(x:xs),ys)) = Just $ DS (x,xs,(y:ys)) cycleR (DS (y, x:xs ,ys)) = Just $ DS (x,xs, y:ys )
cycleR _ = Nothing cycleR _ = Nothing
+21 -73
View File
@@ -24,16 +24,13 @@ import Geometry.Vector
import Data.Function import Data.Function
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import Control.Applicative import Control.Applicative
-- | Return a point a distance away from a first point towards a second point. -- | Return a point a distance away from a first point towards a second point.
-- Does not go past the second point. -- Does not go past the second point.
alongSegBy :: Float -> Point2 -> Point2 -> Point2 alongSegBy :: Float -> Point2 -> Point2 -> Point2
alongSegBy !x !a !b = a +.+ y *.* normalizeV (b -.- a) alongSegBy !x !a !b = a +.+ y *.* normalizeV (b -.- a)
where where
y = min x $ dist a b y = min x $ dist a b
-- | Given a line and a point return the point on the line closest to the -- | Given a line and a point return the point on the line closest to the
-- point. -- point.
closestPointOnLine closestPointOnLine
@@ -44,7 +41,6 @@ closestPointOnLine
{-# INLINE closestPointOnLine #-} {-# INLINE closestPointOnLine #-}
closestPointOnLine !a !b !p = a +.+ u *.* (b -.- a) closestPointOnLine !a !b !p = a +.+ u *.* (b -.- a)
where u = closestPointOnLineParam a b p where u = closestPointOnLineParam a b p
-- | Given a line and a point return a value corresponding to how far along the -- | Given a line and a point return a value corresponding to how far along the
-- line the point is. -- line the point is.
closestPointOnLineParam closestPointOnLineParam
@@ -55,36 +51,28 @@ closestPointOnLineParam
{-# INLINE closestPointOnLineParam #-} {-# INLINE closestPointOnLineParam #-}
closestPointOnLineParam !a !b !p closestPointOnLineParam !a !b !p
= (p -.- a) `dotV` (b -.- a) / (b -.- a) `dotV` (b -.- a) = (p -.- a) `dotV` (b -.- a) / (b -.- a) `dotV` (b -.- a)
-- | Draw a rectangle based on maximal N E S W values. -- | Draw a rectangle based on maximal N E S W values.
rectNESW :: Float -> Float -> Float -> Float -> [Point2] rectNESW :: Float -> Float -> Float -> Float -> [Point2]
rectNESW !a !b !c !d = [(b,a),(b,c),(d,c),(d,a) ] rectNESW !a !b !c !d = [(b,a),(b,c),(d,c),(d,a) ]
-- | Draw a rectangle based on maximal N S E W values. -- | Draw a rectangle based on maximal N S E W values.
rectNSEW :: Float -> Float -> Float -> Float -> [Point2] rectNSEW :: Float -> Float -> Float -> Float -> [Point2]
rectNSEW !n !s !e !w = rectNESW n e s w rectNSEW !n !s !e !w = rectNESW n e s w
-- | Draw a rectangle based on maximal N S W E values. -- | Draw a rectangle based on maximal N S W E values.
rectNSWE :: Float -> Float -> Float -> Float -> [Point2] rectNSWE :: Float -> Float -> Float -> Float -> [Point2]
rectNSWE !n !s !w !e = [ (w,n), (w,s), (e,s), (e,n)] rectNSWE !n !s !w !e = [ (w,n), (w,s), (e,s), (e,n)]
-- | Draw a rectangle around the origin with given height and width
rectWdthHght :: Float -> Float -> [Point2] rectWdthHght :: Float -> Float -> [Point2]
rectWdthHght w h = rectNSWE h (-h) (-w) w rectWdthHght w h = rectNSWE h (-h) (-w) w
-- | Draw a rectangle around the origin with given height and width
-- | Test whether a point is in a polygon or on the polygon border. -- | Test whether a point is in a polygon or on the polygon border.
-- Supposes the points in the -- Supposes the points in the
-- polygon are listed in anticlockwise order. -- polygon are listed in anticlockwise order.
pointInOrOnPolygon :: Point2 -> [Point2] -> Bool pointInOrOnPolygon :: Point2 -> [Point2] -> Bool
pointInOrOnPolygon !p (x:xs) = all (\l -> not (uncurry isRHS l p)) $ zip (x:xs) (xs ++ [x]) pointInOrOnPolygon !p (x:xs) = all (\l -> not (uncurry isRHS l p)) $ zip (x:xs) (xs ++ [x])
-- | Test whether a point is strictly inside a polygon. -- | Test whether a point is strictly inside a polygon.
-- Supposes the points in the polygon are listed in anticlockwise order. -- Supposes the points in the polygon are listed in anticlockwise order.
pointInPolygon :: Point2 -> [Point2] -> Bool pointInPolygon :: Point2 -> [Point2] -> Bool
pointInPolygon !p [] = False pointInPolygon !p [] = False
pointInPolygon !p (x:xs) = all (\l -> uncurry (errorIsLHS 1) l p) $ zip (x:xs) (xs ++ [x]) pointInPolygon !p (x:xs) = all (\l -> uncurry (errorIsLHS 1) l p) $ zip (x:xs) (xs ++ [x])
-- | Debug version of 'pointInPolygon'. -- | Debug version of 'pointInPolygon'.
errorPointInPolygon :: Int -> Point2 -> [Point2] -> Bool errorPointInPolygon :: Int -> Point2 -> [Point2] -> Bool
errorPointInPolygon !i !p xs errorPointInPolygon !i !p xs
@@ -92,36 +80,30 @@ errorPointInPolygon !i !p xs
| length xs == 2 = error "two point polygon" | length xs == 2 = error "two point polygon"
| nub xs == xs = pointInPolygon p xs | nub xs == xs = pointInPolygon p xs
| otherwise = error $ "errorPointInPolygon "++ show i | otherwise = error $ "errorPointInPolygon "++ show i
-- | Debug version of 'normalizeV'. -- | Debug version of 'normalizeV'.
errorNormalizeV :: Int -> Point2 -> Point2 errorNormalizeV :: Int -> Point2 -> Point2
errorNormalizeV !i (0,0) = error $ "problem with function: errorNormalizeV "++show i errorNormalizeV !i (0,0) = error $ "problem with function: errorNormalizeV "++show i
errorNormalizeV !i !p = normalizeV p errorNormalizeV !i !p = normalizeV p
-- | Debug version of 'angleVV'. -- | Debug version of 'angleVV'.
errorAngleVV :: Int -> Point2 -> Point2 -> Float errorAngleVV :: Int -> Point2 -> Point2 -> Float
errorAngleVV !i (0,0) _ = error $ "problem with function: errorAngleVV "++show i errorAngleVV !i (0,0) _ = error $ "problem with function: errorAngleVV "++show i
errorAngleVV !i _ (0,0) = error $ "problem with function: errorAngleVV "++show i errorAngleVV !i _ (0,0) = error $ "problem with function: errorAngleVV "++show i
errorAngleVV !i !p !p' = angleVV p p' errorAngleVV !i !p !p' = angleVV p p'
-- | Debug version of 'isLHS'. -- | Debug version of 'isLHS'.
errorIsLHS :: Int -> Point2 -> Point2 -> Point2 -> Bool errorIsLHS :: Int -> Point2 -> Point2 -> Point2 -> Bool
errorIsLHS !i !x !y errorIsLHS !i !x !y
| x == y = error $ "problem with function: errorIsLHS " ++show i | x == y = error $ "problem with function: errorIsLHS " ++show i
| otherwise = isLHS x y | otherwise = isLHS x y
-- | Debug version of 'closestPointOnLine' -- | Debug version of 'closestPointOnLine'
errorClosestPointOnLine :: Int -> Point2 -> Point2 -> Point2 -> Point2 errorClosestPointOnLine :: Int -> Point2 -> Point2 -> Point2 -> Point2
errorClosestPointOnLine !i !x !y errorClosestPointOnLine !i !x !y
| x == y = error $ "problem with function: errorClosestPointOnLine " ++show i | x == y = error $ "problem with function: errorClosestPointOnLine " ++show i
| otherwise = closestPointOnLine x y | otherwise = closestPointOnLine x y
-- | Debug version of 'closestPointOnLineParam' -- | Debug version of 'closestPointOnLineParam'
errorClosestPointOnLineParam :: Int -> Point2 -> Point2 -> Point2 -> Float errorClosestPointOnLineParam :: Int -> Point2 -> Point2 -> Point2 -> Float
errorClosestPointOnLineParam !i !x! y! z errorClosestPointOnLineParam !i !x! y! z
| x == y = dist x z | x == y = dist x z
| otherwise = closestPointOnLineParam x y z | otherwise = closestPointOnLineParam x y z
-- | Test whether a point is on the LHS of a line. -- | Test whether a point is on the LHS of a line.
-- Returns False if the line is of zero length. -- Returns False if the line is of zero length.
isLHS isLHS
@@ -141,7 +123,6 @@ isLHS
a2 = y' - y a2 = y' - y
b1 = x'' - x b1 = x'' - x
b2 = y'' - y b2 = y'' - y
-- | Test whether a point is on the LHS of a line. -- | Test whether a point is on the LHS of a line.
-- Returns False if the line is of zero length. -- Returns False if the line is of zero length.
isRHS isRHS
@@ -161,14 +142,12 @@ isRHS
a2 = y' - y a2 = y' - y
b1 = x'' - x b1 = x'' - x
b2 = y'' - y b2 = y'' - y
-- | Reorder points to be anticlockwise around their center. -- | Reorder points to be anticlockwise around their center.
orderPolygon :: [Point2] -> [Point2] orderPolygon :: [Point2] -> [Point2]
orderPolygon [] = [] orderPolygon [] = []
orderPolygon ps = sortBy (compare `on` \p -> argV (p -.- cen)) ps orderPolygon ps = sortBy (compare `on` \p -> argV (p -.- cen)) ps
where where
cen = 1/ fromIntegral (length ps) *.* foldr1 (+.+) ps cen = 1/ fromIntegral (length ps) *.* foldr1 (+.+) ps
-- | Adds a point to a convex polygon. -- | Adds a point to a convex polygon.
-- If the point is inside, returns the original. -- If the point is inside, returns the original.
-- Points ordered anticlockwise, input not checked. -- Points ordered anticlockwise, input not checked.
@@ -176,21 +155,17 @@ addPointPolygon :: Point2 -> [Point2] -> [Point2]
addPointPolygon p ps addPointPolygon p ps
| pointInOrOnPolygon p ps = ps | pointInOrOnPolygon p ps = ps
| otherwise = orderPolygon $ p : ps | otherwise = orderPolygon $ p : ps
-- | Creates the convex hull of a set of points. -- | Creates the convex hull of a set of points.
convexHull :: [Point2] -> [Point2] convexHull :: [Point2] -> [Point2]
convexHull (x:y:z:xs) = foldr addPointPolygon (orderPolygon (x:y:z:[])) xs convexHull (x:y:z:xs) = foldr addPointPolygon (orderPolygon [x,y,z]) xs
convexHull _ = error "Tried to create the convex hull of two or less points" convexHull _ = error "Tried to create the convex hull of two or less points"
-- | Return distance between two points. -- | Return distance between two points.
dist :: Point2 -> Point2 -> Float dist :: Point2 -> Point2 -> Float
{-# INLINE dist #-} {-# INLINE dist #-}
dist !p1 !p2 = magV (p2 -.- p1) dist !p1 !p2 = magV (p2 -.- p1)
-- | Return midpoint between two points. -- | Return midpoint between two points.
pHalf :: Point2 -> Point2 -> Point2 pHalf :: Point2 -> Point2 -> Point2
pHalf !a !b = 0.5 *.* (a +.+ b) pHalf !a !b = 0.5 *.* (a +.+ b)
-- | Test whether a circle is on a segment by intersecting a new normal segment through the -- | Test whether a circle is on a segment by intersecting a new normal segment through the
-- center of the circle with the segment itself. -- center of the circle with the segment itself.
-- Returns False if the circle center is beyond the enpoints of the -- Returns False if the circle center is beyond the enpoints of the
@@ -202,7 +177,6 @@ circOnSegNoEndpoints !p1 !p2 !c !rad = isJustTrue (fmap (\p -> magV (p -.- c) <
y = intersectSegLine' p1 p2 c (c +.+ vNormal (p1 -.- p2)) y = intersectSegLine' p1 p2 c (c +.+ vNormal (p1 -.- p2))
isJustTrue (Just True) = True isJustTrue (Just True) = True
isJustTrue _ = False isJustTrue _ = False
-- | Test whether a circle is on a segment by intersecting a normal and testing -- | Test whether a circle is on a segment by intersecting a normal and testing
-- the distance to the endpoints of the segment. -- the distance to the endpoints of the segment.
circOnSeg :: Point2 -> Point2 -> Point2 -> Float -> Bool circOnSeg :: Point2 -> Point2 -> Point2 -> Float -> Bool
@@ -213,29 +187,24 @@ circOnSeg !p1 !p2 !c !rad = magV (p1 -.- c) <= rad || magV (p2 -.- c) <= rad
y = intersectSegLine' p1 p2 c (c +.+ vNormal (p1 -.- p2)) y = intersectSegLine' p1 p2 c (c +.+ vNormal (p1 -.- p2))
isJustTrue (Just True) = True isJustTrue (Just True) = True
isJustTrue _ = False isJustTrue _ = False
-- | Find the difference between two Nums. -- | Find the difference between two Nums.
difference :: (Ord a, Num a) => a -> a -> a difference :: (Ord a, Num a) => a -> a -> a
difference x y difference x y
| x > y = x - y | x > y = x - y
| otherwise = y - x | otherwise = y - x
-- | Given vector line direction and a vector movement, -- | Given vector line direction and a vector movement,
-- reflects the movement accoring to the line. -- reflects the movement accoring to the line.
reflectIn :: Point2 -> Point2 -> Point2 reflectIn :: Point2 -> Point2 -> Point2
reflectIn line vec = reflectIn line vec = rotateV angle vec
let angle = 2 * angleBetween line vec where
in rotateV angle vec angle = 2 * angleBetween line vec
-- | Find angle between two points. -- | Find angle between two points.
-- Not normalised, ranges from -2*pi to 2*pi. -- Not normalised, ranges from -2*pi to 2*pi.
angleBetween :: Point2 -> Point2 -> Float angleBetween :: Point2 -> Point2 -> Float
angleBetween v1 v2 = argV v1 - argV v2 angleBetween v1 v2 = argV v1 - argV v2
-- | Return a list containing two copies of a pair. -- | Return a list containing two copies of a pair.
doublePair :: (a,a) -> [(a,a)] doublePair :: (a,a) -> [(a,a)]
doublePair (x,y) = [(x,y),(y,x)] doublePair (x,y) = [(x,y),(y,x)]
-- | Test whether two polygons intersect by testing the intersection of each -- | Test whether two polygons intersect by testing the intersection of each
-- consecutive pair of points. -- consecutive pair of points.
polysIntersect :: [Point2] -> [Point2] -> Bool polysIntersect :: [Point2] -> [Point2] -> Bool
@@ -245,40 +214,32 @@ polysIntersect (p:ps) (q:qs)
pairs1 = zip (p:ps) (ps++[p]) pairs1 = zip (p:ps) (ps++[p])
pairs2 = zip (q:qs) (qs++[q]) pairs2 = zip (q:qs) (qs++[q])
polysIntersect _ _ = False polysIntersect _ _ = False
-- | Test whether two polygons intersect or if one is contained in the other. -- | Test whether two polygons intersect or if one is contained in the other.
polysOverlap :: [Point2] -> [Point2] -> Bool polysOverlap :: [Point2] -> [Point2] -> Bool
polysOverlap (p:ps) (q:qs) = polysIntersect (p:ps) (q:qs) polysOverlap (p:ps) (q:qs) = polysIntersect (p:ps) (q:qs)
|| pointInPolygon p (q:qs) || pointInPolygon p (q:qs)
|| pointInPolygon q (p:ps) || pointInPolygon q (p:ps)
polysOverlap _ _ = False polysOverlap _ _ = False
-- | Test whether any polygons from a first list intersect with any polygons from -- | Test whether any polygons from a first list intersect with any polygons from
-- a second list. -- a second list.
anyPolyssIntersect :: [[Point2]] -> [[Point2]] -> Bool anyPolyssIntersect :: [[Point2]] -> [[Point2]] -> Bool
anyPolyssIntersect x y = or $ polysIntersect <$> x <*> y anyPolyssIntersect x y = or $ polysIntersect <$> x <*> y
-- | Return n equidistant points on a circle with a radius of 600. -- | Return n equidistant points on a circle with a radius of 600.
nRays :: Int -> [Point2] nRays :: Int -> [Point2]
nRays n = take n $ iterate (rotateV (2*pi/fromIntegral n)) (600,0) nRays n = take n $ iterate (rotateV (2*pi/fromIntegral n)) (600,0)
-- | Return n equidistant points on a circle with a radius of x. -- | Return n equidistant points on a circle with a radius of x.
nRaysRad :: Int -> Float -> [Point2] nRaysRad :: Int -> Float -> [Point2]
nRaysRad n x = take n $ iterate (rotateV (2*pi/fromIntegral n)) (x,0) nRaysRad n x = take n $ iterate (rotateV (2*pi/fromIntegral n)) (x,0)
-- | Test whether an angle is to the left of another angle, according to the -- | Test whether an angle is to the left of another angle, according to the
-- smallest change in rotation between them. -- smallest change in rotation between them.
-- This appears to sometimes fail if the angles are not normalized. -- This appears to sometimes fail if the angles are not normalized.
isLeftOfA :: Float -> Float -> Bool isLeftOfA :: Float -> Float -> Bool
isLeftOfA angle1 angle2 = isLeftOfA angle1 angle2 = (angle1 - angle2 < pi && angle1 > angle2)
(angle1 - angle2 < pi && angle1 > angle2)
|| (angle2 - angle1 > pi && angle2 > angle1) || (angle2 - angle1 > pi && angle2 > angle1)
-- | Test whether a vector is to the left of another, according to the smallest -- | Test whether a vector is to the left of another, according to the smallest
-- change of rotation between them. -- change of rotation between them.
isLeftOf :: Point2 -> Point2 -> Bool isLeftOf :: Point2 -> Point2 -> Bool
isLeftOf x y = isLeftOfA (argV x) (argV y) isLeftOf x y = isLeftOfA (argV x) (argV y)
-- | Find the difference between two angles. -- | Find the difference between two angles.
-- Possibly not correct... -- Possibly not correct...
diffAngles :: Float -> Float -> Float diffAngles :: Float -> Float -> Float
@@ -292,7 +253,6 @@ diffAngles x y
differenceAngles = diffAngles differenceAngles = diffAngles
angleDifference = diffAngles angleDifference = diffAngles
-- | Given a triangle where we know the length of a first side, -- | Given a triangle where we know the length of a first side,
-- the length of a second side, and the angle between the first side and the -- the length of a second side, and the angle between the first side and the
-- third side, finds the length of the third side. -- third side, finds the length of the third side.
@@ -305,7 +265,6 @@ ssaTri ab bc a
let c = asin ( (ab * sin a)/bc) let c = asin ( (ab * sin a)/bc)
b = pi - (a + c) b = pi - (a + c)
in sin b * bc / sin a in sin b * bc / sin a
-- | Given two points of a triangle and a third point, return -- | Given two points of a triangle and a third point, return
-- the point which lies between pa and pc' on a line from pb of length bc. -- the point which lies between pa and pc' on a line from pb of length bc.
-- Note that there are likely two such points, this should return the point -- Note that there are likely two such points, this should return the point
@@ -316,7 +275,6 @@ ssaTriPoint pa pb pc' bc
a = errorAngleVV 6 (pb -.- pa) (pc' -.- pa) a = errorAngleVV 6 (pb -.- pa) (pc' -.- pa)
ac = ssaTri ab bc a ac = ssaTri ab bc a
in pa +.+ (ac *.* errorNormalizeV 47 (pc' -.- pa)) in pa +.+ (ac *.* errorNormalizeV 47 (pc' -.- pa))
-- | Safe version of 'ssaTriPoint'. -- | Safe version of 'ssaTriPoint'.
ssaTriPoint' :: Point2 -> Point2 -> Point2 -> Float -> Maybe Point2 ssaTriPoint' :: Point2 -> Point2 -> Point2 -> Float -> Maybe Point2
ssaTriPoint' pa pb pc' bc ssaTriPoint' pa pb pc' bc
@@ -333,41 +291,34 @@ ssaTriPointCorrect pa pb pc' bc
where where
p = ssaTriPoint pa pb pc' bc p = ssaTriPoint pa pb pc' bc
param = closestPointOnLineParam pa pc' p param = closestPointOnLineParam pa pc' p
-- | Given a segment and external point, find the closest point on the segment. -- | Given a segment and external point, find the closest point on the segment.
closestPointOnSeg :: Point2 -> Point2 -> Point2 -> Point2 closestPointOnSeg :: Point2 -> Point2 -> Point2 -> Point2
closestPointOnSeg segP1 segP2 p closestPointOnSeg segP1 segP2 p
| errorClosestPointOnLineParam 3 segP1 segP2 p <= 0 = segP1 | errorClosestPointOnLineParam 3 segP1 segP2 p <= 0 = segP1
| errorClosestPointOnLineParam 4 segP1 segP2 p >= 1 = segP2 | errorClosestPointOnLineParam 4 segP1 segP2 p >= 1 = segP2
| otherwise = errorClosestPointOnLine 2 segP1 segP2 p | otherwise = errorClosestPointOnLine 2 segP1 segP2 p
-- | Return Just a point if it is inside a circle, Nothing otherwise. -- | Return Just a point if it is inside a circle, Nothing otherwise.
pointInCircle :: Point2 -> Float -> Point2 -> Maybe Point2 pointInCircle :: Point2 -> Float -> Point2 -> Maybe Point2
pointInCircle p r c pointInCircle p r c
| p == c = Just p | p == c = Just p
| magV (p -.- c) < r = Just p | magV (p -.- c) < r = Just p
| otherwise = Nothing | otherwise = Nothing
-- | Determines if a moving point intersects with a circle, -- | Determines if a moving point intersects with a circle,
-- if so, returns a point on circle that intersects with the line passing -- if so, returns a point on circle that intersects with the line passing
-- throught the circle : HOPEFULLY THE CORRECT OF THE TWO! -- throught the circle : HOPEFULLY THE CORRECT OF THE TWO!
collidePointCirc :: Point2 -> Point2 -> Float -> Point2 -> Maybe Point2 collidePointCirc :: Point2 -> Point2 -> Float -> Point2 -> Maybe Point2
collidePointCirc p1 p2 rad c = ssaTriPoint' p2 c p1 rad collidePointCirc p1 p2 rad c = ssaTriPoint' p2 c p1 rad
-- | As 'collidePointCirc', but changes the point to a measure of the distance. -- | As 'collidePointCirc', but changes the point to a measure of the distance.
collidePointCirc' :: Point2 -> Point2 -> Float -> Point2 -> Maybe Float collidePointCirc' :: Point2 -> Point2 -> Float -> Point2 -> Maybe Float
collidePointCirc' p1 p2 rad c = fmap (\x -> magV (x -.- p1)) collidePointCirc' p1 p2 rad c = fmap (\x -> magV (x -.- p1))
(collidePointCirc p1 p2 rad c) (collidePointCirc p1 p2 rad c)
-- | As 'collidePointCirc', but returns both the point and the measure of the distance. -- | As 'collidePointCirc', but returns both the point and the measure of the distance.
collidePointCirc'' :: Point2 -> Point2 -> Float -> Point2 -> Maybe (Point2,Float) collidePointCirc'' :: Point2 -> Point2 -> Float -> Point2 -> Maybe (Point2,Float)
collidePointCirc'' p1 p2 rad c = (,) <$> collidePointCirc p1 p2 rad c collidePointCirc'' p1 p2 rad c = (,) <$> collidePointCirc p1 p2 rad c
<*> collidePointCirc' p1 p2 rad c <*> collidePointCirc' p1 p2 rad c
-- | As 'collidePointCirc', but uses the supposedly correct version of ssaTriPoint. -- | As 'collidePointCirc', but uses the supposedly correct version of ssaTriPoint.
collidePointCircCorrect :: Point2 -> Point2 -> Float -> Point2 -> Maybe Point2 collidePointCircCorrect :: Point2 -> Point2 -> Float -> Point2 -> Maybe Point2
collidePointCircCorrect p1 p2 rad c = ssaTriPointCorrect p2 c p1 rad collidePointCircCorrect p1 p2 rad c = ssaTriPointCorrect p2 c p1 rad
-- | Finds the height of a triangle using herons formula. -- | Finds the height of a triangle using herons formula.
-- The base is the line between the first two points. -- The base is the line between the first two points.
heron :: Point2 -> Point2 -> Point2 -> Float heron :: Point2 -> Point2 -> Point2 -> Float
@@ -380,7 +331,6 @@ heron x y z
s = (a+b+c)/2 s = (a+b+c)/2
area = sqrt(s*(s-a)*(s-b)*(s-c)) area = sqrt(s*(s-a)*(s-b)*(s-c))
in 2*area/a in 2*area/a
-- | Multiplies reflection in normal by factor. -- | Multiplies reflection in normal by factor.
reflectInParam :: Float -> Point2 -> Point2 -> Point2 reflectInParam :: Float -> Point2 -> Point2 -> Point2
reflectInParam x line vec = reflectInParam x line vec =
@@ -388,7 +338,6 @@ reflectInParam x line vec =
rAng = rotateV angle vec rAng = rotateV angle vec
p = x *.* errorClosestPointOnLine 3 (0,0) (vNormal line) rAng p = x *.* errorClosestPointOnLine 3 (0,0) (vNormal line) rAng
in rAng -.- p in rAng -.- p
--reflectIn' :: Point2 -> Point2 -> Point2 -> Point2 -> Point2 --reflectIn' :: Point2 -> Point2 -> Point2 -> Point2 -> Point2
--reflectIn' l1 l2 v1 v2 = v1 +.+ reflectIn (l1 -.- l2) (v2 -.- v1) --reflectIn' l1 l2 v1 v2 = v1 +.+ reflectIn (l1 -.- l2) (v2 -.- v1)
@@ -397,22 +346,19 @@ isOnSeg l1 l2 p =
errorClosestPointOnLineParam 10 l1 (l1 +.+ vNormal (l2 -.- l1)) p == 0 errorClosestPointOnLineParam 10 l1 (l1 +.+ vNormal (l2 -.- l1)) p == 0
&& errorClosestPointOnLineParam 11 l1 l2 p <= 1 && errorClosestPointOnLineParam 11 l1 l2 p <= 1
&& errorClosestPointOnLineParam 12 l1 l2 p >= 0 && errorClosestPointOnLineParam 12 l1 l2 p >= 0
-- | Divide a segment into a list of points with a maximal distance between -- | Divide a segment into a list of points with a maximal distance between
-- them. -- them.
-- the take 5000 here is a hack, otherwise divideLine seems to sometimes -- the take 5000 here is a hack, otherwise divideLine seems to sometimes
-- generate an infinite list, and I don't know why -- generate an infinite list, and I don't know why
divideLine :: Float -> Point2 -> Point2 -> [Point2] divideLine :: Float -> Point2 -> Point2 -> [Point2]
--divideLine x a b = map (\i -> a +.+ (i / (fromIntegral numPoints)) *.* (b -.- a)) --divideLine x a b = map (\i -> a +.+ (i / (fromIntegral numPoints)) *.* (b -.- a))
divideLine x a b = divideLine x a b = take 5000
take 5000
$ map (\i -> a +.+ (fromIntegral i / fromIntegral numPoints *.* (b -.- a)) ) $ map (\i -> a +.+ (fromIntegral i / fromIntegral numPoints *.* (b -.- a)) )
ns ns
where where
d = dist a b d = dist a b
numPoints = max 1 $ ceiling $ d / x numPoints = max 1 $ ceiling $ d / x
ns = [0 .. numPoints] ns = [0 .. numPoints]
-- | As 'divideLine', but must return an odd number of points. -- | As 'divideLine', but must return an odd number of points.
divideLineOddNumPoints :: Float -> Point2 -> Point2 -> [Point2] divideLineOddNumPoints :: Float -> Point2 -> Point2 -> [Point2]
--divideLine x a b = map (\i -> a +.+ (i / (fromIntegral numPoints)) *.* (b -.- a)) --divideLine x a b = map (\i -> a +.+ (i / (fromIntegral numPoints)) *.* (b -.- a))
@@ -422,22 +368,25 @@ divideLineOddNumPoints x a b = take 5000
where where
d = dist a b d = dist a b
numPoints' = max 1 $ ceiling $ d / x numPoints' = max 1 $ ceiling $ d / x
numPoints | even numPoints' = numPoints' numPoints
| even numPoints' = numPoints'
| otherwise = numPoints' + 1 | otherwise = numPoints' + 1
ns = [0 .. numPoints] ns = [0 .. numPoints]
-- | Given two pairs of Ints, returns a list of pairs of Ints that form -- | Given two pairs of Ints, returns a list of pairs of Ints that form
-- a digital line between them. -- a digital line between them.
digitalLine :: (Int,Int) -> (Int,Int) -> [(Int,Int)] digitalLine :: (Int,Int) -> (Int,Int) -> [(Int,Int)]
{-# INLINE digitalLine #-} {-# INLINE digitalLine #-}
digitalLine (x1,y1) (x2,y2) digitalLine (x1,y1) (x2,y2)
| abs (x1-x2) > abs (y1-y2) = [ (x,( (y1-y2) * x + x1*y2 - x2*y1) `rdiv` (x1-x2) ) | abs (x1-x2) > abs (y1-y2) =
| x <- intervalList x1 x2 ] [ (x,( (y1-y2) * x + x1*y2 - x2*y1) `rdiv` (x1-x2) )
| otherwise = [ ( ((x1-x2) * y + y1*x2 - y2*x1) `rdiv` (y1-y2) , y) | x <- intervalList x1 x2
| y <- intervalList y1 y2 ] ]
| otherwise =
[ ( ((x1-x2) * y + y1*x2 - y2*x1) `rdiv` (y1-y2) , y)
| y <- intervalList y1 y2
]
where where
rdiv a b = round $ fromIntegral a / fromIntegral b rdiv a b = round $ fromIntegral a / fromIntegral b
-- | Given two pairs of 'Int's, create a list of pairs of 'Int's that form a -- | Given two pairs of 'Int's, create a list of pairs of 'Int's that form a
-- rectangle between them. -- rectangle between them.
digitalRect :: (Int,Int) -> (Int,Int) -> [(Int,Int)] digitalRect :: (Int,Int) -> (Int,Int) -> [(Int,Int)]
@@ -448,13 +397,11 @@ digitalRect (a,b) (c,d) = [(s,t) | s <- [minx .. maxx] , t <- [miny .. maxy]]
minx = min a c minx = min a c
maxy = max b d maxy = max b d
miny = min b d miny = min b d
-- | Given two Ints, creates the list of Ints between these. -- | Given two Ints, creates the list of Ints between these.
intervalList :: Int -> Int -> [Int] intervalList :: Int -> Int -> [Int]
intervalList x y intervalList x y
| y >= x = [x .. y] | y >= x = [x .. y]
| otherwise = reverse [y..x] | otherwise = reverse [y..x]
-- | Create points on the circumference of a circle with maximal distance -- | Create points on the circumference of a circle with maximal distance
-- between them. -- between them.
divideCircle :: Float -> Point2 -> Float -> [Point2] divideCircle :: Float -> Point2 -> Float -> [Point2]
@@ -478,7 +425,7 @@ arcStepwisePositive
-> Point2 -- ^ Center -> Point2 -- ^ Center
-> Point2 -- ^ Start vector from center -> Point2 -- ^ Start vector from center
-> [Point2] -> [Point2]
arcStepwisePositive ssize a cen v = ((cen +.+) . (\rot -> rotateV rot v) ) <$> rots arcStepwisePositive ssize a cen v = (cen +.+) . (`rotateV` v) <$> rots
where where
rots :: [Float] rots :: [Float]
rots = map ((a*) . (/ fromIntegral n ) . fromIntegral) [0 .. n] rots = map ((a*) . (/ fromIntegral n ) . fromIntegral) [0 .. n]
@@ -502,7 +449,6 @@ makeLoopPairs :: [Point2] -> [(Point2,Point2)]
makeLoopPairs [] = error "tried to make loop with empty list of points" makeLoopPairs [] = error "tried to make loop with empty list of points"
makeLoopPairs [x] = error "tried to make loop with singleton list of points" makeLoopPairs [x] = error "tried to make loop with singleton list of points"
makeLoopPairs (x:xs) = zip (x:xs) (xs ++ [x]) makeLoopPairs (x:xs) = zip (x:xs) (xs ++ [x])
-- | Test whether a point is in a cone. -- | Test whether a point is in a cone.
-- Note the pair is ordered. -- Note the pair is ordered.
-- Doesn't work for obtuse angles. -- Doesn't work for obtuse angles.
@@ -512,4 +458,6 @@ pointIsInCone
-> Point2 -- ^ Point to test. -> Point2 -- ^ Point to test.
-> Bool -> Bool
pointIsInCone c (rightp,leftp) p = isLHS c rightp p && isLHS leftp c p pointIsInCone c (rightp,leftp) p = isLHS c rightp p && isLHS leftp c p
-- | TODO: implement using Control.Foldl
centroid :: Foldable t => t Point2 -> Point2
centroid xs = 1 / fromIntegral (length xs) *.* foldl' (+.+) (0,0) xs
+2 -2
View File
@@ -1,6 +1,6 @@
{- | {- |
Module : Loop Module : Loop
Description : Minimal game loop Description : Simple game loop
This module sets up an SDL window which may be updated using a simple game loop. This module sets up an SDL window which may be updated using a simple game loop.
-} -}
@@ -41,7 +41,7 @@ setupLoop
startWorld <- ioStartWorld startWorld <- ioStartWorld
initializeAll initializeAll
bracket bracket
(createWindow (T.pack "A Minimal Game Loop") (winConfig xSize ySize)) (createWindow (T.pack "Simple Game Loop") (winConfig xSize ySize))
destroyWindow destroyWindow
$ \window -> bracket $ \window -> bracket
(glCreateContext window) (glCreateContext window)
-1
View File
@@ -1,4 +1,3 @@
{-# LANGUAGE TemplateHaskell #-}
module Music module Music
where where
import qualified SDL.Mixer as Mix import qualified SDL.Mixer as Mix
+9 -9
View File
@@ -120,7 +120,7 @@ extrapolate (ox,oy) (ax,ay) (bx,by) (x,y) =
color :: RGBA -> Picture -> Picture color :: RGBA -> Picture -> Picture
{-# INLINE color #-} {-# INLINE color #-}
color c pic = OverPic id id 0 (const c) pic color c = OverPic id id 0 (const c)
translate3 :: Float -> Float -> Point3 -> Point3 translate3 :: Float -> Float -> Point3 -> Point3
{-# INLINE translate3 #-} {-# INLINE translate3 #-}
@@ -128,15 +128,15 @@ translate3 a b (x,y,z) = (x+a,y+b,z)
translate :: Float -> Float -> Picture -> Picture translate :: Float -> Float -> Picture -> Picture
{-# INLINE translate #-} {-# INLINE translate #-}
translate x y pic = OverPic (translate3 x y) id 0 id pic translate x y = OverPic (translate3 x y) id 0 id
setDepth :: Float -> Picture -> Picture setDepth :: Float -> Picture -> Picture
{-# INLINE setDepth #-} {-# INLINE setDepth #-}
setDepth d pic = OverPic (\(x,y,_) -> (x,y,d)) id 0 id pic setDepth d = OverPic (\(x,y,_) -> (x,y,d)) id 0 id
setLayer :: Int -> Picture -> Picture setLayer :: Int -> Picture -> Picture
{-# INLINE setLayer #-} {-# INLINE setLayer #-}
setLayer i pic = OnLayer i pic setLayer = OnLayer
scale3 :: Float -> Float -> Point3 -> Point3 scale3 :: Float -> Float -> Point3 -> Point3
{-# INLINE scale3 #-} {-# INLINE scale3 #-}
@@ -144,7 +144,7 @@ scale3 a b (x,y,z) = (x*a,y*b,z)
scale :: Float -> Float -> Picture -> Picture scale :: Float -> Float -> Picture -> Picture
{-# INLINE scale #-} {-# INLINE scale #-}
scale x y pic = OverPic (scale3 x y) (\(a,b) ->(a*x,b*y)) 0 id pic scale x y = OverPic (scale3 x y) (\(a,b) ->(a*x,b*y)) 0 id
rotate3 :: Float -> Point3 -> Point3 rotate3 :: Float -> Point3 -> Point3
{-# INLINE rotate3 #-} {-# INLINE rotate3 #-}
@@ -154,7 +154,7 @@ rotate3 a (x,y,z) = (x',y',z)
rotate :: Float -> Picture -> Picture rotate :: Float -> Picture -> Picture
{-# INLINE rotate #-} {-# INLINE rotate #-}
rotate a pic = OverPic (rotate3 a) id a id pic rotate a = OverPic (rotate3 a) id a id
pictures :: [Picture] -> Picture pictures :: [Picture] -> Picture
{-# INLINE pictures #-} {-# INLINE pictures #-}
@@ -162,9 +162,9 @@ pictures = Pictures
makeArc :: Float -> (Float,Float) -> [Point2] makeArc :: Float -> (Float,Float) -> [Point2]
{-# INLINE makeArc #-} {-# INLINE makeArc #-}
makeArc rad (a,b) = zipWith rotateV as (repeat (0,rad)) makeArc rad (a,b) = map (`rotateV` (0,rad)) angles
where where
as = [a,a+step.. b] angles = [a,a+step.. b]
step = pi * 0.2 step = pi * 0.2
circleSolid :: Float -> Picture circleSolid :: Float -> Picture
@@ -203,7 +203,7 @@ thickLine ps t = pictures $ f ps
thickCircle :: Float -> Float -> Picture thickCircle :: Float -> Float -> Picture
{-# INLINE thickCircle #-} {-# INLINE thickCircle #-}
thickCircle rad wdth = thickArc 0 (2*pi) rad wdth thickCircle = thickArc 0 (2*pi)
arcSolid :: Float -> Float -> Float -> Picture arcSolid :: Float -> Float -> Float -> Picture
{-# INLINE arcSolid #-} {-# INLINE arcSolid #-}
+1 -1
View File
@@ -1,4 +1,4 @@
{-# LANGUAGE DefaultSignatures, TypeOperators, FlexibleContexts #-} {-# LANGUAGE TypeOperators, FlexibleContexts #-}
{- | Pulled from {- | Pulled from
https://stackoverflow.com/questions/10112733/haskell-simple-constructor-comparison-function https://stackoverflow.com/questions/10112733/haskell-simple-constructor-comparison-function
-} -}
+9 -13
View File
@@ -1,4 +1,3 @@
{-# LANGUAGE QuasiQuotes #-}
module Shader module Shader
( makeShader ( makeShader
, addTexture , addTexture
@@ -47,7 +46,7 @@ extractProgAndUnis :: FullShader a -> (Program,[UniformLocation])
extractProgAndUnis s = (_shaderProgram s, _shaderUniforms s) extractProgAndUnis s = (_shaderProgram s, _shaderUniforms s)
pokeShaders :: [FullShader a] -> F.FoldM IO a [Int] pokeShaders :: [FullShader a] -> F.FoldM IO a [Int]
pokeShaders fss = traverse pokeShader fss pokeShaders = traverse pokeShader
pokeShader :: FullShader a -> F.FoldM IO a Int pokeShader :: FullShader a -> F.FoldM IO a Int
pokeShader fs = F.FoldM (pokeRender fls (zip ptrs nAtss)) (return 0) return pokeShader fs = F.FoldM (pokeRender fls (zip ptrs nAtss)) (return 0) return
@@ -61,18 +60,17 @@ pokeRender :: (a -> [[[Float]]])
pokeRender toFs ptrs n rt = pokeList ptrs n (toFs rt) pokeRender toFs ptrs n rt = pokeList ptrs n (toFs rt)
pokeList :: [(Ptr Float,Int)] -> Int -> [[[Float]]] -> IO Int pokeList :: [(Ptr Float,Int)] -> Int -> [[[Float]]] -> IO Int
pokeList ptrs n fsss = foldM (pokePtrs ptrs) n fsss pokeList ptrs = foldM (pokePtrs ptrs)
pokePtrs :: [(Ptr Float,Int)] -> Int -> [[Float]] -> IO Int pokePtrs :: [(Ptr Float,Int)] -> Int -> [[Float]] -> IO Int
pokePtrs ptrIs n fss = do pokePtrs ptrIs n fss = do
zipWithM_ f ptrIs fss zipWithM_ f ptrIs fss
return $ n + 1 return $ n + 1
where f (ptr,i) fs = pokeArrayOff ptr (i*n) fs where
f (ptr,i) fs = pokeArrayOff ptr (i*n) fs
pokeArrayOff :: Storable a => Ptr a -> Int -> [a] -> IO () pokeArrayOff :: Storable a => Ptr a -> Int -> [a] -> IO ()
pokeArrayOff ptr i xs = pokeArrayOff ptr i = zipWithM_ (pokeElemOff ptr) [i..]
zipWithM_ (pokeElemOff ptr) [i..] xs
bindArrayBuffers :: Int -> [(BufferObject,Ptr Float,Int)] -> IO () bindArrayBuffers :: Int -> [(BufferObject,Ptr Float,Int)] -> IO ()
{-# INLINE bindArrayBuffers #-} {-# INLINE bindArrayBuffers #-}
@@ -82,22 +80,20 @@ bindArrayBuffers numVs ps = do
bufferData ArrayBuffer $= (fromIntegral $ floatSize * numVs * i, ptr, StreamDraw) bufferData ArrayBuffer $= (fromIntegral $ floatSize * numVs * i, ptr, StreamDraw)
bindShaderBuffers :: [FullShader a] -> [Int] -> IO () bindShaderBuffers :: [FullShader a] -> [Int] -> IO ()
bindShaderBuffers fss is = bindShaderBuffers = zipWithM_ f
zipWithM_ f fss is
where where
f fs i = bindArrayBuffers i $ _vaoBufferTargets $ _shaderVAO fs f fs i = bindArrayBuffers i $ _vaoBufferTargets $ _shaderVAO fs
drawShaders :: [FullShader a] -> [Int] -> IO () drawShaders :: [FullShader a] -> [Int] -> IO ()
drawShaders fss is = drawShaders = zipWithM_ drawShader
zipWithM_ drawShader fss is
drawShader :: FullShader a -> Int -> IO () drawShader :: FullShader a -> Int -> IO ()
{-# INLINE drawShader #-} {-# INLINE drawShader #-}
drawShader fs i = do drawShader fs i = do
currentProgram $= Just (_shaderProgram fs) currentProgram $= Just (_shaderProgram fs)
bindVertexArrayObject $= (Just (_vao $ _shaderVAO fs)) bindVertexArrayObject $= Just (_vao $ _shaderVAO fs)
case _shaderTexture fs of case _shaderTexture fs of
Just (ShaderTexture {_textureObject = to}) Just ShaderTexture{_textureObject = to}
-> textureBinding Texture2D $= Just to -> textureBinding Texture2D $= Just to
_ -> return () _ -> return ()
drawArrays (_shaderDrawPrimitive fs) 0 (fromIntegral i) drawArrays (_shaderDrawPrimitive fs) 0 (fromIntegral i)
+4 -8
View File
@@ -50,10 +50,7 @@ In the update:
-} -}
playAndUpdate :: Ord a => SoundData a -> M.Map a Sound -> IO (M.Map a Sound) playAndUpdate :: Ord a => SoundData a -> M.Map a Sound -> IO (M.Map a Sound)
playAndUpdate sData newSounds playAndUpdate sData newSounds
= updateSounds (_loadedChunks sData) (mergeSounds newSounds (_playingSounds sData)) = updateSounds (_loadedChunks sData) (M.unionWith mergeSound newSounds (_playingSounds sData))
mergeSounds :: Ord a => M.Map a Sound -> M.Map a Sound -> M.Map a Sound
mergeSounds as bs = M.unionWith mergeSound as bs
mergeSound :: Sound -> Sound -> Sound mergeSound :: Sound -> Sound -> Sound
mergeSound newS oldS mergeSound newS oldS
@@ -85,7 +82,7 @@ tryPlay sd s = do
Mix.halt i Mix.halt i
Mix.playOn i Mix.Once (sd IM.! _soundChunkID s) Mix.playOn i Mix.Once (sd IM.! _soundChunkID s)
return $ s return $ s
& soundChannel .~ Just i & soundChannel ?~ i
& soundStatus .~ Playing & soundStatus .~ Playing
repetitions :: Sound -> Mix.Times repetitions :: Sound -> Mix.Times
@@ -100,14 +97,13 @@ tryGetChannel s = case _soundChannel s of
decrementTimer :: Sound -> IO Sound decrementTimer :: Sound -> IO Sound
decrementTimer s = case _soundTime s of decrementTimer s = case _soundTime s of
Just t | t > 0 -> return $ s & soundTime .~ Just (t - 1) Just t
| t > 0 -> return $ s & soundTime ?~ t - 1
| otherwise -> fadeOutMaybe (_soundChannel s) (_soundFadeTime s) | otherwise -> fadeOutMaybe (_soundChannel s) (_soundFadeTime s)
>> return (s & soundTime .~ Nothing >> return (s & soundTime .~ Nothing
& soundStatus .~ FadingOut) & soundStatus .~ FadingOut)
Nothing -> return s Nothing -> return s
--applyPosition = return
applyPosition :: Sound -> IO Sound applyPosition :: Sound -> IO Sound
applyPosition s = case _soundPos s of applyPosition s = case _soundPos s of
Nothing -> return s Nothing -> return s
+3 -3
View File
@@ -30,11 +30,11 @@ polygonStrictlyConvex ps = True
--prop_looping :: [Point2] -> [WallP] -> Bool --prop_looping :: [Point2] -> [WallP] -> Bool
prop_looping = forAllShrink genTris shrinkTris $ \tris -> prop_looping = forAllShrink genTris shrinkTris $ \tris ->
(all (not . (\[a,b,c] -> isOnSeg a b c not (any ( \[a,b,c] -> isOnSeg a b c
|| isOnSeg a c b || isOnSeg a c b
|| isOnSeg b c a || isOnSeg b c a
) ) tris) ) tris)
==> (isLooping' $ foldr cutWalls' [] tris) ==> isLooping' (foldr cutWalls' [] tris)
shrinkTris [] = [] shrinkTris [] = []
shrinkTris (x:xs) = xs : map (x :) (shrinkTris xs) shrinkTris (x:xs) = xs : map (x :) (shrinkTris xs)