This repository has been archived on 2023-06-24. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
2022FuncProg-project3-RPGEn.../lib/RPGEngine/Data/Level.hs
2022-12-23 12:06:46 +01:00

100 lines
No EOL
4.3 KiB
Haskell

module RPGEngine.Data.Level
-- Everything is exported
where
import GHC.IO (unsafePerformIO)
import System.Directory (getDirectoryContents)
import RPGEngine.Input.Core (ListSelector(..))
import RPGEngine.Data (Action(..), Level (..), Physical (..), Direction (..), Entity (..), Game (..), Item (..), Player (..), State (..), X, Y, Layout, Condition (InventoryFull, InventoryContains, Not, AlwaysFalse), ItemId)
import RPGEngine.Config (levelFolder, inventorySize)
import Data.Foldable (find)
------------------------------ Exported ------------------------------
-- Find first position of a Physical
-- Graceful exit by giving Nothing if there is nothing found.
findFirstOf :: Level -> Physical -> Maybe (X, Y)
findFirstOf l@Level{ index = index } physical = try
where matches = filter (\(x, y, v) -> v == physical) index
try | not (null matches) = Just $ (\(x, y, _) -> (x, y)) $ head matches
| otherwise = Nothing
-- What is located at a given position in the level?
findAt :: (X, Y) -> Level -> Physical
findAt pos lvl@Level{ index = index } = try
where matches = map (\(_, _, v) -> v) $ filter (\(x, y, v) -> (x, y) == pos) index
try | not (null matches) = head matches
| otherwise = Void
hasAt :: (X, Y) -> Level -> Maybe (Either Item Entity)
hasAt pos level = match firstItem firstEntity
where match :: Maybe Item -> Maybe Entity -> Maybe (Either Item Entity)
match (Just a) _ = Just $ Left a
match _ (Just a) = Just $ Right a
match _ _ = Nothing
firstEntity = find ((== pos) . getECoord) $ entities level
getECoord e = (entityX e, entityY e)
firstItem = find ((== pos) . getICoord) $ items level
getICoord i = (itemX i, itemY i)
getWithId :: String -> Level -> Maybe (Either Item Entity)
getWithId id level = match firstItem firstEntity
where match :: Maybe Item -> Maybe Entity -> Maybe (Either Item Entity)
match (Just a) _ = Just $ Left a
match _ (Just a) = Just $ Right a
match _ _ = Nothing
firstEntity = find ((== id) . entityId) $ entities level
firstItem = find ((== id) . itemId) $ items level
directionOffsets :: Direction -> (X, Y)
directionOffsets North = ( 0, 1)
directionOffsets East = ( 1, 0)
directionOffsets South = ( 0, -1)
directionOffsets West = (-1, 0)
directionOffsets Stay = ( 0, 0)
getLevelList :: [FilePath]
getLevelList = drop 2 $ unsafePerformIO $ getDirectoryContents levelFolder
-- Get the actions of either an entity or an item
getActions :: Either Item Entity -> [([Condition], Action)]
getActions (Left item) = itemActions item
getActions (Right entity) = entityActions entity
getActionText :: Action -> String
getActionText Leave = "Leave"
getActionText (RetrieveItem _) = "Pick up"
getActionText (UseItem _) = "Use item"
getActionText (IncreasePlayerHp _) = "Take a healing potion"
getActionText (DecreaseHp _ used) = "Attack using " ++ used
getActionText _ = "ERROR"
-- Filter based on the conditions, keep only the actions of which the
-- conditions are met.
-- Should receive a Playing state
filterActions :: State -> [([Condition], Action)] -> [Action]
filterActions _ [] = []
filterActions s (entry:others) = met entry $ filterActions s others
where met (conditions, action) l | all (meetsCondition s) conditions = action:l
| otherwise = l
-- Check if a condition is met or not.
meetsCondition :: State -> Condition -> Bool
meetsCondition s InventoryFull = isInventoryFull $ player s
meetsCondition s (InventoryContains id) = inventoryContains id $ player s
meetsCondition s (Not condition) = not $ meetsCondition s condition
meetsCondition _ AlwaysFalse = False
-- Check if the inventory of the player is full.
isInventoryFull :: Player -> Bool
isInventoryFull p = inventorySize <= length (inventory p)
-- Check if the inventory of the player contains an item.
inventoryContains :: ItemId -> Player -> Bool
inventoryContains id p = any ((== id) . itemId) $ inventory p
-- Retrieve an item from inventory
itemFromInventory :: ItemId -> [Item] -> (Maybe Item, [Item])
itemFromInventory iid list = (match, filteredList)
where match = find ((== iid) . itemId) list
filteredList = filter ((/= iid) . itemId) list