Monday, October 31, 2011

I was going to create the player and rooms to move around in but I decided to add a little more to the map. The very crowded map now shows bonus items in dead ends and secret rooms. You can also mouseover a room to see details about it's region, name, and contents.

There's a limited amount of keys and locks so if you add enough regions then you'll see "key #33" or something like that.

Here are some things I added:
for each unlocked dead end, there's a chance of adding a random lock and bonus
when placing a room, there's a chance of adding a secret room
when placing a room, there's a chance of a name and or some item

I'm not sure what theme or items I want in the final game, the ones here are just examples. Once I get the mechanics figured out (like how to create an interesting map) then I can figure out what theme I want to have.

I think I've crammed all I can into the map for now; time to start on actual gameplay.

Sunday, October 30, 2011

My last post had a bug where new regions may not connect to a neighboring room. I thought about fixing it before posting but decided to post it anyway. Now I hate buggy software as much as anyone, and this bug makes the map unsolveable since there can be rooms you can't get to, so why did I post it anyway?

This is a work in progress and sometimes - most of the time - those are messy. Sometimes it's good to see how things are made, bugs and all.

I already fixed it when I changed that part of the code for my next iteration.

So what caused the bug in the first place? I changed the code that connects a room when it is placed. I made it keep placing connections until the new room is connected to another room in the same region unless it was the first room in that region. Otherwise a room could be placed and it would connect to a neighboring room from a different region and not connect to a room in it's own region. If that was the room that had the key and it was locked with that corresponding lock, then there was no way to get the key. In fixing that bug I introduced a new one.

It took a few hours and I had to rewrite the code for doors, but I've got keys and locks working. A major part of any metroidvania is exploring new areas and finding some kind of impassable barrier - a wide pit, a wall of metal blocks, a force field, etc. It's only later when you find some new ability or item - double jump, rocket launcher, field disabler, etc - that you can go past the barrier to a new region. You can abstract this idea of obstacles and items as "locks" and matching "keys". In one game the "red locks" and "red key" might represent actual locked doors and a key, in another game they might be security cameras and a disguise, and in another game they might be tall walls and the ability to climb walls.

You can see the locks and keys in my latest update. The icons are ugly and hard to distinguish, but it's just for example and will be redone many times before the project is over. Consider this the "alpha version" artwork.

[I just noticed that sometimes the first room in a region doesn't connect to the other rooms. A bug I just fixed when I redid that code for my latest work.]

when visiting a region for locks and keys:
place an unused key
put the matching lock on one door to each unvisited adjacent region
any unlocked doors to adjacent regions are added to a "to do" list
visit each unvisited adjacent region

after visiting all regions for locks and keys:
for each unlocked door on the "to do" list, put a random used lock

This ensures that each region has a key that you need to proceed to the neighboring regions. Although; since each region can connect with its neighboring regions multiple times, it's theoretically possible that getting the first key would be enough to explore all regions.

Saturday, October 29, 2011

Different regions! It was easier than I thought it would be - of course it has been in the back of my head for a while so I didn't jump in with my first thought.

to start a new region:
create a list of all frontiers for all rooms
randomly pick one to start the new region
clear all other frontiers
place a room as normal

The current region determines the room color and a randomly chosen maximum height and width and can easily be used to control more things like the artwork, items, bad guys, secrets, and other things. Like placing doors, this algorithm is guaranteed to connect with existing regions and could even connect multiple other regions.

The rooms are now connected! I used a very simple method that's guaranteed to connect and will even create loops to join different "branches" that happen to be near by.

to connect a room:
after placing a room
get a list of all adjacent cells that are in a room
randomly pick some cells to create doors

This can create multiple opening between two rooms. That's not a problem yet but it could be tweaked later on. This should be enough to create the gameplay portion but I'd like to work on defining different regions at the world-gen level before I move on to creating a player to run around.

Time for a retrospective! I think retrospectives are probably the most important thing a developer could do since reflecting on what you've done is the difference between someone with 10 years of experience and someone with 1 year of experience repeated 10 times. There are as many different styles of retrospectives as there are teams who do them but I've found that these few questions are usually good enough for me.

What does this retrospective cover? For this roguelike tutorial I tried a few new and different things; the most obvious one being that this was a series of blog posts. This is also the first time I had something of a magic system. There were also a few tweaks to how I normally code things. The roguelike itself is not meant to be a complete and fun game - it's just a basic example of a few different things that may help some roguelike developers - so I'm not going to review the game as a game.

What worked well? As far as code goes, the Screen interface worked really well. Having goblins pickup and use items is neat, as is learning the identity of things by watching others use them. As far as a tutorial goes, I think it can be useful for some people. Even though like there are, at most, a handful of people who read each post, I did get more feedback than I expected, including a reference to behavior trees - something I didn't know about. I'm also pleased that my posts were a mix of code, references to other sources, and some of my own thoughts about why I'm doing what I'm doing. It's not as authoritative as saying "THIS IS THE ONE TRUE AND RIGHT WAY TO DO THIS", and some of it was probably a bad idea, but I've always found that the most instructive guides show the uncertainties and mistakes we run into and how to deal with them.

What needs to work better? One thing I've learned about building something via blog posts is that refactoring is very difficult to show; it's easy to show new code to add, especially if you have small classes and methods, but I don't know of any easy way to show removing, rewriting, and refactoring. This means that the final code, although mostly small pieces, could use a lot of cleanup work and this isn't representative of my best code and may even be a bad example. Oops. Using no globals was a laudable goal but lead to some things I'm not to happy about, like the path finder using a collection of points rather than a fixed size 2D array since I didn't have an easy way to tell the path finder what the map size is. There are a few minor annoyances with the code, like the creature class becoming a behemoth, but most of that is from adding features without refactoring. The spell-related code is quite ugly and clunky too - mostly because I'm not familiar with writing magic systems and couldn't refractor so it was just charging ahead with little idea what I was doing.

What should be done differently next time? I still think a series of blog posts can make a good tutorial but it needs something that makes it easier to show refactoring - perhaps putting everything on github and discussing the changes each time. That would be a slight improvement but still not quite good enough. I tried to be very structured to make sure I followed through and didn't lose interest halfway through but it would have been better to break it into more than 20 parts. I've used Ninject to make it easier to wire things together and something like that would work well for this kind of project; I thought about it but didn't want to add another post about how to use a dependency injection framework.

In summary

Use something to counter the limits to show refactoring on a series of blog posts.

Don't limit yourself to a fixed number of posts.

The Screen interface was the best thing I did: keep doing that.

The AsciiPanel was useful but it needs work to avoid flickering and to support animations.

Each post should have code, narration, references, and details about the author's thought process.

I liked getting comments from readers even more than I thought I would.

Any feedback from you, readers? What did you like? What did you not like? What could be done differently?

Tuesday, October 25, 2011

One of the things I enjoy the most about roguelikes is identifying items. Usually not by scroll of identify or funky unicorn tricks, but by boldly quaffing and reading — yeah, I tend to die a lot. Identification is something I haven't seen in other games and something that I think any good roguelike needs. The basic idea is that if we've identified an item, or given it a name of our own, then we see the name, otherwise we see it's appearance.

Since the appearance has to be passed in, our code is broken in all the places that create items - this is a good thing because now we can see what areas we need to change. If appearance is null then the name is used since most things look like what they are; e.g. a rock looks like a rock and a sword looks like a sword. Because of this we can pass a null appearance to all items except the potions. Before we get to the potions we need to set up some colors and text to use in our factory.

This creates some text ("red potion", "green potion") and some corresponding colors (red, green), and shuffles the text so each time you create a new factory they will be in a different order. Since we create a new factory once per game, each game will have different text and colors.

Now to set the potion color, just use the new data when creating potions.

Our CreatureAi class needs to record what items have been identified and what the names of identified or renamed items are. We could have this tracked by the items themselves or some global variables, but this way creatures can identify and converse about item appearances too. By modeling it as close to reality as possible, i.e. where creature's have their own mind and names for items, interesting possibilities and emergent behavior are more likely.

Wherever we use an item's name we need to use nameOf instead. The easiest way I can think of doing this is to make the name method private and see where the code breaks. Those places need to use the creature's nameOf method instead. The only places we need the real name is in the PlayScreen where we check to see if the player has the Teddy Bear, or whatever the victory object is, and in the CreatureAi getName and setName methods. Once we make all the other changes we can make the name method public and everything should compile again.

Run it and you should see that potions are now listed by color instead of the real name. I got an error when starting but that was fixed by setting up the GoblinAi before the Goblin is given a weapon and armor.

Now we need to let the player identify things when used. In the StuffFactory, for each quaffEffect make the creature learn the name of the potion if any effect happens. Here's an example:

The Creature's throwAttack should also let the thrower learn the name of anything that has a quaffEffect. Now when you play you can learn the identity of potions by quaffing or throwing them.

It's still possible to learn the name of an Effect that you shouldn't learn. If you kill a bat with a yellow potion you shouldn't be able to see the effect it had or identify what the potion is since the bat died from being hit by a bottle and there wasn't anything left for the effect to apply to. Let's create a version of the doAction method that handles this logic. This version of doAction will take a message and an item. Anyone who can see the creature should see the message and learn the identity of the item, unless the creature is dead, then nothing happens. We can reuse some of the code in the current doAction.

The goblin quaffs a cyan potion.
The goblin looks stronger.
The cyan potion is a strength potion!

If the potions' quaffEffect use this new doAction then things will work a little better and we can remove the learnName from throwAttack since everyone who see's the creature will identify the potion based on the effect. This also means that if your creatures quaff potions everyone who watches can figure out what it is.

And that's one way of doing item identification. We had to make a lot of little changes all over the place, like using the creature's nameOf instead of the item's name method, but it wasn't difficult or error-prone. Each creature has it's own idea of what things are named so you could even let intelligent creatures tell each other the names. Maybe each goblin should quaff one unidentified potion during it's life and then discuss with others.

Or all goblins could share the same itemNames map — although that's kind of cheating.

You could also let the player give names to things. A RenameItemScreen that let's you rename a specific item or all items with a specific appearance. That way if the player deduces that red potions are healing potions then they can rename all red potions to healing potions or if they like their individual sword they can rename it Excalibur.

One last addition: add a "cause of death" string to the creature class and pass one in to modifyHp.

Friday, October 21, 2011

Time to add some magic to our game. This will take a lot of code and will take a long time to balance. To keep it simple, we'll just use mana and spellbooks. Scrolls are easy to add since they're basically potions that you read instead of quaff so I won't add scrolls - but I'm sure you can figure out how to do that by now or at least you will be able to after this tutorial.

We're going to have spells and each will have it's own effect. But when we add that effect to a creature, we want each creature to get it's own effect, otherwise weird things will happen because the spell will have an effect being applied to many creatures and the shared state (like duration) will be wonky. Instead, a spell will have an effect and when applying it to something we can create a copy and apply the copy. That way each time you cast a spell the effect will have it's own state. Add a copy constructor to the Effect class like this:

public Effect(Effect other){
this.duration = other.duration;
}

The first new class we'll need is a Spell class to tie together a spell name, cost, and effect.

Don't forget to initialize writtenSpells in the Item constructor. This should allow us to create scrolls, spell books, notes, or even engraved items. Very simple and flexible. If we create an effect that just displays a note to the user then we could even let the player add his own non-magical engravings to items.

Let's add some spell books. I'm going to create two simple ones but you should add more spells and more books. These are just examples of what can be done. The first is a healer type book:

Now we just need a ReadScreen to select an item to read, a ReadSpell screen to select a spell from the item, and a CastSpell screen to select a target for the spell. You should be able to figure those out but let's do them in the opposite order:

Update the PlayScreen to add spell books, map the r key to the new ReadScreen, and update the HelpScreen.

I know this is already a very long tutorial, but there's one little thing that bugs me. The creature class has some special methods that are only called when gaining a level, the gain* methods. They're only called from one place and they're small enough that we can just inline them. Eclipse, and most IDEs, can do this for you, just select the method name, right click, Refactor, Inline.

(days later....) I just realized a different, and almost certainly better, way of handling effects for each spell. Instead of each spell having a reference to an Effect and using the Effect's copy constructor, the spell class should act as an Effect factory and have an abstract newEffect method. Each individual spell would subclass Spell and implement newEffect. I'll have to do that with my next roguelike.

Tuesday, October 18, 2011

Let's add some potions now. When the player, or smart monster, quaffs a potion it's effect will be applied to the creature. What can we say about effects? Most effects will only last for a certain duration. Some will apply every turn or every few turns (like poison or a slow heal). Others will have a change that lasts for the duration (like confuse or resist cold). This can be done with a start method that that applies the change when first quaffed, an end method that unapplies the change when the duration has run out, and an update method that is called every turn in between. I think this will cover the basics so let's get started on them. We'll create a base Effect class and subclass it with specific effects.

I think I've said this before but that InventoryBasedScreen is really paying off. Now bind that to the 'q' key in the PlayScreen class and update the createItems method, also in the PlayScreen class, to add some potions. Try 3 or 4 per level to start with. Don't forget to update the HelpScreen too. Play around and change the durations or strengths or abundance of potions. Try adding some new ones that change the vision radius, heal over time, stop regeneration, consume extra food, or fill someone's stomach. I'm sure you can think of even more potions and effects. There you go; potions and effects that are simple and flexible. We're going to add a few more effects in the next tutorial when we add magic.

Wouldn't it be cool if throwing a potion at a creature caused the effect to apply to it? Easy-peasy.

Then make sure the throw method removes the item if it has a quaffEffect and the target was a creature, otherwise it should add to the world like it already does. Now you can sit back and chuck poison bottles at goblins.

After adding goblins to the addCreatures method of the PlayScreen you should be able to play and fight some rather tough goblins with armor and weapons of their own. Don't forget to tweak each creatures hp, attack, defense, the food values of corpses, and the xp gained or how much xp is needed for each level. You should also change the number of items and creatures per level. I prefer few items on the ground. That way the player almost has to confront goblins to get better loot.

So our goblins can use melee weapons and armor — that's nice — but they will run over and beat you with a bow instead of fire them. How about if they could throw things or fire from a distance? Time to work on the GoblinAi. My goblins will, in order of priority, try to: ranged attack, throw attack, melee attack, pickup stuff, and wander if they can't do anything else. Let's get to it.

It's a good idea to take these helper methods, and the hunt method, and move them up to the CreatureAi class. You can use the Pull Up refactoring in Eclipse. That way they can be used by any future creatures we add.

After adding intelligent goblins things should be much more difficult. Play test many times and tweak all the values and behavior you can.

Goblins should also see if they are holding better weapon or armor and switch to it if they are.

And now you have goblins that will chase you when they can, attack from afar when they can, and switch to better equipment they find. That's a monster that's more intelligent than many rogulike denizens. You can make them even more intellegent by having them remember where the player is. If they can't see the player anymore then they go to that location. This way they won't lose interest in you just because you step out of view for one turn.

These goblins are tough — sometimes too tough. It would be easier if we could regenerate some health. Add this to the creature class:

Set the regenHpPer1000 to something reasonable in the constructor. I use 10. You could also use constructor injection or call modifyRegenHpPer1000 in our factory to make some monsters regenerate very quickly.

Then create a new method to regenerateHealth and call it as part of the update method.

We can set the default to 1 in the constructor and update the StuffFactory to give a value to things that are good for throwing like certain weapons or rocks. Don't forget to update the item class's details method.

Now let's add a couple methods to the Creature class. One throws an item to a location and one damages any creature there.

The throwing screen will be interesting because it's the first time we have a double screen scenario. We need a subclass of InventoryBasedScreen to select what we want to throw and then a subclass of a TargetBasedScreen to pick what to throw it at.

The ThrowAtScreen is simple and self explanatory. We can throw at anything we can see that isn't blocked by walls.

Anything that has a non zero rangedAttackValue is a ranged weapon. This way a weapon can have separate attack values for melee, thrown, and ranged combat. We'll keep it simple and say that ranged weapons can hit anything we can see that isn't blocked by terrain.

Add new ranged weapons to the StuffFactory. Bows are good at ranged combat but not very good at hitting things up close.

Creatures sometimes use up an item and it no longer exists. Other times they no longer have the item but it still exists in the world. Either way, we need to make sure they no longer have it equipped and that they no longer have it in their inventory. One way to do this is to create two helper methods and call these when possible.

This particular implementation has the hidden side effect that the message that is passed in must end in a damage indicator since the commonAttack method will add that. It's not good to do things like this too often, but sometimes that happens.

That's sufficient but kind of lame. I'm sure you could come up with a better story and maybe say something about what all the symbols are. Don't forget to add this new screen to the respondToUserInput method in the PlayScreen class.

Now lets make a screen that tells us details about what's in our inventory. I'll call it the ExamineScreen and map it to the x key in the PlayScreen.

You could also display some extra description that gets passed into the item constructor.

Let's start our screen to let us look around. We'll let the user pick a tile and then tell them what it is. If you think about it, this isn't the only time the user will pick a tile through. Throwing, firing bows, and aiming spells all involve picking a tile. Since the InventoryBasedScreen has payed off so well, I think we should create a TargetBasedScreen. Let's get to it.

We'll keep track of the player, a caption representing what we're targeting, the screen coordinates where the player is looking from, and the s and y offset of where we're targeting. The player and caption are protected so our subclasses can use them. Don't worry, it will make sense.

When it's time to display the output, we need to draw a line from the player to the target. I chose a line of magenta *s, but that's up to you. We also need to display the caption to the user.

The user can change what's being targeted with the movement keys, select a target with Enter, or cancel with Escape. If the user tries to target something it can't, like firing out of range, then we go back to where we were targeting before.

This will display details to the user about whatever they are targeting. If you use this code then you'll need to create a few methods to get details about creatures and tiles. Don't forget to map it to the ';' key, or whatever key you want, in the PlayScreen.

You may have noticed a problem with the LookScreen in that you can get details about things the player can't see. Let's fix it by making some small changes to the Creature class. Basically, only return what the creature can see or remember.

Now we've got a help screen, a way to see details about what's in our inventory, and our surroundings. Nothing very glamorous or game changing this time but it's all very helpful for the user. The TargetBasedScreen should also make future screens easier.

Tuesday, October 4, 2011

It's great that we've got some caves, equipment, and monsters but what about character development? Levels, feats, attributes, classes, and skill trees can be a complex subject worth studying but, and maybe you saw this coming, we'll do something simple to start with. For now, when a creature is killed, it's killer gains xp, when enough xp is gained, a new level is gained and some benefit is chosen. One thing I'd like to have is other creatures can gain levels too. Why? Just because I haven't seen it done before (at least not that I've noticed). It also means that positioning weak monsters between you and the big bad guy may just make the big bad guy gain levels. Maybe you should start rethinking the use of meat shields....

Our creatures need xp, a level, and a way to gain xp and levels. When the xp passes the next level threshold, the level should be incremented, the ai should get notified, and the creature should heal a bit.

The starting level is initialized to 1 in the constructor. I'm using a formula to determine how much experience is needed for the next level but you can use a lookup table or some other formula. Many interesting things have been said about leveling and power curves so read up, try different things, and do what works for you.

We need to update the attack method to grant experience when a creature is killed. Add the following to the end of the attack method:

if (other.hp < 1)
gainXp(other);

Now we can grant experience based on some experience value the creature has, or on it's level, or on the killers level, or by some combination. I'm using a simple formula for now.

This ensures that tougher creatures are worth more and by subtracting the killer's level, easy creatures will soon be worth nothing. It's not perfect but it's simple to explain, understand, and code.

If you play it now (after creating an empty onGainLevel in CreatureAi) you should see notices about gaining levels. That's a good sign.

For this simple roguelike, when something gains a level it get's some stat bonus; increased hp, increased attack, etc. The player will be shown a list to chose from but other creatures will get one at random.

Let's create a class to represent a level up option's name and actual effect.

We need something to track all the possible options and enforce some of our level-up logic. We'll call it a LevelUpController — even though classes with Manager or Controller in the name are usually vague and messy and not the best way to do things.

I created a few simple options based on the stats we already have but I'm sure you can come up with more. These are anonymous classes - if you're not familiar with them you should check them out. Anonymous classes can make some things very clear and succinct - other things are best left to regular classes.

This LevelUpController should be able to select one option at random and apply it to a given creature.

If you try it now you should see that when you gain a level you look tougher or stronger etc. You may even notice something else looking stronger or more aware. That's why I think it's so cool to have a method like doAction; you can, if you're lucky, see the rare and subtle events like these.

Try it.

What about when the player gains a level? Shouldn't we show a list of options for the user to choose from? Let's start by making sure the player doesn't automatically get free bonuses.

Override the onGainLevel method in the PlayerAi class.

public void onGainLevel(){
}

Now we update the PlayScreen's respondToUserInput method. When we first enter the method, before the user does anything, we need to record the player's level.

int level = player.level();

After responding to the player's input, we need to see if that resulted in a level up. If so, we jump into a LevelUpScreen and tell it how many bonuses the player get's to pick.

And there you go; a simple leveling system that lets the player decide how they want to progress their character. You could add different bonuses like special moves, critical hits, extra xp per kill, or special abilities. You could even make it so the player could chose a new item after leveling up.