dev #25
					 9 changed files with 504 additions and 12 deletions
				
			
		
							
								
								
									
										247
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										247
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,3 +1,250 @@ | ||||||
| # RPG-Engine | # RPG-Engine | ||||||
| 
 | 
 | ||||||
| Schrijf een game-engine voor een rollenspel | Schrijf een game-engine voor een rollenspel | ||||||
|  | 
 | ||||||
|  | https://pixel-poem.itch.io/dungeon-assetpuck | ||||||
|  | https://kyrise.itch.io/kyrises-free-16x16-rpg-icon-pack | ||||||
|  | 
 | ||||||
|  | # RPG Engine requirements | ||||||
|  | 
 | ||||||
|  | ## Functional requirements | ||||||
|  | 
 | ||||||
|  | - [ ] Parsing of engine configuration file to game object | ||||||
|  | - [ ] Rendering of all game objects (Levels, objects, entities, ...) | ||||||
|  | - [ ] A start menu with the possibility of selecting a level | ||||||
|  | - [ ] An end screen that shows wether or not a player won | ||||||
|  | - [ ] Support for built-in engine functions | ||||||
|  | 
 | ||||||
|  | - [ ] Player can move around in grid-world. | ||||||
|  | - [ ] Player can pick up objects. | ||||||
|  | - [ ] Player can use objects. | ||||||
|  | - [ ] Player can loose and gain health points. | ||||||
|  | - [ ] Player can interact with other entities (fight enimies, open doors, ...). | ||||||
|  | - [ ] Player can go to the next level. | ||||||
|  | 
 | ||||||
|  | ## Not-functional requirements | ||||||
|  | 
 | ||||||
|  | - [ ] Use Parsing. | ||||||
|  | - [ ] Use at least one (1) monad transformer. | ||||||
|  | - [ ] Write good and plenty of documentation.:w | ||||||
|  | 
 | ||||||
|  | - [ ] Write tests (for example, using HSpec). | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | # Plaats om dingen neer te jotten | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Play <--- HandleInput | ||||||
|  |  | | ||||||
|  |  | | ||||||
|  |  v | ||||||
|  | Level <--- LoadLevel <--- Parse | ||||||
|  |  | | ||||||
|  |  | | ||||||
|  |  v | ||||||
|  | RenderLevel | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | - [ ] State paradigma gebruiken om van startscherm naar playscherm naar pause scherm naar endscherm te gaan | ||||||
|  | 
 | ||||||
|  | Nuttige links:  | ||||||
|  | 
 | ||||||
|  | - https://jakewheat.github.io/intro_to_parsing/ | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Jarne — Today at 22:44 | ||||||
|  | Da kan hoor en had da eerst, me gloss eeft geen goede text dus... | ||||||
|  | ListDirectory, en er was ook een fuctie takeBaseName | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # RPG-Engine Documentation | ||||||
|  | 
 | ||||||
|  | ## Playing the game | ||||||
|  | 
 | ||||||
|  | TODO | ||||||
|  | 
 | ||||||
|  | - Input commands etc | ||||||
|  | - An example playthrough | ||||||
|  | 
 | ||||||
|  | ## Writing your own stages | ||||||
|  | 
 | ||||||
|  | A stage description file, conventionally named `<stage_name>.txt` is a file with a JSON-like format. It is used to describe | ||||||
|  |  everything inside a single stage of your game, including anything related to the player, the levels your game contains | ||||||
|  |  and what happens in that level. It is essentially the raw representation of the initial state of a single game. | ||||||
|  | 
 | ||||||
|  | > Note: At the moment, every game has a single stage description file. Chaining several files together is not possible yet. | ||||||
|  | 
 | ||||||
|  | A stage description file consists of several elements. | ||||||
|  | 
 | ||||||
|  | | Element         | Short description                                                                                         | | ||||||
|  | | --------------- | --------------------------------------------------------------------------------------------------------- | | ||||||
|  | | `Block`         | optionally surrounded by `{ ... }`, consists of several `Entry`'s, optionally separated by commas `,`     | | ||||||
|  | | `Entry`         | is a `Key` - `Value` pair, optionally separated by a colon `:`                                            | | ||||||
|  | | `Key`           | is a unique, predefined `String` describing `Value`                                                       | | ||||||
|  | | `Value`         | is either a `Block` or a `BlockList` or a traditional value, such as `String` or `Int`                    | | ||||||
|  | | `BlockList`     | is a number of `Block`'s, surrounded by `[ ... ]`, separated by commas, can be empty                      | | ||||||
|  | 
 | ||||||
|  | We'll look at the following example to explain these concepts. | ||||||
|  | 
 | ||||||
|  | ```javascript | ||||||
|  | player: { | ||||||
|  |     hp: 50, | ||||||
|  |     inventory: [ | ||||||
|  |         { | ||||||
|  |             id: "dagger", | ||||||
|  |             x: 0, | ||||||
|  |             y: 0, | ||||||
|  |             name: "Dagger", | ||||||
|  |             description: "Basic dagger you found somewhere", | ||||||
|  |             useTimes: infinite, | ||||||
|  |             value: 10, | ||||||
|  | 
 | ||||||
|  |             actions: {} | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | levels: [ | ||||||
|  |     { | ||||||
|  |         layout: { | ||||||
|  |             | * * * * * * | ||||||
|  |             | * s . . e * | ||||||
|  |             | * * * * * * | ||||||
|  |         }, | ||||||
|  |         items: [], | ||||||
|  |         entities: [] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         layout: { | ||||||
|  |             | * * * * * * * * | ||||||
|  |             | * s . . . . e * | ||||||
|  |             | * * * * * * * * | ||||||
|  |         }, | ||||||
|  |         items: [ | ||||||
|  |             { | ||||||
|  |                 id: "key", | ||||||
|  |                 x: 3, | ||||||
|  |                 y: 1, | ||||||
|  |                 name: "Doorkey", | ||||||
|  |                 description: "Unlocks a secret door", | ||||||
|  |                 useTimes: 1, | ||||||
|  |                 value: 0, | ||||||
|  |                 actions: { | ||||||
|  |                     [not(inventoryFull())] retrieveItem(key), | ||||||
|  |                     [] leave() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         entities: [ | ||||||
|  |             { | ||||||
|  |                 id: "door", | ||||||
|  |                 x: 4, | ||||||
|  |                 y: 1, | ||||||
|  |                 name: "Secret door", | ||||||
|  |                 description: "This secret door can only be opened with a key", | ||||||
|  |                 direction: left, | ||||||
|  |                 actions: { | ||||||
|  |                     [inventoryContains(key)] useItem(key), | ||||||
|  |                     [] leave() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     } | ||||||
|  | ] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | This stage description file consists of a single `Block`. A stage description file always does. This top level `Block` | ||||||
|  |  contains two `Value`s `player` and `levels`, not separated by commas.  | ||||||
|  | 
 | ||||||
|  | `player` describes a `Block` that represents the player of the game. Its `Entry`s are `hp` (a traditional value) and | ||||||
|  |  `inventory` (a `BlockList` of several other `Block`s). They are both separated by commas this time. It is possible for | ||||||
|  |  the inventory to be an empty list `[]`. | ||||||
|  | 
 | ||||||
|  | `levels` is a `BlockList` that contains all the information to construct your game. | ||||||
|  | 
 | ||||||
|  | ### `layout` syntax | ||||||
|  | 
 | ||||||
|  | If `Key`  has the value `layout`, `Value` is none of the types discussed so far. Instead `Layout` is specifically made | ||||||
|  |  to describe the layout of a level. This object is surrounded by `{ ... }` and consists of multiple lines, starting with | ||||||
|  |  a vertical line `|` and several characters of the following: | ||||||
|  | 
 | ||||||
|  | - `x` is an empty tile a.k.a. void. | ||||||
|  | - `.` is a tile walkable by the player. | ||||||
|  | - `*` is a tile not walkable by the player. | ||||||
|  | - `s` is the starting position of the player. | ||||||
|  | - `e` is the exit. | ||||||
|  | 
 | ||||||
|  | All characters are interspersed with spaces. | ||||||
|  | 
 | ||||||
|  | ### `actions` syntax | ||||||
|  | 
 | ||||||
|  | If `Key` has the value `actions`, the following changes are important for its `Value`, which in this case is a `Block` | ||||||
|  |  with zero or more `Entry`s like so: | ||||||
|  | 
 | ||||||
|  | - `Key` has type `ConditionList`. | ||||||
|  |    | ||||||
|  |   A `ConditionList` consists of several `Condition`s, surrounded by `[ ... ]`, separated by commas. A `ConditionList` | ||||||
|  |    can be empty. If so, the conditional is always fulfilled. | ||||||
|  | 
 | ||||||
|  |   A `Condition` is one of the following: | ||||||
|  |    | ||||||
|  |   - `inventoryFull()`: the players inventory is full. | ||||||
|  |   - `inventoryContains(objectId)`: the players inventory contains an object with id `objectId`. | ||||||
|  |   - `not(condition)`: logical negation of `condition`. | ||||||
|  | 
 | ||||||
|  | - `Value` is an `Action`. | ||||||
|  | 
 | ||||||
|  |   An `Action` is one of the following: | ||||||
|  | 
 | ||||||
|  |   - `leave()` | ||||||
|  |   - `retrieveItem(objectId)` | ||||||
|  |   - `useItem(objectId)` | ||||||
|  |   - `decreaseHp(entityId, objectId)` | ||||||
|  |   - `increasePlayerHp(objectId)` | ||||||
|  | 
 | ||||||
|  | ### Back to the example | ||||||
|  | 
 | ||||||
|  | If we look at the example, all the objects are | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | >Block< | ||||||
|  |     Entry = Key ('player') + >Block< | ||||||
|  |         Entry = Key ('hp') + Value (50) | ||||||
|  |         Entry = Key ('inventory') + >BlockList< | ||||||
|  |             length = 1 | ||||||
|  |             Block | ||||||
|  |                 Entry = Key ('id') + Value ("dagger") | ||||||
|  |                 ... <several traditional entries like this> | ||||||
|  |                 Entry = Key ('actions') + empty Block | ||||||
|  |     Entry = Key ('levels') + >BlockList< | ||||||
|  |         length = 2 | ||||||
|  |         >Block< | ||||||
|  |             Entry = Key ('layout') + Layout | ||||||
|  |                 <multiple lines that describe the layout> | ||||||
|  |             Entry = Key ('items') + empty BlockList | ||||||
|  |             Entry = Key ('entities') + empty BlockList | ||||||
|  |         >Block< | ||||||
|  |             Entry = Key ('layout') + Layout | ||||||
|  |                 <multiple lines that describe the layout> | ||||||
|  |             Entry = Key ('items') + >BlockList< | ||||||
|  |                 length = 1 | ||||||
|  |                 >Block< | ||||||
|  |                     Entry = Key ('id') + Value ("key") | ||||||
|  |                     ... <several traditional entries like this> | ||||||
|  |                     Entry = Key ('actions') + >Block< | ||||||
|  |                         Entry = >ConditionList< + Action ('retrieveItem(key)') | ||||||
|  |                             length = 1 | ||||||
|  |                             Condition ('not(inventoryFull())'))  | ||||||
|  |                         Entry = empty ConditionList + Action ('leave()') | ||||||
|  |             Entry = Key ('entities') + >BlockList< | ||||||
|  |                 length = 1 | ||||||
|  |                 >Block< | ||||||
|  |                     Entry = Key ('id') + Value ("door") | ||||||
|  |                     ... <several traditional entries like this> | ||||||
|  |                     Entry = Key ('actions') + >Block< | ||||||
|  |                         Entry = >ConditionList< + Action ('useItem(key)') | ||||||
|  |                             length = 1 | ||||||
|  |                             Condition ('inventoryContains(key)') | ||||||
|  |                         Entry = empty ConditionList + Action ('leave()') | ||||||
|  | ``` | ||||||
							
								
								
									
										132
									
								
								lib/control/Parse.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								lib/control/Parse.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,132 @@ | ||||||
|  | module Parse where | ||||||
|  | 
 | ||||||
|  | -- TODO Maak wrapper module | ||||||
|  | -- TODO This module should not be used by anything except for wrapper module and tests | ||||||
|  | 
 | ||||||
|  | import Game | ||||||
|  | import Player | ||||||
|  | import Text.Parsec | ||||||
|  | import Text.Parsec.Char | ||||||
|  | import Text.Parsec.String | ||||||
|  | import Data.List | ||||||
|  | import Data.Maybe | ||||||
|  | import Text.Parsec.Error (Message(UnExpect)) | ||||||
|  | 
 | ||||||
|  | -- TODO parseFromFile gebruiken | ||||||
|  | 
 | ||||||
|  | -- Parser type | ||||||
|  | -- type Parser = Parsec String () | ||||||
|  | 
 | ||||||
|  | -- A wrapper, which takes a parser and some input and returns a  | ||||||
|  | -- parsed output. | ||||||
|  | parseWith :: Parser a -> String -> Either ParseError a | ||||||
|  | parseWith parser = parse parser "" | ||||||
|  | 
 | ||||||
|  | ignoreWS :: Parser a -> Parser a | ||||||
|  | ignoreWS parser = spaces >> parser | ||||||
|  | 
 | ||||||
|  | -- Also return anything that has not yet been parsed | ||||||
|  | parseWithRest :: Parser a -> String -> Either ParseError (a, String) | ||||||
|  | --                     fmap (,) over Parser monad and apply to rest | ||||||
|  | parseWithRest parser = parse ((,) <$> parser <*> rest) "" | ||||||
|  |     where rest = manyTill anyToken eof | ||||||
|  | 
 | ||||||
|  | parseToGame :: Game | ||||||
|  | parseToGame = undefined | ||||||
|  | 
 | ||||||
|  | -- Info in between brackets, '(..)', '[..]', '{..}' or '<..>' | ||||||
|  | data Brackets a = Brackets a | ||||||
|  |               deriving (Eq, Show) | ||||||
|  | 
 | ||||||
|  | parseToPlayer :: Player | ||||||
|  | parseToPlayer = undefined | ||||||
|  | 
 | ||||||
|  | -- any words separated by whitespace | ||||||
|  | parseWord :: Parser String | ||||||
|  | parseWord = do many alphaNum | ||||||
|  | 
 | ||||||
|  | -- TODO Expand to allow different kinds of brackets, also see Brackets data type. | ||||||
|  | -- TODO Check if brackets match order. | ||||||
|  | -- TODO Allow nested brackets. | ||||||
|  | brackets :: Parser (Brackets String) | ||||||
|  | brackets = do | ||||||
|  |     ignoreWS $ char '(' | ||||||
|  |     e <- ignoreWS $ many1 alphaNum | ||||||
|  |     ignoreWS $ char ')' | ||||||
|  |     return $ Brackets e | ||||||
|  | 
 | ||||||
|  | ------------------------ | ||||||
|  | 
 | ||||||
|  | data Value = String String | ||||||
|  |            | Integer Int | ||||||
|  |            | Infinite | ||||||
|  |            deriving (Show, Eq) | ||||||
|  | 
 | ||||||
|  | -- See documentation for more details, only a short description is | ||||||
|  | --provided here. | ||||||
|  | data StructureElement = Block [StructureElement] | ||||||
|  |                       | Entry String StructureElement-- Key + Value | ||||||
|  |                       | Regular Value -- Regular value, Integer or String or Infinite | ||||||
|  |                       | ConditionList [StructureElement] | ||||||
|  |                       -- TODO | ||||||
|  |                       | Condition -- inventoryFull() etc. | ||||||
|  |                       -- TODO | ||||||
|  |                       | Action -- leave(), useItem(objectId) etc. | ||||||
|  |                       deriving (Show, Eq) | ||||||
|  | 
 | ||||||
|  | -- TODO Add ConditionList and Action | ||||||
|  | structureElement :: Parser StructureElement | ||||||
|  | structureElement = choice [block, regular] | ||||||
|  | 
 | ||||||
|  | -- A Block is a list of Entry s | ||||||
|  | block :: Parser StructureElement | ||||||
|  | block = do | ||||||
|  |     ignoreWS $ char '{' | ||||||
|  |     list <- ignoreWS $ many1 entry | ||||||
|  |     ignoreWS $ char '}' | ||||||
|  |     return $ Block list | ||||||
|  | 
 | ||||||
|  | entry :: Parser StructureElement | ||||||
|  | entry = do | ||||||
|  |     key <- ignoreWS $ many1 alphaNum | ||||||
|  |     ignoreWS $ char ':' | ||||||
|  |     value <- ignoreWS structureElement -- TODO Is this the correct one to use? | ||||||
|  |     return $ Entry key value | ||||||
|  | 
 | ||||||
|  | regular :: Parser StructureElement | ||||||
|  | regular = do | ||||||
|  |     value <- ignoreWS $ choice [integer, valueString, infinite] | ||||||
|  |     return $ Regular value | ||||||
|  | 
 | ||||||
|  | integer :: Parser Value | ||||||
|  | integer = do | ||||||
|  |     value <- ignoreWS $ many1 digit | ||||||
|  |     return $ Integer (read value :: Int) | ||||||
|  | 
 | ||||||
|  | valueString :: Parser Value | ||||||
|  | valueString = do | ||||||
|  |     ignoreWS $ char '"' | ||||||
|  |     value <- ignoreWS $ many1 (noneOf ['"']) | ||||||
|  |     ignoreWS $ char '"' | ||||||
|  |     return $ String value | ||||||
|  | 
 | ||||||
|  | infinite :: Parser Value | ||||||
|  | infinite = do | ||||||
|  |     ignoreWS $ string "infinite" | ||||||
|  |     notFollowedBy alphaNum | ||||||
|  |     return Infinite | ||||||
|  | 
 | ||||||
|  | conditionList :: Parser StructureElement | ||||||
|  | conditionList = do | ||||||
|  |     ignoreWS $ char '[' | ||||||
|  |     list <- ignoreWS $ many1 condition | ||||||
|  |     ignoreWS $ char ']' | ||||||
|  |     return $ ConditionList list | ||||||
|  | 
 | ||||||
|  | -- TODO | ||||||
|  | condition :: Parser StructureElement | ||||||
|  | condition = undefined | ||||||
|  | 
 | ||||||
|  | -- TODO YOU ARE HERE | ||||||
|  | action :: Parser StructureElement | ||||||
|  | action = undefined | ||||||
|  | @ -8,11 +8,12 @@ library | ||||||
|   hs-source-dirs: lib, lib/control, lib/data, lib/render |   hs-source-dirs: lib, lib/control, lib/data, lib/render | ||||||
|   build-depends: |   build-depends: | ||||||
|     base >= 4.7 && <5, |     base >= 4.7 && <5, | ||||||
|     gloss >= 1.11 && < 1.14, gloss-juicy >= 0.2.3 |     gloss >= 1.11 && < 1.14, gloss-juicy >= 0.2.3, | ||||||
|  |     parsec >= 3.1.15.1 | ||||||
|   exposed-modules: |   exposed-modules: | ||||||
|     RPGEngine, |     RPGEngine, | ||||||
|     -- Control |     -- Control | ||||||
|     Input, InputHandling, |     Input, InputHandling, Parse, | ||||||
|     -- Data |     -- Data | ||||||
|     Game, Internals, Player, State, |     Game, Internals, Player, State, | ||||||
|     -- Render |     -- Render | ||||||
|  | @ -26,7 +27,11 @@ executable rpg-engine | ||||||
| 
 | 
 | ||||||
| test-suite rpg-engine-test | test-suite rpg-engine-test | ||||||
|   type: exitcode-stdio-1.0 |   type: exitcode-stdio-1.0 | ||||||
|   main-is: RPG-Engine-Test.hs |   main-is: RPGEngineSpec.hs | ||||||
|   hs-source-dirs: test |   hs-source-dirs: test | ||||||
|   default-language: Haskell2010 |   default-language: Haskell2010 | ||||||
|   build-depends: base >=4.7 && <5, hspec <= 2.10.6, rpg-engine |   build-depends: base >=4.7 && <5, hspec <= 2.10.6, hspec-discover, rpg-engine | ||||||
|  |   other-modules:  | ||||||
|  |     InteractionSpec,  | ||||||
|  |     -- Parsing | ||||||
|  |     ParsedToGameSpec, ParserSpec | ||||||
|  |  | ||||||
|  | @ -42,6 +42,7 @@ extra-deps: | ||||||
| # | # | ||||||
| # extra-deps: [] | # extra-deps: [] | ||||||
| - gloss-juicy-0.2.3@sha256:0c3bca95237cbf91f8b3b1936a0661f1e0457acd80502276d54d6c5210f88b25,1618 | - gloss-juicy-0.2.3@sha256:0c3bca95237cbf91f8b3b1936a0661f1e0457acd80502276d54d6c5210f88b25,1618 | ||||||
|  | - parsec-3.1.15.1@sha256:8c7a36aaadff12a38817fc3c4ff6c87e3352cffd1a58df640de7ed7a97ad8fa3,4601 | ||||||
| 
 | 
 | ||||||
| # Override default flag values for local packages and extra-deps | # Override default flag values for local packages and extra-deps | ||||||
| # flags: {} | # flags: {} | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								test/InteractionSpec.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								test/InteractionSpec.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | module InteractionSpec where | ||||||
|  | 
 | ||||||
|  | import Test.Hspec | ||||||
|  | 
 | ||||||
|  | spec :: Spec | ||||||
|  | spec = do | ||||||
|  |     describe "Player with Inventory" $ do | ||||||
|  |         it "TODO: Simple test" $ do | ||||||
|  |             pending | ||||||
							
								
								
									
										52
									
								
								test/ParsedToGameSpec.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								test/ParsedToGameSpec.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | module ParsedToGameSpec where | ||||||
|  | 
 | ||||||
|  | import Test.Hspec | ||||||
|  | import Parse | ||||||
|  | 
 | ||||||
|  | spec :: Spec | ||||||
|  | spec = do | ||||||
|  |     describe "Game" $ do | ||||||
|  |         it "TODO: Simple game" $ do | ||||||
|  |             pending | ||||||
|  |         it "TODO: More complex game" $ do | ||||||
|  |             pending | ||||||
|  |         it "TODO: Game with multiple levels" $ do | ||||||
|  |             pending | ||||||
|  |      | ||||||
|  |     describe "Player" $ do | ||||||
|  |         it "TODO: Simple player" $ do | ||||||
|  |             pending | ||||||
|  |      | ||||||
|  |     describe "Inventory" $ do | ||||||
|  |         it "TODO: Empty inventory" $ do | ||||||
|  |             pending | ||||||
|  |         it "TODO: Singleton inventory" $ do | ||||||
|  |             pending | ||||||
|  |         it "TODO: Filled inventory" $ do | ||||||
|  |             pending | ||||||
|  |      | ||||||
|  |     describe "Items" $ do | ||||||
|  |         it "TODO: Simple item" $ do | ||||||
|  |             pending | ||||||
|  |             -- Check id | ||||||
|  |             -- Check x | ||||||
|  |             -- Check y | ||||||
|  |             -- Check name | ||||||
|  |             -- Check description | ||||||
|  |             -- Check useTimes | ||||||
|  |             -- Check value | ||||||
|  |             -- Check actions | ||||||
|  |      | ||||||
|  |     describe "Actions" $ do | ||||||
|  |         it "TODO: Simple action" $ do | ||||||
|  |             pending | ||||||
|  |      | ||||||
|  |     describe "Entities" $ do | ||||||
|  |         it "TODO: Simple entity" $ do | ||||||
|  |             pending | ||||||
|  |      | ||||||
|  |     describe "Level" $ do | ||||||
|  |         it "TODO: Simple layout" $ do | ||||||
|  |             pending | ||||||
|  |         it "TODO: Complex layout" $ do | ||||||
|  |             pending | ||||||
							
								
								
									
										52
									
								
								test/ParserSpec.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								test/ParserSpec.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | module ParserSpec where | ||||||
|  | 
 | ||||||
|  | import Test.Hspec | ||||||
|  | import Parse | ||||||
|  | import Data.Either | ||||||
|  | 
 | ||||||
|  | spec :: Spec | ||||||
|  | spec = do | ||||||
|  |     describe "Basics of entries" $ do | ||||||
|  |         it "can parse integers" $ do | ||||||
|  |             let correct = Right $ Regular $ Integer 1 | ||||||
|  |             correct `shouldBe` parseWith regular "1" | ||||||
|  |         it "can parse string" $ do | ||||||
|  |             let input   = "dit is een string" | ||||||
|  |                 correct = Right $ Regular $ String input | ||||||
|  |             correct `shouldBe` parseWith regular ("\"" ++ input ++ "\"") | ||||||
|  |         it "can parse infinite" $ do | ||||||
|  |             let correct = Right $ Regular Infinite | ||||||
|  |             correct `shouldBe` parseWith regular "infinite" | ||||||
|  | 
 | ||||||
|  |             let wrong = Right $ Regular Infinite | ||||||
|  |             wrong `shouldNotBe` parseWith regular "infinitee" | ||||||
|  |          | ||||||
|  |         it "can parse entries" $ do | ||||||
|  |             let input   = "id : \"dagger\"" | ||||||
|  |                 correct = Right $ Entry "id" $ Regular $ String "dagger" | ||||||
|  |             correct `shouldBe` parseWith entry input | ||||||
|  | 
 | ||||||
|  |             let input   = "x: 0" | ||||||
|  |                 correct = Right $ Entry "x" $ Regular $ Integer 0 | ||||||
|  |             correct `shouldBe` parseWith entry input | ||||||
|  |          | ||||||
|  |             let input   = "useTimes: infinite" | ||||||
|  |                 correct = Right $ Entry "useTimes" $ Regular Infinite | ||||||
|  |             correct `shouldBe` parseWith entry input | ||||||
|  |      | ||||||
|  |     describe "Special kinds" $ do | ||||||
|  |         it "can parse actions" $ do | ||||||
|  |             let input = "actions: {}" | ||||||
|  |                 correct = Right $ Entry "actions" $ Regular Infinite -- TODO Change this | ||||||
|  |             correct `shouldBe` parseWith action input | ||||||
|  |          | ||||||
|  |         it "can parse conditions" $ do | ||||||
|  |             pending | ||||||
|  |          | ||||||
|  |         it "can parse layouts" $ do | ||||||
|  |             pending | ||||||
|  |      | ||||||
|  |     describe "Lists and blocks" $ do | ||||||
|  |         it "can parse entities" $ do | ||||||
|  |             pending | ||||||
|  |          | ||||||
|  | @ -1,7 +0,0 @@ | ||||||
| import Test.Hspec |  | ||||||
| 
 |  | ||||||
| main :: IO() |  | ||||||
| main = hspec $ do |  | ||||||
|     describe "Dummy category" $ do |  | ||||||
|         it "Dummy test" $ do |  | ||||||
|             0 `shouldBe` 0 |  | ||||||
							
								
								
									
										1
									
								
								test/RPGEngineSpec.hs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/RPGEngineSpec.hs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | {-# OPTIONS_GHC -F -pgmF hspec-discover #-} | ||||||
		Reference in a new issue