Saturday, November 28, 2009

Review: Triangle Wizard

Since this is Thanksgiving weekend, I didn't have to program. At the recommendation of someone in a comment thread, I decided to check out Triangle Wizard. Here's my mini-review:

Name: Triangle Wizard
Type: Roguelike, real time, modified
Website: http://www.trianglewizard.webs.com/

I had never heard of this game before yesterday. It's a freeware real-time roguelike, which only runs under Windows. It came with an installer and installed/ran with no issues.

The title screen reminded me of Diablo, it was well polished. One this it could use would be mouse support, it took me 15 seconds to figure out what was going on. I selected tutorial since I knew nothing so far.

The tutorial is one of those "learn as you do" training rooms. I had some trouble figuring out which icon was your mouse cursor and which was the player. Once I passed that, I figured out that it was a hybrid mouse and keyboard game. The keyboard moves the character and selects spells. The mouse handles targeting and casting. I love this control scheme. It makes "run-and-gun" strafing easy and smooth. If magecrawl was going to be real-time, I would seriously steal it. Another feature that I love is the "persistent casting". You can set it, and any enchantments you have cast will recast when they expire. The tutorial had a few bugs, which I sent to the maintainer, but it effectively taught me the basics.

The character selection screen was a bit confusing. The "right arrow" seemed to randomize selected items. It took me a few minutes to figure out how to set my name. Once I figured it out, I selected a human pyromancer.


Within ten seconds of starting, I was swarmed by half a dozen brigands. After fending them off, I got a chance to explore. There seemed to be a huge number of spells you could buy early, maybe too many. It was a bit overwhelming. Beyond that, I explored awhile until I ran into a "summoned phoenix". It was immune to my fire spells, and killed me.

I'm obviously not very good at the game, since I've played a few times and keep getting killed on the opening level. However, it has peaked my interest, and I'll try it some more. If you have a Windows machine, it worth a try.

Tuesday, November 24, 2009

More Map Madness

So, I don't want to call the map generator "done" yet, but it's good enough for me to move on I think. It now handles all the cases I think are important enough for my first pass. Here's a picture of a map (with FOV turned off) to give you an idea.





As I mentioned before, I've nicknamed this map generator "Stitches". I took some inspiration from torchlight when I came up with the idea. Since it reads "chunks" from a file, if I keep adding more and unique chunks, better quality maps should result. For example here is one of the room chunks:

7 7 MainRoom
###^###
#.....#
#.M#M.#
^.###.^
#.M#M.#
#.....#
###^###

The '^'s are where the map generator can connect up other segments, '#'s are walls, and 'M' are monsters.

Now that both generators are "good enough", I can concentrate on my next tasks. I have two iterations planned before my text "tech demo" release.

Iteration 6 (Current)
  • Map Generator Work
  • Multiple levels, with stairs connecting
  • Help Screen
Iterator 7 (Combat)
  • Wands
  • Multiple monster types (more on this in another post)
  • More spell effects
  • Color!


Monday, November 23, 2009

Design Goals of Magecrawl

Introduction

While magecrawl is still in major development and there are major areas of decisions that haven't been made, I have a few overarching design goals and principles that I'd like to stick to.

Roguelike

While to qualify what is exactly a roguelike is a difficult question, magecrawl should fit squarely into the category. I'm aiming for things such as productively generated content, permadeath (see below on instakills), and very much the "ascii feel".

Libtcod (via libtocd-net) provides a great way to give a game an ascii feel while still be reasonable to program and look good. Productively generating conent is what keeps the game worth playing again after winning. I hope to add some sort of optional content for those who "assention" is not enough.

No obscure knowledge needed

Games such as Nethack all but require a large base of obscure knowledge to win. While some knowledge between games should transfer over, that's the primary way one can get better at games, sometimes the amount needed to win goes overboard. Reading a gold detection scroll while confused, polymorphing into a cocktrice to use their eggs as weapons, and the entire identification game in Nethack are prime examples.

Instakills are not fun

In games with permadeath, walking down the stairs and dying is not fun. The skill in playing a game should be primary in getting out of sticky situations, not playing the game a few hundred times to memorize all the things not to do. Read "Fake Difficulty" for more on this.

The tricky part with this goal is not making the game easy, or trivial. I want some areas to be fiendishly difficult, and I don't mind killing the player when they do stupid things. Running should sometimes be the best option, as running into Sigmund in Crawl can be.

Arcane theme

As the name suggests, magecrawl has something to do with magic. Every character will have some sort of magical ability. This does not mean all you can play is squishy robe wearing glass cannons. Based upon the (skills/class?) you choose, wading into melee, calling down fire from heaven, or sending others to do your dirty work should all be options.

One nice things about sticking to the theme is that it allows for better fluff and some ideas that wouldn't be possible otherwise. In a future essay, I'll talk about my plans for economy which have magic as its linchpin.

Conclusion

While I hope that I'll come up with many other great ideas and features in the months (and years?) ahead, these are the foundational ideas I'll try to build upon.

Sunday, November 22, 2009

On Tools

In programming magecrawl, I've grown to have a list of preferred tools, and since i have a few moments before bed, I figured I'd list.

Mercurial - Distributed version control is awesome, even when it's just you working on a project. Mercurial is great because unlike git, it doesn't run like a dog on windows. The windows integration is nice as well. I wish the visual studio support was a bit farther along, but overall a great version control system. If you're coding, and not using version control, you should be.

Visual Studio - By far the nicest environment to edit c#. Intellisence always works, unlike in c++ visual studio. Monodevelop is a good standby, and the best on non-windows platforms.

Vim - For all the text editing that isn't code. If you're a vim user, learn macros. They will become your new best friend. For those who don't have the patience to learn an editor with just a high learning curve, I heard notepad++ is a good outside Visual Studio editor.

Map Generator, and the need to do other things

So the last 2-3 weeks, I've been working on map generators for magecrawl. Here's a few examples:


This is my "Stitch" map generator. It generates a graph of entrances, halls, and rooms, then reads "chunks" from a file and stitches them togeather to make a map. Right now, it looks pretty boring since there is only one room type and 4 hallway types. While there are some issues, I'm pretty proud with it.


 

This is the 'cave' map generator. It implements this algorithm for generating caves with some tweaks. It seems to give more consistent maps than my stitch generator.

The only issue I'm having is that staring at map generators during all my free time gets a bit boring. Last week I implemented a few 'nice' features that were suggested from those who played with the magecrawl tech demo gruop. This week I worked on cleaning up the code, using my point struct instead of int x, int y where reasonable and LINQing up the code where it makes sense.

LINQ is awesome

So, after some prodding at work, I learned enough LINQ to be dangerous. Boy, it makes some code shorter and easier to read.

From:
public bool Operate(Character characterOperating, Point pointToOperateAt)
{
bool didAnything = false;

foreach (MapObject obj in m_map.MapObjects)
{
OperableMapObject operateObj = obj as OperableMapObject;
if (operateObj != null && operateObj.Position == pointToOperateAt)
{
operateObj.Operate();
m_timingEngine.ActorDidAction(characterOperating);
didAnything = true;
}
}

return didAnything;
}


To:
public bool Operate(Character characterOperating, Point pointToOperateAt)
{
    OperableMapObject operateObj = m_map.MapObjects.OfType<OperableMapObject>().
SingleOrDefault(x => x.Position == pointToOperateAt);
    if (operateObj != null)
    {
        operateObj.Operate();
        m_timingEngine.ActorDidAction(characterOperating);
        return true;
    }
    return false;
}

It doesn't seem like a lot, but multiple it a few dozen times and you get some serious space savings. It also helped me realize that the previous code was allowing for multiple map objects in a given square, which violates one of my map invariants.

Thursday, November 19, 2009

Plugging Away...

The thing about personal projects is that you generally work on them on your off-time, after 8+ hours of coding and such at work. Sometimes, even if you really enjoy the topic your working on, your too mentally exhausted to come home and code. Sometimes, cooking dinner, a walk with the wife, or any other normal activity comes along and uses the time you planned on coding today. Sometime, when you stare at the list of things your project needs, it can be overwhelming.

The thing about magecrawl is that I've restarted it one too many times. I think I'm on number 8 if you get technical. I'll get so far, get to a hard part, look at my code, and want to start over. Now some of those restarts taught me important lessons: why using a managed language makes things easier, why you should separate the game engine logic from the gui, etc. However, at this point, restarting would be a waste. I don't have any of those project breaking issues.

So the strategy I have for not getting burned out and wanting to quit? Plug away a little bit each day. Yesterday I fixed some issues with the map generator, today I'll write a help screen, maybe next week I'll work on getting more than one type of monster. It doesn't matter if I work 20 minutes, and then go play torchlight, at least I accomplished something.

Now that I've written this out, I feel like it's a poor clone of Fire And Motion from Joel.

Wednesday, November 18, 2009

Shallow copying a stack

I needed to shallow copy a data structure that contained a few stacks in c#. Without thinking i did the following:

public Foo(Foo p)
{
Stack = new Stack(p.Stack);
}

However, this doesn't do what you'd expect. The stack is converted into an enumerable, and then read into the new stack. However, it's backwards. There is no "copy" constructor for stacks.

Here was my easy solution:

public Foo(Foop)
{
// There is no Stack constructor that take a stack, just the enumerable one
// Since we want a shallow copy, we'll just reverse the list and use that
Stack = new Stack(p.Stack.Reverse());
}

Since LINQ has a reverse method, we just get the enumerable and reverse it. Then the stack will be created with the same ordering.

Hello World

In the beginning, the programmer wrote "Hello World". And he saw that it was good. Then then the programmer wanted to tell others about it, so he found a humorous title and started a blog. And thus, IfErrorThrowNewBrick was born.

It's here that I hope to write on my experiences on programming in general, and specifically on my work on my pet roguelike game, magecrawl. I've been programming in c# for about about a year a a half at least, mostly at home but now at work as well. It's now my favorite language to write in, with the exception of using python to hack out rough tools.

Well that's enough of an introduction.