My entry is available at https://benob.itch.io/expelledrl. You play as a hero who just arrived in front of the amulet of Yendor after battling and levelling for the length of the dungeon. This is when everything derails...
I couldn't figure out how to make working standalone executables out of python+tcod, so you have to deal with the source code download. This post is full of spoilers, so start by playing the game.
I had to battle a lot of bugs at the end, and some I was not able to squish. The game includes a story, a tutorial, a whopping 13 different endings. The main innovation is the possession spell, at the heart of the game-play.
You cast the possess spell by pressing 'p' while there is exactly one enemy in your field of vision. You take control of it and let go the control of your previous host. The host either dies, suffers or starts following and helping you. There is a cooldown period which depends on the value of the host so that you can't jump from body to body. The possess spell is implemented by being able to the AI controller of a creature by a controller based on player input.
In addition to the restriction on enemies on screen and cooldown, the other mechanic that pushes you towards swapping hosts is that there is no healing.
Once you possess a creature, you gain access to all its buffs and spells (press the 'a' key). Some can launch fireballs while others can summon rodents. Terrain buffs help you cross rivers.
Since I did not have time to implement an inventory system, there are no items. With possession, this makes monsters the items as they provide the bonuses that you may get from items. You find yourself exploring levels to find a certain type of monster.
Combat is quite brutal and quick escape is vital because of those features. There is no time system, so all monsters move at the same speed. The only way to outpace a foe is to leave its field of vision, thanks to a loosy AI;)
The game is composed of 9 levels. The first is the outside of the dungeon, just a cosmetic level with no challenge. Then, each level presents a new enemy or new feature of the game. The generator is the original generator from the tcod python tutorial. The last level is static and contains the boss. The boss itself is an overpowered caster who can summon any creature from the game. So, the basic strategy is to isolate one of its summons and possess it. Hit, get hit, rinse and repeat. The ending depends on who you possess when you kill the boss.
Implementing a RL based on the possession mechanic has several challenges.
- The first one is that anything that the player can do, everyone must be able to do. That includes vision, items, spells,... This suddenly adds a lot to the TODO list.
- The second one is that players will try to bring with them a whole family of useful hosts to be able to use them at anytime, or they may try to stick to a universally useful body. The game has to impose restrictions to limit that behaviour.
- The second is that the certain challenges depend on the availability of a monster in the area. Making it fun for the player to find that critter can be difficult, it it is easy to create frustrating dead-ends by letting the key monster die.
- The last one is that you need to implement monsters with quite a variety of capabilities to make the dungeon interesting. It requires a lot of development time, and balancing is much more complex as if you want to overpower the player, you also overpower an enemy.
In term of restrictions on possession, I opted for a cooldown timer, no healing, and a single foe in view. I could also have explored a decay which removes hp with time which would act as a hot potato which kills you after a timer. I also though of underpowering high-power monsters when they walk stairs (by alternating element themes such as water and fire).
I didn't have time to implement items and inventories, but I had, I still wonder how to prevent the player from systematically dropping all its equipment before possessing another monster. Maybe single use items which "fuse" with the critters could be a reasonable option.
The game is developed with python and libtcod. I have quite some experience with rapid prototyping in python, and that makes it a good language for those kind of projects. I had never tried libtcod before and therefore I started with the tutorial. The first problem was python2, which nobody uses anymore (really). I found some ports of the tutorial but it was a bit late. A more serious problem was that the data structure and design choices in the tutorial turned out to be counter-productive and I had to refactor a lot of the code. Lack of time quickly made it look like a plate of spaghetti. I really wanted tiles (and bought an Oryx set), so I was disappointed to learn that tcod cannot stack transparent tiles on top of eachother. I wrote a pysdl2 renderer in one evening to replace the functionality which also allowed me to use non-monospaced fonts. But handling the mouse turned out to be too complicated so I dropped mouse support. I also developed a tool for rearranging my tileset although given the number of tiles I have used it was not necessary.
All in all, I had a lot of fun to participate in a 7DRL, my first. I had explored RL dev before, but never made a complete game. I am glad I succeeded.