diff --git a/lib/RPGEngine/Data/Level.hs b/lib/RPGEngine/Data/Level.hs index e3bf9f2..875514d 100644 --- a/lib/RPGEngine/Data/Level.hs +++ b/lib/RPGEngine/Data/Level.hs @@ -91,4 +91,10 @@ 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 \ No newline at end of file +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 \ No newline at end of file diff --git a/lib/RPGEngine/Input/ActionSelection.hs b/lib/RPGEngine/Input/ActionSelection.hs index 0a34015..ad7692b 100644 --- a/lib/RPGEngine/Input/ActionSelection.hs +++ b/lib/RPGEngine/Input/ActionSelection.hs @@ -4,11 +4,11 @@ module RPGEngine.Input.ActionSelection import RPGEngine.Input.Core (InputHandler, handleKey, composeInputHandlers, ListSelector (selection)) -import RPGEngine.Data (Game (..), State (..), Direction (..), Action (..), ItemId, EntityId, Level (..), Player (inventory, playerHp, Player), Item (..), HP) +import RPGEngine.Data (Game (..), State (..), Direction (..), Action (..), ItemId, EntityId, Level (..), Player (inventory, playerHp, Player), Item (..), HP, Entity (..)) import Graphics.Gloss.Interface.IO.Game (Key(SpecialKey), SpecialKey (KeyUp, KeyDown)) import Graphics.Gloss.Interface.IO.Interact ( SpecialKey(..), KeyState(..) ) -import RPGEngine.Data.Level (getWithId) +import RPGEngine.Data.Level (getWithId, itemFromInventory) import Data.Foldable (find) ------------------------------ Exported ------------------------------ @@ -72,13 +72,30 @@ useItem :: ItemId -> State -> State -- TODO useItem _ s = s -- TODO -- Attack an entity using an item +-- Should receive a Playing state 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 +decreaseHp eid iid s@Playing{ level = level, player = player } = newState + where newState = s{ level = newLevel, player = newPlayer } + -- Change player + (Just usingItem) = find ((== iid) . itemId) (inventory player) + usedItem = decreaseDurability usingItem + newInventory = filter (/= usingItem) $ inventory player + newPlayer = player{ inventory = putItemBack usedItem newInventory, playerHp = newHp } + putItemBack Nothing inv = inv + putItemBack (Just item) inv = item:inv + newHp = changeHealth (playerHp player) damageGetAmount -- Damage dealt by entity + damageDealAmount = itemValue usingItem + -- Change entity + (Just (Right attackedEntity)) = getWithId eid level + newLevel = level{ entities = putEntityBack dealtWithEntity newEntities } + newEntities = filter ((/= eid) . entityId) $ entities level + dealtWithEntity = decreaseHealth attackedEntity damageDealAmount + putEntityBack Nothing list = list + putEntityBack (Just ent) list = ent:list + damageGetAmount = inverse (entityValue attackedEntity) + inverse (Just val) = Just (-val) + inverse Nothing = Nothing +decreaseHp _ _ _ = Error "something went wrong while attacking" -- Heal a bit -- Should receive a Player @@ -97,6 +114,12 @@ decreaseDurability item@Item{ useTimes = Nothing } = Just item -- Infinite uses decreaseDurability item@Item{ useTimes = Just val } | 0 < val - 1 = Just item{ useTimes = Just (val - 1) } | otherwise = Nothing -- Broken +decreaseHealth :: Entity -> Maybe Int -> Maybe Entity +decreaseHealth entity@Entity{ entityHp = Nothing } _ = Just entity +decreaseHealth entity@Entity{ entityHp = Just val } (Just i) | 0 < val - i = Just entity{ entityHp = Just (val - i) } + | otherwise = Nothing +decreaseHealth entity _ = Just entity + -- Change given health by a given amount changeHealth :: HP -> HP -> HP changeHealth (Just health) (Just difference) = Just (health + difference) diff --git a/lib/RPGEngine/Parse/TextToStructure.hs b/lib/RPGEngine/Parse/TextToStructure.hs index fa2486e..d3c7ba0 100644 --- a/lib/RPGEngine/Parse/TextToStructure.hs +++ b/lib/RPGEngine/Parse/TextToStructure.hs @@ -139,7 +139,7 @@ action = try $ do let answer | script == "leave" = Leave | script == "retrieveItem" = RetrieveItem arg | script == "useItem" = UseItem arg - | script == "decreaseHp" = DecreaseHp first second + | script == "decreaseHp" = DecreaseHp first (filter (/= ' ') second) -- TODO Work this hack away | script == "increasePlayerHp" = IncreasePlayerHp arg | otherwise = DoNothing (first, ',':second) = break (== ',') arg diff --git a/src/Main.hs b/src/Main.hs index bb69131..0e997a8 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -1,4 +1,4 @@ -import RPGEngine +import RPGEngine ( playRPGEngine ) ----------------------------- Constants ------------------------------ diff --git a/test/Parser/GameSpec.hs b/test/Parser/GameSpec.hs index c441a22..13ad9e6 100644 --- a/test/Parser/GameSpec.hs +++ b/test/Parser/GameSpec.hs @@ -6,7 +6,6 @@ import RPGEngine.Data import RPGEngine.Parse.Core import RPGEngine.Parse.TextToStructure import RPGEngine.Parse.StructureToGame -import RPGEngine.Parse.TextToStructure (gameFile) spec :: Spec spec = do @@ -40,7 +39,7 @@ spec = do pendingWith "Still need to write this" it "Game with multiple levels" $ do pendingWith "Still need to write this" - + describe "Player" $ do it "cannot die" $ do let input = "player: { hp: infinite, inventory: [] }" @@ -65,7 +64,7 @@ spec = do } Right (Entry (Tag "player") struct) = parseWith structure input structureToPlayer struct `shouldBe` correct - + it "with inventory" $ do let input = "player: { hp: 50, inventory: [ { id: \"dagger\", x: 0, y: 0, name: \"Dolk\", description: \"Basis schade tegen monsters\", useTimes: infinite, value: 10, actions: {} } ] }" correct = Player { @@ -95,7 +94,7 @@ spec = do correct = Item { itemId = "dagger", itemX = 0, - itemY = 0, + itemY = 0, itemName = "Dagger", itemDescription = "Basic dagger you found somewhere", itemValue = Just 10, @@ -104,7 +103,7 @@ spec = do } Right struct = parseWith structure input structureToItem struct `shouldBe` correct - + it "with actions" $ do let input = "{ id: \"key\", x: 3, y: 1, name: \"Doorkey\", description: \"Unlocks a secret door\", useTimes: 1, value: 0, actions: { [not(inventoryFull())] retrieveItem(key), [] leave() } }" correct = Item { @@ -122,30 +121,36 @@ spec = do } Right struct = parseWith structure input structureToItem struct `shouldBe` correct - + describe "Actions" $ do it "no conditions" $ do let input = "{[] leave()}" correct = [([], Leave)] Right struct = parseWith structure input structureToActions struct `shouldBe` correct - + it "single condition" $ do let input = "{ [inventoryFull()] useItem(itemId)}" correct = [([InventoryFull], UseItem "itemId")] Right struct = parseWith structure input structureToActions struct `shouldBe` correct - + it "multiple conditions" $ do let input = "{ [not(inventoryFull()), inventoryContains(itemId)] increasePlayerHp(itemId)}" correct = [([Not InventoryFull, InventoryContains "itemId"], IncreasePlayerHp "itemId")] Right struct = parseWith structure input structureToActions struct `shouldBe` correct + + it "DecreaseHp(entityid, itemid)" $ do + let input = "{ [] decreaseHp(devil, sword) }" + correct = [([], DecreaseHp "devil" "sword")] + Right struct = parseWith structure input + structureToActions struct `shouldBe` correct describe "Entities" $ do it "Simple entity" $ do pendingWith "still need to write this" - + describe "Level" $ do it "Simple layout" $ do let input = "{ layout: { | * * * * * *\n| * s . . e *\n| * * * * * *\n }, items: [], entities: [] }" diff --git a/test/Parser/StructureSpec.hs b/test/Parser/StructureSpec.hs index b084a02..e4c34f5 100644 --- a/test/Parser/StructureSpec.hs +++ b/test/Parser/StructureSpec.hs @@ -146,10 +146,14 @@ spec = do correct = Right $ Regular $ Action $ UseItem "secondId" parseWith regular input `shouldBe` correct - let input = "decreaseHp(entityId,objectId)" + let input = "decreaseHp(entityId, objectId)" correct = Right $ Regular $ Action $ DecreaseHp "entityId" "objectId" parseWith regular input `shouldBe` correct + let input = "decreaseHp(entityId,objectId)" + correct = Right $ Regular $ Action $ DecreaseHp "entityId" "objectId" + parseWith regular input `shouldBe` correct + let input = "increasePlayerHp(objectId)" correct = Right $ Regular $ Action $ IncreasePlayerHp "objectId" parseWith regular input `shouldBe` correct