2018-04-14 09:18:37 +00:00
|
|
|
module NPC where
|
|
|
|
|
|
|
|
import Affection as A
|
|
|
|
|
|
|
|
import qualified Data.Matrix as M
|
|
|
|
import Data.Ecstasy as E
|
|
|
|
|
2018-04-14 16:43:05 +00:00
|
|
|
import Control.Monad.IO.Class (MonadIO(..))
|
|
|
|
|
2018-04-14 09:18:37 +00:00
|
|
|
import Linear
|
|
|
|
|
|
|
|
import System.Random
|
|
|
|
|
|
|
|
import NanoVG hiding (V2(..))
|
|
|
|
|
|
|
|
-- internal imports
|
|
|
|
|
2018-04-14 11:34:28 +00:00
|
|
|
import Navigation
|
|
|
|
import Util
|
|
|
|
|
2018-04-14 09:18:37 +00:00
|
|
|
import Types.UserData
|
2018-04-14 11:34:28 +00:00
|
|
|
import Types.Interior
|
|
|
|
import Types.Map
|
2018-04-14 16:43:05 +00:00
|
|
|
import Types.ReachPoint
|
2018-04-14 09:18:37 +00:00
|
|
|
|
|
|
|
drawNPCs
|
|
|
|
:: Context
|
2018-05-15 17:27:54 +00:00
|
|
|
-> UserData
|
2018-04-14 09:18:37 +00:00
|
|
|
-> [V2 Double]
|
|
|
|
-> Double
|
|
|
|
-> Double
|
|
|
|
-> Int
|
|
|
|
-> Int
|
2018-04-26 13:25:38 +00:00
|
|
|
-> Maybe ImgId
|
2018-05-15 17:27:54 +00:00
|
|
|
-> IO ()
|
|
|
|
drawNPCs ctx ud npcposs prow pcol row col img = do
|
2018-04-14 09:18:37 +00:00
|
|
|
let fnpcposs = filter
|
2018-04-26 13:25:38 +00:00
|
|
|
(\(V2 nr nc) ->
|
|
|
|
let x = realToFrac $ 640 + ((nc - pcol) + (nr - prow)) * 32
|
|
|
|
y = realToFrac $ 360 + ((nr - prow) - (nc - pcol)) * 16
|
|
|
|
in ((realToFrac x > -tileWidth && realToFrac y > -tileHeight) &&
|
|
|
|
(realToFrac x < 1280 && realToFrac (y - (74 - realToFrac tileHeight)) < 720)) &&
|
|
|
|
((all (\m -> prow > (fromIntegral (floor prow :: Int)) + m) minrs &&
|
|
|
|
all (\m -> pcol < (fromIntegral (floor pcol :: Int)) + m) mincs) ||
|
|
|
|
(all (\m -> prow > (fromIntegral (floor prow :: Int)) + m) minrs &&
|
|
|
|
all (\m -> pcol < (fromIntegral (floor pcol :: Int)) + m) maxcs)) &&
|
|
|
|
(floor nr == row && floor nc == col)
|
|
|
|
)
|
2018-04-14 09:18:37 +00:00
|
|
|
npcposs
|
2018-05-15 17:27:54 +00:00
|
|
|
mapM_
|
2018-04-14 09:18:37 +00:00
|
|
|
(\(V2 nr nc) -> do
|
|
|
|
let x = realToFrac $ 640 + ((nc - pcol) + (nr - prow)) * 32
|
|
|
|
y = realToFrac $ 360 + ((nr - prow) - (nc - pcol)) * 16
|
|
|
|
beginPath ctx
|
|
|
|
circle ctx x y 5
|
|
|
|
closePath ctx
|
|
|
|
fillColor ctx (rgba 255 0 0 255)
|
|
|
|
fill ctx
|
|
|
|
)
|
|
|
|
fnpcposs
|
2018-04-26 13:25:38 +00:00
|
|
|
where
|
|
|
|
tileWidth = 64 :: Double
|
|
|
|
tileHeight = 32 :: Double
|
|
|
|
mb = imgObstacle img
|
|
|
|
minrs = Prelude.map (fst . matmin) mb
|
|
|
|
maxrs = Prelude.map (fst . matmax) mb
|
|
|
|
mincs = Prelude.map (snd . matmin) mb
|
|
|
|
maxcs = Prelude.map (snd . matmax) mb
|
2018-04-14 09:18:37 +00:00
|
|
|
|
2018-04-14 11:34:28 +00:00
|
|
|
placeNPCs
|
|
|
|
:: M.Matrix (Maybe ImgId)
|
2018-04-14 16:43:05 +00:00
|
|
|
-> M.Matrix TileState
|
2018-04-14 11:34:28 +00:00
|
|
|
-> [ReachPoint]
|
|
|
|
-> [Graph]
|
|
|
|
-> Int
|
|
|
|
-> Affection UserData [V2 Double]
|
2018-04-14 16:43:05 +00:00
|
|
|
placeNPCs imgmat tilemat rp gr count =
|
2018-04-14 09:18:37 +00:00
|
|
|
doPlace 1 []
|
|
|
|
where
|
|
|
|
doPlace :: Int -> [V2 Double] -> Affection UserData [V2 Double]
|
|
|
|
doPlace nr acc = do
|
|
|
|
if nr <= count
|
|
|
|
then do
|
|
|
|
r <- liftIO $ randomRIO (1, M.nrows imgmat)
|
|
|
|
c <- liftIO $ randomRIO (1, M.ncols imgmat)
|
2018-04-14 11:34:28 +00:00
|
|
|
if null (imgObstacle $ imgmat M.! (r, c)) &&
|
2018-04-14 16:43:05 +00:00
|
|
|
tilemat M.! (r, c) == Hall
|
2018-04-14 09:18:37 +00:00
|
|
|
then doPlace (nr + 1) ((V2 (fromIntegral r) (fromIntegral c)) : acc)
|
2018-04-14 16:43:05 +00:00
|
|
|
else do
|
|
|
|
i <- liftIO $ randomRIO (0, length nonexits - 1)
|
|
|
|
doPlace
|
|
|
|
(nr + 1)
|
|
|
|
((fmap fromIntegral $ pointCoord (nonexits !! i)) : acc)
|
2018-04-14 09:18:37 +00:00
|
|
|
else
|
|
|
|
return acc
|
2018-04-14 11:34:28 +00:00
|
|
|
applRooms row col =
|
2018-04-14 16:43:05 +00:00
|
|
|
(filter (\r -> graphIsRoom r && inBounds (V2 row col) (bounds r)) gr)
|
|
|
|
nonexits =
|
|
|
|
filter
|
|
|
|
(\p ->
|
|
|
|
pointType p /= RoomExit
|
|
|
|
)
|
|
|
|
rp
|
|
|
|
|
|
|
|
updateNPCs
|
2018-04-22 09:59:14 +00:00
|
|
|
:: MonadIO m
|
2018-04-14 16:43:05 +00:00
|
|
|
=> M.Matrix (Maybe ImgId)
|
|
|
|
-> [ReachPoint]
|
|
|
|
-> Double
|
|
|
|
-> SystemT Entity m ()
|
|
|
|
updateNPCs imgmat rp dt =
|
|
|
|
emap $ do
|
|
|
|
with npcState
|
|
|
|
with vel
|
|
|
|
with pos
|
|
|
|
npcState' <- E.get npcState
|
|
|
|
case npcState' of
|
|
|
|
NPCStanding ttl -> do
|
|
|
|
let nttl = ttl - dt
|
|
|
|
if nttl > 0
|
|
|
|
then
|
|
|
|
return $ defEntity'
|
|
|
|
{ npcState = Set $ NPCStanding nttl
|
|
|
|
, vel = Set $ V2 0 0
|
|
|
|
}
|
|
|
|
else do
|
|
|
|
pos' <- E.get pos
|
|
|
|
path <- liftIO $ getPath (fmap floor pos')
|
|
|
|
return $ defEntity'
|
|
|
|
{ npcState = Set $ NPCWalking path
|
|
|
|
}
|
|
|
|
NPCWalking path -> do
|
|
|
|
pos' <- E.get pos
|
|
|
|
if not (null path)
|
|
|
|
then do
|
|
|
|
let itarget = V2 0.5 0.5 + (fromIntegral <$> head path) :: V2 Double
|
|
|
|
if distance pos' itarget < 0.1
|
|
|
|
then
|
|
|
|
return $ defEntity'
|
|
|
|
{ npcState = Set $ NPCWalking (tail path)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return $ defEntity'
|
2018-05-13 20:01:05 +00:00
|
|
|
{ vel = Set $ (* 2) <$> signorm (itarget - pos')
|
2018-04-14 16:43:05 +00:00
|
|
|
}
|
|
|
|
else do
|
|
|
|
ttl <- liftIO $ randomRIO (5, 30)
|
|
|
|
return $ defEntity'
|
|
|
|
{ npcState = Set $ NPCStanding ttl
|
|
|
|
}
|
|
|
|
where
|
|
|
|
getPath pos' = do
|
|
|
|
let seekRP = filter (\p -> pointType p /= RoomExit) rp
|
|
|
|
ntargeti <- randomRIO (0, length seekRP - 1)
|
|
|
|
let ntarget = pointCoord (seekRP !! ntargeti)
|
|
|
|
path = astarAppl imgmat ntarget pos'
|
2018-04-27 21:34:57 +00:00
|
|
|
logIO A.Verbose ("seeking path from " ++ show pos' ++ " to " ++ show ntarget)
|
2018-04-14 16:43:05 +00:00
|
|
|
case path of
|
|
|
|
Nothing -> getPath pos'
|
|
|
|
Just p -> return p
|