From 9addf1ed07f0d0fdeec44b8c6637b64b06bd07be Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Fri, 23 Dec 2022 09:42:34 +0100 Subject: [PATCH] #4 Setup interaction --- README.md | 3 +- lib/RPGEngine/Data.hs | 26 +++++--- lib/RPGEngine/Data/Level.hs | 41 ++++++++++++- lib/RPGEngine/Input.hs | 5 +- lib/RPGEngine/Input/ActionSelection.hs | 76 ++++++++++++++++++++++++ lib/RPGEngine/Input/LevelSelection.hs | 9 +-- lib/RPGEngine/Input/Playing.hs | 55 +++++++++++++---- lib/RPGEngine/Render.hs | 8 ++- lib/RPGEngine/Render/ActionSelection.hs | 26 ++++++++ lib/RPGEngine/Render/LevelSelection.hs | 2 +- lib/RPGEngine/Render/Playing.hs | 3 +- rpg-engine.cabal | 2 + verslag.pdf | Bin 50036 -> 50213 bytes 13 files changed, 223 insertions(+), 33 deletions(-) create mode 100644 lib/RPGEngine/Input/ActionSelection.hs create mode 100644 lib/RPGEngine/Render/ActionSelection.hs diff --git a/README.md b/README.md index 455e7af..51913b2 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,8 @@ These are the keybinds *in* the game. All other keybinds in the menus should be | Move left | `Arrow Left` | `a` | | Move down | `Arrow Down` | `s` | | Move right | `Arrow Right` | `d` | -| Show inventory | `i` | | +| Interaction | `Space` | `f` | +| Show inventory | `i` | `Tab` | | Restart level | `r` | | | Quit game | `Esc` | | diff --git a/lib/RPGEngine/Data.hs b/lib/RPGEngine/Data.hs index 534c36b..46c65d2 100644 --- a/lib/RPGEngine/Data.hs +++ b/lib/RPGEngine/Data.hs @@ -19,22 +19,30 @@ data Game = Game { -- Main menu data State = Menu -- Select the level you want to play - | LevelSelection { levelList :: [FilePath], - selector :: ListSelector } + | LevelSelection { levelList :: [FilePath], + selector :: ListSelector } -- Playing a level - | Playing { levels :: [Level], - count :: Int, - level :: Level, - player :: Player, - restart :: State } + | Playing { levels :: [Level], + count :: Int, + level :: Level, + player :: Player, + restart :: State } + -- Selecting an action + | ActionSelection { actionList :: [Action], + selector :: ListSelector, + -- The player of this state will be used to interact + continue :: State } -- Paused while playing a level - | Paused { continue :: State } + | Paused { continue :: State } -- Won a level | Win -- Lost a level - | Lose { restart :: State } + | Lose { restart :: State } + | Error Message deriving (Eq, Show) +type Message = String + ------------------------------- Level -------------------------------- data Level = Level { diff --git a/lib/RPGEngine/Data/Level.hs b/lib/RPGEngine/Data/Level.hs index f41a0c1..f415844 100644 --- a/lib/RPGEngine/Data/Level.hs +++ b/lib/RPGEngine/Data/Level.hs @@ -5,8 +5,9 @@ where import GHC.IO (unsafePerformIO) import System.Directory (getDirectoryContents) import RPGEngine.Input.Core (ListSelector(..)) -import RPGEngine.Data (Level (..), Physical (..), Direction (..), Entity (..), Game (..), Item (..), Player (..), State (..), X, Y, Layout) +import RPGEngine.Data (Action(..), Level (..), Physical (..), Direction (..), Entity (..), Game (..), Item (..), Player (..), State (..), X, Y, Layout, Condition (InventoryFull, InventoryContains, Not, AlwaysFalse)) import RPGEngine.Config (levelFolder) +import Data.Foldable (find) ------------------------------ Exported ------------------------------ @@ -25,6 +26,17 @@ findAt pos lvl@Level{ index = index } = try 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) + directionOffsets :: Direction -> (X, Y) directionOffsets North = ( 0, 1) directionOffsets East = ( 1, 0) @@ -33,4 +45,29 @@ directionOffsets West = (-1, 0) directionOffsets Stay = ( 0, 0) getLevelList :: [FilePath] -getLevelList = drop 2 $ unsafePerformIO $ getDirectoryContents levelFolder \ No newline at end of file +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 _ = "ERROR" + +-- TODO Check conditions +-- Filter based on the conditions, keep only the actions of which the +-- conditions are met. +filterActions :: [([Condition], Action)] -> [Action] +filterActions [] = [] +filterActions ((conditions, action):others) = action:filterActions others + +-- Check if a condition is met or not. +meetsCondition :: Condition -> Bool +meetsCondition InventoryFull = False -- TODO +meetsCondition (InventoryContains id) = True -- TODO +meetsCondition (Not condition) = not $ meetsCondition condition +meetsCondition AlwaysFalse = False \ No newline at end of file diff --git a/lib/RPGEngine/Input.hs b/lib/RPGEngine/Input.hs index 1314c9e..8fc594c 100644 --- a/lib/RPGEngine/Input.hs +++ b/lib/RPGEngine/Input.hs @@ -13,6 +13,7 @@ import RPGEngine.Input.Playing ( handleInputPlaying ) import RPGEngine.Input.Paused ( handleInputPaused ) import RPGEngine.Input.Win ( handleInputWin ) import RPGEngine.Input.Lose ( handleInputLose ) +import RPGEngine.Input.ActionSelection (handleInputActionSelection) ------------------------------ Exported ------------------------------ @@ -23,4 +24,6 @@ handleAllInput ev g@Game{ state = LevelSelection{} } = handleInputLevelSelection handleAllInput ev g@Game{ state = Playing{} } = handleInputPlaying ev g handleAllInput ev g@Game{ state = Paused{} } = handleInputPaused ev g handleAllInput ev g@Game{ state = Win } = handleInputWin ev g -handleAllInput ev g@Game{ state = Lose{} } = handleInputLose ev g \ No newline at end of file +handleAllInput ev g@Game{ state = Lose{} } = handleInputLose ev g +handleAllInput ev g@Game{ state = ActionSelection{}} = handleInputActionSelection ev g +handleAllInput ev g@Game{ state = Error _ } = handleAnyKey (\game -> game{ state = Menu}) ev g \ No newline at end of file diff --git a/lib/RPGEngine/Input/ActionSelection.hs b/lib/RPGEngine/Input/ActionSelection.hs new file mode 100644 index 0000000..99e6cfe --- /dev/null +++ b/lib/RPGEngine/Input/ActionSelection.hs @@ -0,0 +1,76 @@ +module RPGEngine.Input.ActionSelection +( handleInputActionSelection +) where + +import RPGEngine.Input.Core (InputHandler, handleKey, composeInputHandlers, ListSelector (selection)) + +import RPGEngine.Data (Game (..), State (..), Direction (..), Action (..), ItemId, EntityId) +import Graphics.Gloss.Interface.IO.Game (Key(SpecialKey), SpecialKey (KeyUp, KeyDown)) +import Graphics.Gloss.Interface.IO.Interact + ( SpecialKey(..), KeyState(..) ) + +------------------------------ Exported ------------------------------ + +handleInputActionSelection :: InputHandler Game +handleInputActionSelection = composeInputHandlers [ + handleKey (SpecialKey KeySpace) Down selectAction, + + handleKey (SpecialKey KeyUp) Down $ moveSelector North, + handleKey (SpecialKey KeyDown) Down $ moveSelector South + ] + +---------------------------------------------------------------------- + +selectAction :: Game -> Game +selectAction game@Game{ state = ActionSelection list selection continue } = newGame + where newGame = game{ state = execute selectedAction continue } + selectedAction = Leave +selectAction g = g + +-- TODO Lift this code from LevelSelection +-- Move the selector either up or down +moveSelector :: Direction -> Game -> Game +moveSelector dir game@Game{ state = state@(ActionSelection list selector _) } = newGame + where newGame = game{ state = newState } + newState = state{ selector = newSelector } + newSelector | constraint = selector{ selection = newSelection } + | otherwise = selector + constraint = 0 <= newSelection && newSelection < length list + newSelection = selection selector + diff + diff | dir == North = -1 + | dir == South = 1 + | otherwise = 0 +moveSelector _ g = g{ state = Error "Something went wrong while moving the selector up or down"} + +------------------------------ Actions ------------------------------- + +execute :: Action -> State -> State +execute (RetrieveItem id ) s = pickUpItem id s +execute (UseItem id ) s = useItem id s +execute (DecreaseHp eid iid) s = decreaseHp eid iid s +execute (IncreasePlayerHp iid) s = increasePlayerHp iid s +execute _ s = s + +-- Pick up the item with itemId and put it in the players inventory +pickUpItem :: ItemId -> State -> State +pickUpItem _ s = s -- TODO + +-- Use an item on the player +useItem :: ItemId -> State -> State -- TODO +useItem _ s = s -- TODO + +-- Attack an entity using an item +decreaseHp :: EntityId -> ItemId -> State -> State +decreaseHp _ _ s = s +-- TODO DecreaseHp of monster +-- TODO Check if monster is dead +-- TODO Entity attack player +-- TODO Decrease durability of item +-- TODO Break item if durability below zero + +-- Heal a bit +increasePlayerHp :: ItemId -> State -> State +increasePlayerHp _ s = s +-- TODO Increase playerHp +-- TODO Decrease durability of item +-- TODO Remove item if durability below zero \ No newline at end of file diff --git a/lib/RPGEngine/Input/LevelSelection.hs b/lib/RPGEngine/Input/LevelSelection.hs index 5266782..84420c0 100644 --- a/lib/RPGEngine/Input/LevelSelection.hs +++ b/lib/RPGEngine/Input/LevelSelection.hs @@ -24,14 +24,15 @@ handleInputLevelSelection = composeInputHandlers [ -- Select a level and load it in selectLevel :: Game -> Game -selectLevel game@Game{ state = LevelSelection{ levelList = list, selector = selector }} = newGame +selectLevel game@Game{ state = LevelSelection list selector } = newGame where newGame = parse $ levelFolder ++ (list !! index) index = selection selector -selectLevel g = g +selectLevel g = g{ state = Error "Something went wrong while selecting a level"} +-- TODO Lift this code from ActionSelection -- Move the selector either up or down moveSelector :: Direction -> Game -> Game -moveSelector dir game@Game{ state = state@LevelSelection{ levelList = list, selector = selector } } = newGame +moveSelector dir game@Game{ state = state@(LevelSelection list selector) } = newGame where newGame = game{ state = newState } newState = state{ selector = newSelector } newSelector | constraint = selector{ selection = newSelection } @@ -41,4 +42,4 @@ moveSelector dir game@Game{ state = state@LevelSelection{ levelList = list, sele diff | dir == North = -1 | dir == South = 1 | otherwise = 0 -moveSelector _ g = g \ No newline at end of file +moveSelector _ g = g{ state = Error "Something went wrong while moving the selector up or down"} \ No newline at end of file diff --git a/lib/RPGEngine/Input/Playing.hs b/lib/RPGEngine/Input/Playing.hs index cff2b86..f2c3f1a 100644 --- a/lib/RPGEngine/Input/Playing.hs +++ b/lib/RPGEngine/Input/Playing.hs @@ -5,15 +5,16 @@ module RPGEngine.Input.Playing , putCoords ) where -import RPGEngine.Input.Core (InputHandler, handle, handleKey, composeInputHandlers) +import RPGEngine.Input.Core (InputHandler, handle, handleKey, composeInputHandlers, ListSelector (..)) -import RPGEngine.Data (Game (..), Layout(..), Level(..), Physical(..), Player(..), State(..), X, Y, Direction (..)) +import RPGEngine.Data (Game (..), Layout(..), Level(..), Physical(..), Player(..), State(..), X, Y, Direction (..), Entity (..), Item (..)) import RPGEngine.Data.Game (isLegalMove, isPlayerDead, isPlayerAtExit) -import RPGEngine.Data.Level (directionOffsets, findFirstOf) +import RPGEngine.Data.Level (directionOffsets, findFirstOf, hasAt, filterActions, getActions) import Data.Maybe (fromJust, isNothing) import Graphics.Gloss.Interface.IO.Game (Key(..)) import Graphics.Gloss.Interface.IO.Interact (SpecialKey(..), KeyState(..), Event(..), KeyState(..)) +import Prelude hiding (interact) ------------------------------ Exported ------------------------------ @@ -28,15 +29,21 @@ handleInputPlaying = composeInputHandlers [ handleKey (SpecialKey KeyDown) Down $ movePlayer South, handleKey (SpecialKey KeyLeft) Down $ movePlayer West, - handleKey (Char 'w') Down $ movePlayer North, - handleKey (Char 'd') Down $ movePlayer East, - handleKey (Char 's') Down $ movePlayer South, - handleKey (Char 'a') Down $ movePlayer West, + handleKey (Char 'w') Down $ movePlayer North, + handleKey (Char 'd') Down $ movePlayer East, + handleKey (Char 's') Down $ movePlayer South, + handleKey (Char 'a') Down $ movePlayer West, - handleKey (Char 'r') Down restartGame, + -- Interaction with entities and items + handleKey (SpecialKey KeySpace) Down checkForInteraction, + handleKey (Char 'f') Down checkForInteraction, - handleKey (Char 'i') Down $ toggleInventoryShown True, - handleKey (Char 'i') Up $ toggleInventoryShown False + handleKey (Char 'i') Down $ toggleInventoryShown True, + handleKey (Char 'i') Up $ toggleInventoryShown False, + handleKey (SpecialKey KeyTab) Down $ toggleInventoryShown True, + handleKey (SpecialKey KeyTab) Up $ toggleInventoryShown False, + + handleKey (Char 'r') Down restartGame ] ---------------------------------------------------------------------- @@ -63,6 +70,7 @@ pauseGame g = g restartGame :: Game -> Game restartGame g@Game{ state = playing@Playing{ restart = restarted } } = g{ state = restarted } +restartGame g = g{ state = Error "something went wrong while restarting the level"} -- Go to next level if there is a next level, otherwise, initialize win state. goToNextLevel :: State -> State @@ -83,16 +91,39 @@ movePlayer dir g@Game{ state = s@Playing{ player = p@Player{ position = (x, y) } newCoord | isLegalMove dir g = (x + xD, y + yD) | otherwise = (x, y) (xD, yD) = directionOffsets dir -movePlayer _ g = g +movePlayer _ g = g{ state = Error "something went wrong while moving the player" } + +checkForInteraction :: Game -> Game +checkForInteraction g@Game{ state = Playing{ level = level, player = player }} = newGame + where newGame | canInteract = interact g + | otherwise = g + canInteract = not $ null $ hasAt pos level + pos = position player +checkForInteraction g = g{ state = Error "something went wrong while checking for entities to interact with" } + +interact :: Game -> Game +interact g@Game{ state = s@Playing{ level = level, player = player } } = g{ state = newState } + where newState = ActionSelection actionList selector continue + actionList = filterActions $ getActions $ fromJust $ hasAt pos level + selector = ListSelector 0 False + pos = position player + continue = s +interact g = g{ state = Error "something went wrong while interacting with object"} toggleInventoryShown :: Bool -> Game -> Game toggleInventoryShown shown g@Game{ state = s@Playing{ player = p }}= newGame where newGame = g{ state = newState } newState = s{ player = newPlayer } newPlayer = p{ showInventory = shown } +toggleInventoryShown _ g = g{ state = Error "something went wrong while working inventory" } -- Map all Physicals onto coordinates putCoords :: Level -> [(X, Y, Physical)] putCoords l@Level{ layout = lay } = concatMap (\(a, bs) -> map (\(b, c) -> (b, a, c)) bs) numberedList where numberedStrips = reverse $ zip [0::Int .. ] $ reverse lay - numberedList = map (\(x, strip) -> (x, zip [0::Int ..] strip)) numberedStrips \ No newline at end of file + numberedList = map (\(x, strip) -> (x, zip [0::Int ..] strip)) numberedStrips + +-- putCoords l = concatMap numberColumns intermediate +-- where numberColumns (rowIndex, numberedRow) = map (\(colIndex, cell) -> (colIndex, rowIndex, cell)) numberedRow +-- intermediate = zip [0 .. ] numberedRows +-- numberedRows = zip [0::X .. ] $ layout l \ No newline at end of file diff --git a/lib/RPGEngine/Render.hs b/lib/RPGEngine/Render.hs index a9c2e74..2c2e158 100644 --- a/lib/RPGEngine/Render.hs +++ b/lib/RPGEngine/Render.hs @@ -15,9 +15,11 @@ import RPGEngine.Render.Paused ( renderPaused ) import RPGEngine.Render.Win ( renderWin ) import RPGEngine.Render.Lose ( renderLose ) -import Graphics.Gloss (Display) +import Graphics.Gloss ( Display, text, color ) import Graphics.Gloss.Data.Picture (Picture, blank) import Graphics.Gloss.Data.Display (Display(..)) +import RPGEngine.Render.ActionSelection (renderActionSelection) +import RPGEngine.Config (textColor) ---------------------------------------------------------------------- @@ -32,4 +34,6 @@ render Game{ state = s@LevelSelection{} } = renderLevelSelection s render Game{ state = s@Playing{} } = renderPlaying s render Game{ state = s@Paused{} } = renderPaused s render Game{ state = s@Win } = renderWin s -render Game{ state = s@Lose{} } = renderLose s \ No newline at end of file +render Game{ state = s@Lose{} } = renderLose s +render Game{ state = s@ActionSelection{}} = renderActionSelection s +render Game{ state = Error message } = color textColor $ text message \ No newline at end of file diff --git a/lib/RPGEngine/Render/ActionSelection.hs b/lib/RPGEngine/Render/ActionSelection.hs new file mode 100644 index 0000000..164719e --- /dev/null +++ b/lib/RPGEngine/Render/ActionSelection.hs @@ -0,0 +1,26 @@ +module RPGEngine.Render.ActionSelection +( renderActionSelection +) where + +import RPGEngine.Data (State (..), Action (..)) +import Graphics.Gloss + ( Picture, text, pictures, translate, scale, color ) +import Graphics.Gloss.Data.Picture (blank) +import RPGEngine.Data.Level (getActionText) +import RPGEngine.Config (uizoom, selectionColor, textColor) +import RPGEngine.Input.Core (ListSelector(selection)) +import RPGEngine.Render.Playing (renderPlaying) +import RPGEngine.Render.Core (overlay) + +------------------------------ Exported ------------------------------ + +renderActionSelection :: State -> Picture +renderActionSelection (ActionSelection list selector continue) = everything + where numberedTexts = zip [0::Int ..] $ map getActionText list + sel = selection selector + everything = pictures $ [renderPlaying continue, overlay] ++ map render numberedTexts + render (i, t) | i == sel = color selectionColor $ make (i, t) + | otherwise = color textColor $ make (i, t) + make (i, t) = scale uizoom uizoom $ translate 0 (offset i) $ text t + offset i = negate (250 * uizoom * fromIntegral i) +renderActionSelection _ = blank \ No newline at end of file diff --git a/lib/RPGEngine/Render/LevelSelection.hs b/lib/RPGEngine/Render/LevelSelection.hs index 082a8a1..e952b17 100644 --- a/lib/RPGEngine/Render/LevelSelection.hs +++ b/lib/RPGEngine/Render/LevelSelection.hs @@ -21,7 +21,7 @@ renderLevelSelection state = result ---------------------------------------------------------------------- renderLevelList :: Renderer State -renderLevelList LevelSelection{ levelList = list, selector = selector } = everything +renderLevelList (LevelSelection list selector) = everything where everything = pictures $ map render entries sel = selection selector entries = zip [0::Int .. ] list diff --git a/lib/RPGEngine/Render/Playing.hs b/lib/RPGEngine/Render/Playing.hs index f902178..98252c2 100644 --- a/lib/RPGEngine/Render/Playing.hs +++ b/lib/RPGEngine/Render/Playing.hs @@ -42,7 +42,8 @@ focusPlayer _ = id renderLevel :: Renderer Level renderLevel Level{ layout = l, items = i, entities = e } = level where level = pictures [void, layout, items, entities] - void = createVoid + -- void = createVoid + void = blank layout = renderLayout l items = renderItems i entities = renderEntities e diff --git a/rpg-engine.cabal b/rpg-engine.cabal index 3323cdb..bfd1afa 100644 --- a/rpg-engine.cabal +++ b/rpg-engine.cabal @@ -23,6 +23,7 @@ library RPGEngine.Input RPGEngine.Input.Core + RPGEngine.Input.ActionSelection RPGEngine.Input.Menu RPGEngine.Input.LevelSelection RPGEngine.Input.Playing @@ -37,6 +38,7 @@ library RPGEngine.Render RPGEngine.Render.Core + RPGEngine.Render.ActionSelection RPGEngine.Render.Menu RPGEngine.Render.LevelSelection RPGEngine.Render.Playing diff --git a/verslag.pdf b/verslag.pdf index c974837aa88e97c54e182754cc11fc07894d420f..d607e19ef4b64e0453b857b332f480b7f4627c32 100644 GIT binary patch delta 14200 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