Monday 7 March 2016

7DRL Challenge 2016 - Day 1

Technically day 1 was yesterday, but I'll write up a summary of what was accomplished now since I ended so late in the day.

I took the framework previously developed for HarvestRL and converted it to use for this game: all the UI elements, the mapping functionality, and basic AI were working nicely with the next project. I was also able to properly create an executable that runs outside my IDE, which was a serious problem last year.

Most of my work on the first day, aside from getting all that stuff copied over, was to build a proper level generator. The extended version of HarvestRL creates a world map and generates outdoor landscapes according to the overworld terrain. That is not what I wanted here; there will only be one map, and it needs to be an interconnected set of rooms. I turned to the BSP generator in LibTCoD again and fired that up. It worked out okay, but it will need to be tweaked. Below is a screenshot of a dungeon it created. Notice that the varied land tiles work properly (this was from HarvestRL already).


I'm ignoring walls in the game (that's how I can move and see through walls in that screenshot), but that's from having debug mode turned on. Two more things need to be added to this generator. First, there need to be paths leading out of the dungeon to the edge of the map. These paths will be one of the two ways enemies will enter to attack that player. Second, I need to add caverns. Since this is meant to be a fort built underground, there needs to be a feeling of "undergroundness" and this will come across more easily with some cavern-like areas. There are several empty-space areas of the map, so most likely that's where I'll put them. If they cross existing corridors, that's even better.

After playing around with this though, I realized that my initial idea for the game was going to be very tedious. The plan was to have the player clear out the dungeon, then more enemies would spawn, and you'd repeat this until some end-game condition was met. Looking at the size of this dungeon, and remembering that backtracking will occur, such a cycle of play sounds boring. That's no good.

Instead, what I will do next is fill the dungeon with enemies already, have more enemies spawn from uncontrolled regions, and the spawned enemies will seek out and attack the player (capturing rooms along the way). Since I had planned to let the player make traps and barricades and such, this change in enemy behavior will still work. It will probably add significant tension to the game too, which is something I wanted.

I won't have much time on Days 2 and 3 of the challenge, but my plan for those days includes:
  • Add caverns and doors to the dungeon layout
  • Have monsters start in most rooms, with the Guard AI
  • Spawn monsters, and have these hunt the player character
There is already rudimentary combat and health, so that will help with testing how well I can clear out the dungeon and potentially die. This will give me the opportunity to add the losing and winning screens back in, and have a way of properly ending the game. If all that can be finished by Day 3, then the rest of the week will just be adding in more content and polish.

Saturday 5 March 2016

7DRL Challenge 2016

Despite my desire to do more work on the upgrade to HarvestRL, I'm going to use the 7DRL challenge to again get something else done. This time, I'm working on improving various aspects of combat and positioning, so my entry this year is going to handle those things.

I'm calling it Deep Despair. The theme is a dwarven warrior who's lost everything except a vault of gold and is desperate to protect it. The game is going to be closer to a Hero Defense than a traditional RL in style, but I want to use the RL engine I've already built and add better combat mechanics to it: proper use of special attacks, positioning yourself to block attacks, and so on. The combat in HarvestRL was simplistic and much more uninteresting than I had anticipated. This time around, I plan to focus on that part of the game to make it more interesting.

When this is finished, I will have another game that is (hopefully) enjoyable to play but also has everything I need to put better combat into HarvestRL. I'll probably be lucky to have even 30 hours over the next 7 days to work on it, so we'll see how things go.

Thursday 23 April 2015

Simple Village Generation

Although I will be improving the village generator that I used in HarvestRL, this post will share my original method. It was rather simple, so people who want to quickly throw together a village might be interested in this.

First, here is what a typical village in HarvestRL looked like:

For those unfamiliar with dungeon generation, realize that you can use those algorithms to create pretty much anything even if they aren't supposed to be dungeons. That's a hint for what I did here. The full process worked somewhat like this.

1) Determine the space on the map to use for the village.
In this case, I used a random width and height between 40 and 60 tiles. This variation helped to keep the village from seeming too similar each time, and it also varied the population numbers.

2) Make a road into the village.
I picked a random point in the middle of the Southern edge of the village and created a path that went through that point. It started at the edge of the village and went into the middle of it. The end point was also randomized so that it didn't always stop right in the middle of the village, sometimes it stopped a little short. Then, I generated the other half that went from the edge of the village to the edge of the map. Once the path got a certain distance away from the village, I had it meander like a river. The path always led south out of the village, because I didn't want to make the farm's starting location too random.

3a) Divide the village space.
I used a Binary Space Partition (BSP) algorithm to break up the village area into smaller chunks. Libtcod already provided this. Defining the smallest space to be about 8x8, I worked with 3 levels of divisions to create a series of spaces. These I saved as rectangle objects. Although you could use the generated BSP Tree to store the connections between these rectangles, I didn't do that.

3b) Organize the partitions.
Each rectangle was a "plot of land" for a villager on which a building would be placed. The size of the building was randomized further (an inner rectangle), so that the spacing between buildings would be non-uniform. I stored this inner rectangle as a separate value in the same Building object (which at this point had two values: the rectangle for the plot of land, and the rectangle for the building). This step was performed while iterating over the leaves of the BSP Tree, and then I discarded the Tree since I didn't need it anymore.

3c) Discard rectangles over the village path.
Since the path was generated before the partitioning, each rectangle was checked to see if it overlapped with the path. If it overlapped the path, I didn't save it. This guaranteed an empty space where the path went into the village, so the entrance wouldn't feel too crowded. Since the rectangles varied in size and position, this could also affect the number of buildings (and hence population) in the village.

4) Randomize the type of building.
I made an enum containing all the types of buildings that I wanted to have in the village. Then, I added the required types of buildings to a list (in my case, the Harvest Shrine and the Shop), filled 3/4 of the list with homes, and then filled the remainder with random picks from the list of building types. A full list was equal in size to the number of buildings that were created. This ensured I had a safe distribution of homes, businesses/specialty places, and quest-required buildings. Due to lack of time on the 7DRL, most of the building types just reverted to homes.

5a) Assign building types.
At this point I have two lists: one of all the Building objects, and one for all of the building types to be created. Both lists are equal in size. First, I picked the largest building and made it the Shrine (the first building type in its corresponding list); obviously, this is not necessary for other games but it shows that the generation order does not have to be random. After this, I iterated over the list of buildings and gave each the next entry on the building type list. Thus, I could guarantee how many buildings of each type were created, and keep the possibilities random; the random choice of building types occurred in step 4, while step 5 decided where that building type would become instantiated in the village. This step could be improved, such as assigning types based on the relative positions of buildings, but it worked well for a quick village.

5b) Orient the building.
As I assigned building types, I also oriented the building. I picked a random edge of the building, labeled it the front, and stored that value (I just used a direction enum, the same enum used for movement directions). This step could be done more intelligently; for example, buildings close to the middle of the village would face outward and buildings near the edge of the village would face inward. You could easily calculate what is inward vs. outward by looking at the closeness of the building to the center of the village. I just left them random, except for the Shrine that always faced South.

6) Instantiate the building.
With all the details decided, I iterated over the building list and changed the terrain of the map. The outer rectangle was filled with grass, the edge of the inner rectangle was made a wall, and the inside of the inner rectangle was made a floor. Then I picked a random spot along the front wall, that was one tile away from either edge, and made that spot the door. A short dirt path was created from the door to the edge of the land plot. Some furniture was randomly placed in the building (which looks strange at times, since it's too random) and a random number of inhabitants were created (between 1 and 3).

The furniture and number of inhabitants was dependent on the building type. So, when you're playing the 7DRL and you enter a building containing one person and no furniture, that's because the building was not actually a home. Note that building types could also be other village features, like a graveyard or a garden or a fountain. Again, I had that in the code but never finished it so sometimes you'll find a village with big open spaces between buildings. For a more intelligent method of creating interiors, you could use plans that can change in orientation. The only plan I had was for the Shrine, but it was so hard-coded that I couldn't change the orientation (hence why the Shrine had to face South). I had already spent enough time on other stuff in the game that I didn't want to make the room plans better, but I can do it now.

7) Create a town wall.
I thought about doing this but didn't in the end. However, it is pretty easy to add if you want. You already have the borders of the village saved, so just create a wall around the edge of it and leave an opening when you come across the path.

So, that's the algorithm in a very broad sense. Since it uses BSP it still seems somewhat blocky, and that's why I want to use something different in the Extended Edition of Rogue Harvest. However, if you want to generate a village with a few hours of coding then this works. You'll need a BSP implementation, but you might be using that for dungeon generation anyway.

On that note, the area around the village was generated in an even simpler way. Notice that the edges of the map are non-uniform but in a somewhat smooth manner:


What dungeon generation algorithm does this? The Cellular Automata one, that's what. I created a grid with a one-tile border, randomly seeded a few other places, and ran the automata algorithm a few times. Then, I took it and used that to create the edges of the map (the mountains) and rocky places in the middle. This created the valley for the village, and it was created before the village; that way, when I generated the village, terrain around the village could be cleared and buildings wouldn't be lost to random mountains cropping up in someone's backward.

I also used a random seeding of the same grid, and ran it just once to create the grass and stones that litter the valley. Even though you don't need to have something as elaborate as this for open wilderness areas, I highly recommend having something other than stretches of plain grass (the .'s in my case). With a map as big as this game used, having pure grass looks very unappealing. A similar problem could exist with too much variety though, or having a display with confusing meaning; for example, using lower-case letters to represent enemies as well as trees and other wilderness features could be confusing for the user to interpret.

So, there you go. This whole process took me about 5 or 6 hours to think of, plan, and code. While it definitely has some areas for improvements, it's pretty good for a simple outdoors village.

Sunday 19 April 2015

UI Redesign

Given the reviews from the 7DRL Challenge, and my own annoyances with the previous version, I have started the remake of Harvest RL by changing the UI.

First, I wanted to add mouse support. This has been the brunt of my work so far, mainly because of how I coded the UI to begin with. At this point though, mouse support is almost complete. The last thing I need is to get mouse targeting and looking to work properly. Then I'll add the Game Options screen to allow disabling of mouse support (for those who really dislike it) and call that feature complete.

Second, I wanted to change the inventory. There were several complaints about using shift+t to throw items, as an example. Although I had little difficulty with upper-case letter commands, I want to address it for others. The reason I chose this control scheme was so that lower-case letters could be used to select an item, and then upper case letters would interact with the chosen item. After thinking about it more, I realized that I could just use a separate window for the chosen item with the necessary commands. That way lower-case letters could be used for both item selection and item interaction. Two key-presses are needed for things like throwing anyway (even if you use "throw" + "choose item"), so I just needed to make minor changes to the inventory for this to work.

There's a picture of the new inventory screen here. I also added the ability to view (and remove) equipment and put in buttons for the mouse, instead of just key-command tooltips. I'm not satisfied with the button coloring yet, but their functionality is good.


Third, I wanted better info for allies and enemies. There is now a list of enemies on the screen, with health information. Attitude and status effects will be shown there too, but right now that's not even included in the AI yet. After I restore the status effects that I took out from my previous framework (due to it not working right) then I can get hunger, tiredness, and stunning connected to it. That should greatly improve some of the UI issues with those things. Hunger and tiredness need mechanical changes, but I'll work on that later.


Lastly, some people might notice that I'm using a different font. Although I particularly liked the previous font (it's the one I use for Dwarf Fortress all the time), the sizing of this new one gives me a lot more options. I could take inspiration from CogMind and use multiple fonts, but I'm not going to; I'm already experimenting with a different library for drawing routines, and it will cause any work that I do on multiple font rendering to be useless.

This is then the official start of a new version of this game, which I think I'm just going to call Rogue Harvest: Extended Edition. I might change the name later, but it's the tentative name for now. Once these minor UI changes are working properly, I'll put up a proper development plan and do more regular updates.

Saturday 4 April 2015

HarvestRL New Update

As it turns out, there were still several bugs in the previous version, some of which were quite major. I fixed these, added a better intro screen, and greatly optimized the loading times. This may have introduced a minor loading bug, but that's not too important for me. As of version 1.02, I am considering this game complete. It's not great, but it's finished.

That being said, I am taking this and expanding it into a new game. I'm trying to decide if I want to call it HarvestRL2 or HarvestRL:X (for expanded) or just a totally different name. The goal will be similar, but with a different time scale. Currently you can finish the game in 10 or 15 days (potentially even 3 though most of the village dies in that scenario), and I wanted something longer to bring about more interesting aspects of the farming.

In addition, there are major UI problems. The ASCII stuff is fine, and even the way I've displayed information works, but the control scheme does not. I'm going to experiment with a different library since I'll have to make some major changes anyway, see where that takes me, and go from there. I plan to merge the code from this project with another one that involved random world generation but never saw the light of day.

For now, you can get the latest version of HarvestRL here.

Friday 20 March 2015

HarvestRL Update

After taking a break for a few days, I went back to the code for HarvestRL and started making some revisions. There were some rather major bugs that made the game impossible to complete at times. In other cases, the game was exceptionally easy (though this was a rather circumstance). I've gone through and fixed what I thought were the major issues with the game.

So, version 1.01 is now available for download. The full details are available here.

Wednesday 18 March 2015

HarvestRL Postmortem

With the challenge officially done, it's probably a good time to reflect on the game. It needs polish, and I'll have some fixes and adjustments done for those.

Rather than just growing crops for money or whatever, I wanted there to be an actual point to it. One aspect of this was growing food to keep a food-clock in check. Having the player be so hungry that they need to eat every second was just plain annoying, and it made far more sense to have the player grow food for the village. Initially I was going to have the option to sell food to a merchant (for money) or donate it to the village, and have that as a choice. The selling never made it into the game, so it's just an issue of donate it or keep it to eat. The overall clock is what I intended in the game; currently, it's too easy. There isn't enough pressure that the player needs to decide what to do about it since food is too readily available.

The combat is sufficient though tactically shallow. The player has very few hit points for several reasons. I wanted no randomness in the combat. I wanted each opportunity to be hit to be significant. I wanted damage reduction to be limited. As a result, the player should regularly get swarmed and then have to figure out where to go to avoid getting quickly killed. This becomes less of an issue near the end of the game (again like I wanted it), but the final boss is still exceptionally difficult. Unfortunately, it's difficult in a tedious rather than tactically interesting way. However, this is because of another issue.

There's no consumable combat-related items except healing and a weak ranged attack. The ranged attack is certainly useful (especially since it's the only non-renewable resource in the game), but even a few more special effects would have made a huge difference. Unfortunately, the framework I had in the game wasn't working with special effects yet, so I just hardcoded these two quickly (along with the seeds) and left it at that. Later versions will definitely need more, and a greater variety of enemies, to deepen the combat. That is definitely the weakest part of the game right now.

I also really dislike the village generation, but I spent a whole day on it and didn't want to lose any more time for the challenge. The underground levels are actually close to what I initially intended. They're not great, but I didn't want something fancy anyway. It is annoying that you can get an unwinnable game due to the RNG, but at the time I wasn't thinking about such an issue.

Overall, I'm content with my first successful 7DRL. There's a lot of room for growth with this game, but I'm torn between doing regular updates to HarvestRL and turning it into something more versus renaming it as a new game and pushing the boundaries on it. I'm leaning more towards the latter choice though.

I can also integrate this game with others I've started over the past few years but never finished or released. Since I now have something available, and have a means of updating and releasing new versions of things, you'll start seeing more games from me in the months and years to come. Hopefully, that will be a good thing.