This week I worked to add some actual gameplay elements.
Items and Effects
The major addition is an item and effect system split among three definition files:
- item_types - whether an item is consumable, has a cost, and what character is displayed
- effects - what stat is affected, is it increased or decreased, is it permanent, and is it cumulative
- items - defines the color, item type, the effects, and their values and durations (ex: “regen 1 10” heals 1hp per turn for 1 turns)
When the game starts it loads these three files and combines them to create a hashmap of item definitions.
Some items cost energy to use. To regain energy you must consume enemies. Right now this means kill and eat each individual enemy, but in the future I may add offensive abilities that consume multiple enemies at once or automatically consume weaker enemies without using a turn.
I have also made changes to the main game screen panels.
- Stats - added energy, strength, and defense
- In View - lists enemies and items in view and corpses you are standing on
- Inventory - lists the first few items in your inventory, can be used with f1-f4
- Map - added frame around the map
Because I took the time to write renderer and menu traits these changes were very easy to make.
Issues with Tcod Algorithms
While playing this week I ran into issues with the pathfinding and field of vision algorithms provided by tcod. I ended up switching to a different pathfinding library and implementing a fov algorithm. While the changes weren’t fun to do (I spent more than 12 hours translating fov algorithms from c and c# to rust), I am happy to have removed the tcod dependencies outside of the tcod renderer implementation.
I wanted to allow diagonal movement unless one of the two tiles along the diagonal are blocked.
The only real option for customizing the pathfinding is through a callback to determine cost between two tiles. I could have implemented my changes using that, but I decided that if I was going to have to write it myself anyways I may as well use a different library to remove another tcod dependency and give me more options for the future.
I switched to the pathfinding library which provides many pathfinding algorithms for directed and undirected graphs.
Field of Vision
I noticed many situations where enemies would get stuck in doorways and corner while chasing me.
The issue was that the fov algorithms provided by tcod were not symmetric so there were many situations where the player could see an enemy that couldn’t see them and vice versa. I spent a few days implementing different fov algorithms claiming to be symmetric and fast (one of them was neither symmetric nor fast).
The one I decided to use is by Adam Milazzo and is described here in a great comparison of different fov algorithms with well commented code samples.
A Better Map Generator and Reducing Coupling
I started thinking about what kind of maps I want in the future.
The current maze and cave maps are fine while testing, but they quickly get very boring. I created a map viewer to help me visualize what changes I want to make and so I could see where I need to decouple structs and methods.
The map viewer is essentially a minimal implementation of the menu trait with controls to generate maps with different parameters. By creating a second program that implements this minimal functionality I found a lot of places where a struct or method required parameters that were actually unecessary or should be split into multiple methods.
After playing with the map view for a while I decided that I want a map generator similar to the one that brogue uses where it generates various types of rooms, connects them, adds extra paths, and features.
- switch from tcod to pathfinding crate for pathfinding
- add mouse controls functionality (nothing uses it right now)
- add items and effects (three potions, a charm, and their effects)
- split game data and gameloop/controls methods into a gamestate struct and menu trait
- implement menu trait for game, message log, and inventory
- lots of cleanup and grouping things in submodules (map, menu, render, store)
- add energy stat (used to cast spells)
- add restart option after death
- implement milazzo fov algorithm
- remove tcod usage in map (so now it is only used in the tcod renderer trait implementation)
- add level seeds
- switch to characters for all tiles instead of blocks of color
- restructure tile, object, and item definitions
- add inventory pane (shows first few items)
- add f1-f4 to use first four items
- add consume corpse to regain energy
- work on making a map generator similar to the one brogue uses
- make changes to the ai to make it lose interest in chasing the player after a while and have different alert levels
- improve the inventory system: make separate quick use and equipment slots
- make a system for multi step commands (look, move until you hit a wall/see an enemy. etc)
- make “in view” panel only show monsters and what you’re standing on
- add mouse move/look
Screenshots and a Video
Main Game Menu
Message Log Menu
A short video of gameplay