Quest for the Mine Portal
This week a few things, focussed on getting something slightly more coherent together. The objective for this week was to have a quest that takes place in a mine. And not just any quest, but a portal summoning quest. So here we go.
Quest setup
Alas! There are fire elementals coming out of a portal in a mine. To keep things nice and neat, the first level of the mine is a working mine, with miners and without enemies or traps. The wilderness outside of the mine is still dangerous though. The second level of the mine will contain the portal, and it's overall a dangerous place - any enemy can be found here.
The quest to deactivate the portal is given by a village chief. At the moment, I spawn villages on top of city locations, but this is temporary until I get a city screen going (yes, breaking the non-modal roguelike rule)
Miners and ore
So, the first level contains lots of miners working in their mine. So how do we do that? Well, the C++ placement algorithm includes instructions for "miners" and "mined ore", but they are not matched to entities or even entity configuration, but to factory methods that are clever enough to detect what type of mine it is, to spawn appropriate ore, and that we should be creating miners that wear suitable mining equipment, namely a pickaxe and a leather cap. For these I had to make some extra composable sprites, which are mini-sprites that are used in a dynamic sprite composition process. So, the miner sprites are regular human sprites with some bolt-on cap sprite, a bolt-on pickaxe sprite, and so on.
Portal wave spawner
This is something essential I guess (well at least to my standards) - the support for spawning waves of monsters, in regular (or not) intervals. To achieve this I'm using some special "wave spawner" logic attached to an object. Objects with some kind of logic also take turns like creatures do, but unlike creatures, objects take their turns very regularly, at a custom specified rate. Creature turns depend on how long their last action took. So, long story short, the wave spawner logic spawns creatures, then waits until spawned creatures are all dead, then starts a timer, and when timer elapses spawns next wave and so on. When all waves are complete, it deactivates itself. And with a bit of custom code, we can have increasing number of creatures, different creatures, including bosses into the mix, etc. Here, we're keeping it simple and just use fire elementals.
Performance woes
At some point I had some horrible performance issue, which ended up being two issues really, both fixed. I was creating a settlement while in overworld, then tried to move in the overworld, and it was taking several seconds. Bad! This happened because all created turn-taking entities (villagers, 14 of them) got immediately into the time manager queue and could not be "frozen". Given that moving to another tile in the overworld tool 30 game hours, and a simple entity turn is 6 seconds, and I had 14 such villager entities, apparently in the time that it took for the player to move from one tile of the overworld to another adjacent one, the game had simulated 207,000 turns. Oops. This worked out at 0.17ms/turn, so performance per turn was not that horrible, but there were so many of them. Solution? Whenever I instantiate a level, every entity in that level immediately becomes frozen.
Second performance problem (and it was the one I encountered first) was every time an entity took a turn, the game time progressed, and the UI listens to game time changes and updates the calendar widget. Another oops, as in a single frame we might process 100 entities, which means 100 UI updates, replacing the exact same widget. No point whatsoever in doing that. What's worse, the GUI update was setting text in BBCode labels in Godot, and that process is notoriously slow. Anyway, fixed that too, all well
Month break
I'll be away for a bit more than a month for a special sort of summer break, at places where I might not be able to be online, and I possibly don't want to anyway. But I must try not to forget how to gamedev. So, see you all in July!