Happy Christmas everyone! I have the honour of the Christmas Day F# advent calendar post
Thanks Tomas, ha!. I had a whole bunch of different ideas, and typically, I decided to choose the largest, most complicated one. Because of this, there is a lotof code written in just a couple of evenings. It is for the most part, badly designed, horribly written, nowhere near finished and should not be used as an example on how to write anything approaching nice F# code! /disclaimer
If you know me at all you will know that I tend to write lots of crazy type providers. This will, of course, be no exception. In fact, even though I wrote this in just a couple of evenings, it’s probably the most complex ridiculous TP to date. To achieve this, I have used my Interactive Provider which is basically a type provider abstraction that lets you create crazy type providers without writing any provided types code at all! Rejoice.
The TP is a game, which is based on the legendary circa 1980~ game Rogue. I realise that many people will not know about Rogue (although the term Roguelikeis used a lot more these days) so I will explain a few bits that characterise a roguelike game
- There are no graphics. The character is typically thrown into a dungeon which is rendered using ASCII characters only.
- They are procedurally generated. Not just the dungeons themselves – a red potion in one game will be very different to your next.
- They are hard. Although there is an end, usually you just see how far you can get before you die
- They have permadeath. When you die, that’s it – start over from the beginning
- They are typically very complex. Modern roguelikes are epic works of engineering with vast amounts of crazy stuff you can do, cause, and interact with, often in strange and fascinating ways.
Escape from Santa’s Grotto!
So, Christmas Eve is finally over and Santa plus crew have been celebrating a bit too much in the grotto / workshop. One things leads to another, and everyone is smashed on all the sherry picked up from the previous night. Santa wakes up at the bottom of the grotto, hungover, and unfortunately discovers that most the Reindeer and Elves are either still on the sherries or have fallen asleep drunk. Now, everyone knows drunk Reindeer and Elves are incredibly violent, even to Santa. Can you help him navigate his way up through 5 levels of the grotto?
Above shows a typical example of a starting position. Important note!For this to work you MUST use a fixed-width font for your editor tooltips! I recommend Consolas 10-12 (anyone would think type providers were not designed to run games!)
Here is a list of the possible characters and what they depict in the dungeon
- @This is Santa, the player
- =Horizontal wall
- | Vertical wall
- # Corridors that connect rooms
- . Floor
- / Open door
- + Closed door
- * Piles of presents
- % Carrots of various types
- ! Mince pies of various types
- E Elf
- R Reindeer
- < Stairs leading downwards
- > Stairs leading upwards
As the game progresses, you gain experience by killing hostile elves / reindeer and will level up, which increases your maximum hit points, makes you hit harder and more often. Santa will heal over time, but he also gets hungry and must eat. Perhaps you can find some other items that can heal you?
A typical full level map might look something like this
Notice you cannot see any items or monsters that are not in Santa’s field of view (FOV). The FOV algorithm is different in corridors to when you are in rooms, and it is largely terrible due to time constraints, but it still works ok :) Each turn, you are presented with a list of properties in intellisense that represent the available actions for you to perform. Some of these require further input in the form of another list of properties. The available actions are as follows.
- Movement. Represented as N, NW, W, etc. This will move you one tile in that direction, if possible
- Pickup. This will take an item at your feet and put it in your inventory. Note: you will see in the status at the bottom of the screen when you are standing on something you can pick up
- Use Item. This will present you with a list of things in your inventory which you can use. Only trial and error will tell you what a Blue mince pie does, be careful!
- Drop Item. You can drop things. You might notice that Reindeer and Elves sometimes eat stuff they stand on. Perhaps this could be useful?
- Open / Close. You will be asked to pick a direction, at which point the door (if it exists) will be opened / closed. Note that the monsters cannot open doors!
- Wait . Waste a turn doing nothing. Santa gradually heals over time, be he also starves to death if you don’t keep him fed!
- Climb. This will take you to the next or previous level if you are standing on some stairs.
- Roguelikes are risk management games. Often a lot of chance is involved. Food should be a top priority as lack of that will kill you off given enough time, no matter what. To this end you should try to make sure that the monsters do not eat any food lying around on the floor by ensuring they don't walk on those tiles.
- Similarly, eating mince pies is a game of chance, you could get lucky, or it might go horribly wrong. In any case, once you know what a specific colour pie does, you will know all other pies of that colour do the same thing.
- Another way to identify mince pies is to drop them in the path of monsters and see what happens to them if they decide to eat it.
- Use doors to your advantage - monsters cannot open them.
- Sometimes you will be able to sneak past monsters without waking them - you must balance this with fighting and gaining experience, as the monsters will get tougher in each level.
- Monsters cannot follow you up and down stairs.
- It is easy to cheat as this is a type provider, you can just undo your steps. Don’t do that, you are only cheating yourself!
- There are (at time of writing!) 8(!!) different types of mince pie! be sure to experiment, there are some interesting ones such as this!
In order to attack something, simply move in its direction. At the end of your turn, any monsters that are awake will probably try and close in on, or attack you. You will see the results of this at the bottom of the screen in the status messages. If there are more than 2 status messages, you will be presented with a single property named “More” which will continue to cycle though the messages until they are exhausted. I didn't have time to write anything except very rudimentary AI so they are pretty dumb and you should be able to get them stuck on each other, in corridors, and all sorts. Actually! I have changed my mind. They are all still drunk, that is why their path finding is practically non-existent, and not because I had no time to do it!
Some final notes!
Well, I must admit I was furiously coding away just to get this to work at all. There are still some bugs in it, and balance is way way off. Roguelikes usually have an element of luck but this one more so than normal :) I only managed to get a small portion of what I would have liked in, but it still is quite playable (albeit incredibly hard sometimes) and I am fairly sure it is the only roguelike type provider in existence!
To get it running
Head on over to my github, clone and build the Interactive Provider. The IP works by scanning assemblies in a given location to find types that implement IInteractiveServerwhich it then uses to provide the types. Because of this you will need to point the Interactive Provider to the location of the XMAS_2014.dll file, like so
1 2 3 4
#r @"f:\git\InteractiveProvider\InteractiveProvider\bin\Debug\InteractiveProvider.dll" type GamesType = PinkSquirrels.Interactive.InteractiveProvider< @"F:\git\InteractiveProvider\XMAS_2014\bin\Debug\"> let games = GamesType() games.``Start The North Pole``.
Please have a go, and let me know if you beat by tweeting @pezi_pink and / or #fsharp over on twitter! If you manage to escape, be sure to let us know how many presents you managed to pick up on the way!
HO HO HO!