Sunday, November 7, 2010

Learning OpenGL, slowly...

So I've burned a few hours trying to learn OpenGL. I'm using C#, accessing OpenGL via OpenTK. The tutorials here are great, but a bit out of date. After much frustrations, I found that ramblingcoder picked them up and converted them to C#.

Wednesday, November 3, 2010

Frustrations on programming languages

So, I'm honestly a bit demotivated to work on Magecrawl. Part of it is that I'm in the middle of porting it to Silverlight as a way to get a tiles version with little work that will work on Windows/Mac/Linux. Then this week, I come across these articles.

While it isn't like they are canceling Silveight, their "change in focus" and the fact that Mono is currently two major versions behind has me a bit worried. I don't want to sink another 20+ hours fixing things up, and then in a year or two have to move to another UI layer. I also don't want to loose being able to work on it on my Mac, and right now I'm in that boat.

More fundamentally, I'm frustrated that there doesn't seem to be a "good" way to do cross platform UIs for my game. I'm going to rattle though the programming languages I know or are good options. None of them right now seem to be a good fit.

C# - Silverlight: Only Mac/Windows right now. Linux is an unknown period of time away. A bit worried about its future, but probably best option right now.

C# - libtcod: Works everywhere, but no tiles UI.

C# - winforms - Yeah, it might technically work on Mac/Linux, but there are licensing concerns that make ppl not want to install it.

C# - GTK# - Doesn't look native on ANY platform except Gnome.

C/C++ - Any number of frameworks here, QT being the most obvious framework or OpenGL. Ignoring the rewrite aspect, I'd rather not chase memory errors in an unmanaged language when I'm not being paid for it.

python - pygame would be the most logical choice. I don't think I want to write in a dynamically typed language.

objective C - See C/C++ for the unmanaged language type. It also wouldn't work well on Windows/Linux, and I have no clue what GUI framework to use. 

Java - Seriously? Swing looks terrible anywhere, and with Sun Oracle trying its best to kill developer uptake, that isn't an option.

In writing this article, I've come across opentk, which appears to be a open gl binding for C#. While I'd have to learn yet another UI framework, at least I know it'd work everywhere...

Sunday, October 31, 2010

Status Update - Not dead yet...

As one might have noticed, my postings the last few weeks have been few and far between. There are a few contributing factors to this decline:
  • Large amounts of software testing reduce my motivation to come home and work on Magecrawl
  • Work on a website for my wife's business. {shamelessPlug} Music therapy in Austin, Round Rock, Georgetown {/shamelessPlug}. This involved learning pretty quickly CSS/HTML and Joomla as a CMS.
  • Starcraft II - I gave in and got it. It is video games goodness distilled into a drug like potency. I am currently playing against Gold level players on 1v1, and I have a pretty mean 4gate rush. 
 I still haven't given up on Magecrawl. With the testing at work ending and the website up and running, things should be calmer over here. The only hurdle to working on Magecrawl will be not playing SC II...

Tuesday, October 19, 2010

[Offtopic] Pain in PDF printing on my mac, workaround...

So, since I spent three hours of my life on this, I figured a post on the internets for other to find was worth writing.

My goal was simple. My wife had created a document in pages and wanted it professionally printed. First attempt was a simple "save as pdf". That failed, as there were tiny inconsistencies when viewed on a PC. I installed adobe reader on my mac and low and behold, they showed up there. I thought PDFs were supposed to look the same everywhere...

Some google research pointed to PDF X-3, which iWorks claims to be able to export. It is apparently a subset of PDF that everyone agrees on. Yes, let that last sentence sink in. PDF, the format that is supposed to look the same everywhere, now has a sub-format to do that job. Eitherway, attempts to export the document fail with a generic "can not create PDF-X3" error. Apparently this is a long standing bug with iWorks where some complicated documents throw that error. No fix, no work around. This is starting to sound like bloody Linux...

Alright, next approach is using the "ColorSync Utility" to create a filter. People online seem to saying this sometimes works. After launching the beast, I find out that it apparently fails to save resolution settings at all. This means when I filter wife's document through it, it comes out looking like 1990 smacked it upside the head, low resolution and all...

The solution I have come up with is the 500 lb  (226 kg for my metric friends) sledgehammer of a solution.

  1. Open iWorks. Save document as PDF that won't work in adobe.
  2. Open PDF in preview, File->Save As.
  3. Selection JPG, change quality to full and DPI to 500.
  4. Send that 15 meg JPG to the printer...

Thursday, October 7, 2010

crawl-tiles announcned, a "public domain" source of graphical tiles

My work on getting the crawl tiles public domain is complete. Here is the "press release" that I posted to R.G.R.D:

I am happy to announce the first release of the crawl-tiles project
(http://code.google.com/p/crawl-tiles/).


Crawl Stone Soup (http://crawl.develz.org/wordpress/) has a beautiful
set of graphical tiles based on rltiles (http://rltiles.sourceforge.net/) with many extensions and modifications.

Until now, they were under the "Crawl license", derived from the
Nethack license and thus unusable by most projects.


A majority of the developers/artists have signed off their work into
the public domain (CC Zero license technically), and thus their work
is now redistributable and usable by other projects.


I have packaged that work up into a form easily consumable by other
projects, and placed it on the crawl-tiles download page.


Feel free to take a look, use them in your new project. If you do so,
please consider noting in your game where they came from.

Thursday, September 30, 2010

Chugging along on Magecrawl for SL...

Quick update:

I'm still chugging along on Magecrawl for Silverlight. I just finished ranged targetting with overlays, which makes melee/ranged attacks, inventory/spell use, and operate doors work.

I have a bunch of "easy" dialog work to do, a splash screen to make, animations for ranged attacks, etc. I also have the harder work of a skill tree, preferences, and such.

Tuesday, September 28, 2010

Back to work - FF XIV currently a bust...

As some of my previous posts mentioned, I was blasted excited about Final Fantasy XIV and planned a month or two of ignoring Magecrawl around it. The short answer is that isn't happening anymore. The game has major balance and lag issues that currently make it not fun to play. If you were interested in it, I'd give it a few months to see if they can shake out the bugs and make it fun to play.

And so, I'm back to normal development again. My plan is as follows:

  • Finish up my crawl tiles license project, which just involves a boring night or two in front of changelists.
  • Get Magecrawl for SL up and running. My previous post had my TODO list.
  • Start work on the backlog of bugs/features. Right now, for each one that involves UI changes, I'm planning on doing it twice if reasonable.

Monday, September 20, 2010

Magecrawl Status Update

I'm making good progress. I finished up the inventory dialogs tonight, and got started on targetting. Here is is my todo list as of tonight:

Other:
Health/Mana Bars
Status Effect/Monster list on character info
Handle player death
Icons in inventory
Hitting z to cast spell, z should target

Dialogs:
Splash Screen
Help

Hard:
Equipment
Skill Tree
Way to edit preferences
Reasignable keystrokes

Message Box:
Up/Down Stairs
Save
Quit
Welcome Message

Requires Targetting:
Operate
Draw ranged attack
Attack Melee/Ranged
Inventory w\ targetting


Obviously rewriting the skill tree viewer will take the most work, but most of the rest of them will fall into place quickly. Four them require targetting, which I'm currently working on, while 6 require dialog to be written (easy). 4-6 of them don't have to be done for the game to be playable, just nice to haves.

Sunday, September 19, 2010

[Silverlight] ChildWindow focus bugs, oh my!

Another day of programming, another bug in silverlight to work around. When I'm not working around bugs, I'm crazy productive however.

The issue today is key focus, in particular with ChildWindow. This class allows you to place modal dialogs up with a minimal of fuss. The problem is that for some reason they weren't getting keyboard focus correctly. This is a big problem when you want your entire game to be able to be run from the keyboard alone.

Here is my solution (with help from a friend):
public ChildWindowNoFade ParentWindow;

        public ChildWindowNoFade()
        {
            this.DefaultStyleKey = typeof(ChildWindowNoFade);
            this.Loaded += new RoutedEventHandler(ChildWindowNoFade_Loaded);
            this.Closing += new EventHandler<System.ComponentModel.CancelEventArgs>(ChildWindowNoFade_Closing);
        }

        void ChildWindowNoFade_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Dispatcher.BeginInvoke(() =>
            {
                if (ParentWindow != null)
                {
                    ParentWindow.Focus();
                    if (ParentWindow.InitialFocusItem != null)
                        ParentWindow.InitialFocusItem.Focus();
                }
            });
        }

        void ChildWindowNoFade_Loaded(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke(() => 
            {
                Focus();
                if (InitialFocusItem != null)
                    InitialFocusItem.Focus();
            });
        }

        protected abstract Control InitialFocusItem
        {
            get;
        }

Roughly, I'm creating a base class that hooks into loading and closing of windows. It fixes up the focus problems in cases of stacked modal dialog (where ParentWindow is non-null).

A few other notes:
  • Some child windows act funny with keyboard focus if they don't have controls in them and/or they don't have IsTabStop="True" TabIndex="1" set on the window
  • System.Windows.Browser.HtmlPage.Plugin.Focus();    If you call this guy on the creation of your root object will give your application focus.

Saturday, September 18, 2010

[Silverlight] Binding to list box elements throwing MethodAccessException

I spent an hour or two figuring this out, so I figured I'd post about it. Hopefully, the next poor soul who runs into it will find it here:

I was running into a problem binding my list to a Silverlight list box. On listbox creation, the output window had lots of lines that looked like this:


System.Windows.Data Error: Cannot get 'DisplayName' value (type 'System.String') from 'Magecrawl.Items.Consumable' (type 'Magecrawl.Items.Consumable'). BindingExpression: Path='DisplayName' DataItem='Magecrawl.Items.Consumable' (HashCode=45492604); target element is 'System.Windows.Controls.TextBlock' (Name=''); target property is 'Text' (type 'System.String').. System.MethodAccessException: Attempt by method 'System.Windows.CLRPropertyListener.get_Value()' to access method 'Magecrawl.Items.Consumable.get_DisplayName()' failed.
   at System.RuntimeMethodHandle.PerformSecurityCheck(Object obj, RuntimeMethodHandleInternal method, RuntimeType parent, UInt32 invocationFlags)
   at System.RuntimeMethodHandle.PerformSecurityCheck(Object obj, IRuntimeMethodInfo method, RuntimeType parent, UInt32 invocationFlags)

The answer is that under Silverlight, you can not bind to non-public objects. The Consumable objects noted above was a internal object with a public interface. Once I made it public, the problem went away.

A side note, this apparently also occurs if you bind to an anonymous type as well.

Tuesday, September 14, 2010

Why getting your licensing straight is important

So, you might have noticing my posting frequency has decreased the last few weeks. A few things factors have contributed:
  • Deadlines at work give me less time/energy to code for fun
  • Final Fantasy XIV is in open beta
  • Side projects
One of those side projects is what I want to talk about. As you might have noticed, the Silverlight prototypes uses the wonderful graphics from Crawl. Those graphics were based on rltiles and expanded upon by many great artists.

However, no explicit license grant was required of those submissions, and such they are by default under Crawl's license. It is derived from Nethack's license, and is incompatible with pretty much everything. I got around this in the short term by duel licensing magecrawl under BSD/Crawl, but this is not something I'd like to continue forever.

In talking to the development team, I offered to attempt to contact the 20-30 people who have made changes and ask for them to relicense their work. They were interested in getting away from the crawl license, and so they agreed. The license that I suggested and we settled on was this one, which is pretty much a cute way to say "public domain".

The e-mails are still going out to try to get a hold of everyone. This work is going to suck up at least a week or two of my programming nights when it all finished. In addition to that, if I can't get a hold of some people, those tiles will either have to be redone or separated from the "public domain" tiles.

If the number of people that touched the tiles was higher, in the hundreds or thousands, it would be impossible to get everyone to sign off. The impossibility to relicense the Linux kernel is a great example of a project that is in that boat. It is somewhat different, because they are happy with the gpl v2.

This is why getting your license straightened out early is important. Here is a 30 second, I am not a lawyer so don't pretend I am one (not even on TV), summery of licensing.
  • "Public Domain" - Technically not a license, the idea is to give up all rights to the code. This CC license or the WTFPL licenses are in this class.
  • "BSD" - This is the next step in being restrictive, but just barely. The license only requires that you keep the copyright notations on the source code. The MIT license is also very similar.
  • "GPL" - A very common license, with the idea that the source code should stay "open/free". Roughly, any code linked to GPL code must be GPL, and you must offer to distribute any changes that you make to anyone you give copies of your program. It places more restrictions on you as a programmer (other licensing may not be GPL compatible and hence a GPL program can not link against them), and also places restrictions on anyone who distributes your program. However, it prevents anyone from using your source code without opening their changes.
  • "CC" - Many of these licensing don't apply very well to things like text and artwork. The creative commons licensees many times are good fits, with many different flavors.
  • Proprietary - The source code is not open for view/edit. Uncommon but not unheard of in roguelikes. Can not link against GPL code, but can use BSD/Public Domain code.

Tuesday, September 7, 2010

Silverlight fun and arcane "batteries"


While the open beta of Final Fantasy 14 has taken more programming time away that I'd like to admit, I haven't dropped off the face of the planet yet. I've made good progress so far on the new "tiles" GUI, using silverlight. See this video for a quick video of gameplay. There is a huge number of things needed to make it fully functional, ranging from picking up items to the skill tree.

Assuming I was able to make the tiles interface work on Windows/Mac/Linux, both in the web browser and in a stand alone application, I've been toying around with the idea of ditching the ascii interface. I personally enjoy playing the tiles version of crawl more than the ascii version, and I feel I could make either two decent front ends or one awesome one. There is a lot of "if"s still in the air, but would doing that enrage anybody out there? While in the end I'm programming this game for personal pleasure, I do care about the opinions of the players of my game.

Another idea floating around my head is redesigning the magic system in Magecrawl. Right now, it is a fantasy standard MP system, with the MP being generally recharged after every fight. This makes fights "front heavy" with the characters dumping most of their MP early on, and resorting to melee afterwards. Also, it generally devolves into spamming the most powerful attack spell over and over. When I think about arcane duels, this isn't how I imagine things. I imagine almost every round until exhaustion some spell being cast, whether it is a earth-shaking powerful effect or a simple cantrip.

It is hard to make such a wide spread of spell types and tempos effective in the current system. My idea is a take on recharge magic, with a twist. Each spell has a total amount of "energy" that is needed to cast it. The player has a "battery" of mana, which at the end of each turn (that isn't spent moving?) some is syphoned off to fill each skill not ready to cast.

With a property selection of spells, one could alternate between two relatively fast recharging spells, or cast a range of spells (damage, push back, damage, blink away). Long term effects could reduce either the total "battery" before spells start running dry or the rate that spells recharge. Playing arcane characters should be about casting spells and making things blow up :)

Tuesday, August 31, 2010

I can has magecrawl on the internets?


So it might not look like much, but that's magecrawl running in a web browser! Levels generated, items created, monsters waiting for time to start ticking. The only thing missing is drawing and control.

My good friend Ben inspired the idea and helped implement some the magic.

Roughly the magic entails removing all references to libtcod from the game engine. That way, we can load all that code inside a web browser via silverlight, (which can't load native code). I "ported" this code from libtcod:
  • Shadowcasting Line of Sight
  • A* Pathfinding
  • Bresenham Line Generation
"Porting" could be described as the twisted application of force needed to move C code to compile and run in C#. Since none of them used pointer math too heavily, it was reasonable to attempt. The code looks ugly for C# code, but it works.

In theory, it should even save and load! I can use my same serialization code, just point it to "isolated storage" and away we go.

Obviously, a lot of work is needed to make it a real game frontend. But the fact that I could even get this far (and not have to rewrite everything in flash) is pretty awesome.

Saturday, August 28, 2010

A simple way to reduce memory usage of structs/enums in Dictionaries

I can't take credit for this tip, it was pointed out here.

As pointed out here, by default if you use a struct or an enum inside a dictionary, you will alloc objects every time you access the dictionary to box/unbox things. For example this will allocate both a Point an object to box it in:

var squareLookup = new Dictionary<Point, SkillSquare>()
squareLookup[new Point(0,0)] = null;

I ran into issues because I used something like this for drawing the skill tree, and when you scrolled we hit the dictionary a huge number of time.

The linked hint suggests doing something like:
public class PointEqualityComparer : IEqualityComparer<Point>
    {
        public static PointEqualityComparer Instance = new PointEqualityComparer();

        public bool Equals(Point x, Point y)
        {
            return x == y;
        }

        public int GetHashCode(Point obj)
        {
            return obj.GetHashCode();
        }
    }

var squareLookup = new Dictionary<Point, SkillSquare>
    (PointEqualityComparer.Instance)
squareLookup[new Point(0,0)] = null; 

With this simple change, a profiled run of scrolled went from over 70% of all allocated memory being Points to so few it wasn't even broken out as an entry. This increased performance by a huge amount.

Friday, August 27, 2010

Testing - Baby Steps

I just committed the first nunit tests for magecrawl this morning. Automatic testing has been on my "nice to have, but not now" list for multiple releases. The reason in short is that writing tests isn't fun, which in some regards is a stupid reason, and in others is understandable (this project is my hobby, not my second job).

My first step into testing was 11 tests, testing the generators (Item, Monster, Map). They simply just poke each generator public API thousands of times, looking for a hang or crash. During development, I ran into a significant number of issues related to this, so this was a "low hanging fruit".

In the future, I'm planning on writing more tests, testing the game engine itself and more of the external libraries. However, I'm currently demotivated enough that I want/need to work on other more interesting things.

Tuesday, August 24, 2010

Modularization - The joys

Modularization, the process of breaking a monolithic software component into multiple separate components. To be honest, it isn't very much fun. For a year or so, I did a lot of it at work, enough so that my wife recognizes the word and knows it isn't very much fun. This is what I did all weekend.

The first question is why I would spend a significant portion of the weekend doing something I admit isn't fun as part of my "hobby". The truth is that in most hobbies there are parts that one does not enjoy. Runners don't always enjoy getting up early to run, some parts of video games are called "grinds", and practicing a skill or instrument isn't often fun.

Magecrawl during development had a few modular boundaries established early on, between the GameEngine and the UI, that has been honored. However, the "GameEngine" component has grown to include much of the games logic, enough that I felt for testability (more on that in further posts) and understandability, things had to be broken up.

Here is a picture of what I currently have:



A bit of explanation, everything that isn't MageCrawl.exe, GameUI, Interfaces, and Utilities used to be in GameEngine. Here's a rough idea of what everything does:

  • Utilities - Low level stuff, like the Point class, Preferences, and helper classes for saving and finding types at run time.
  • Interfaces - These are interfaces that the GameEngine as a whole provide that allow the GameUI and controls to query information about the current game state. Things like IPlayer, IMap, IGameEngine, etc.
  • GameUI - This is what draws the map, menus, etc.
  • MageCrawl - This is the game engine proper. It has an implicit dependency of GameEngine via MEF. It kicks everything off and runs the main game loop.
  • EngineInterfaces - This is a set of internal interfaces the game engine components use to talk about objects everyone needs to know about. For example IGameEngineCore describes the calls to the GameEngine the various modules can use to implement their behavior. For example, those interfaces might expose how to add a status effect to a creature, but to do that you need to know what a status effect is. But status effects live "above" this module, so we create an interfaces that we can expose at this low level, IStatusEffectCore (IStatusEffect is in Interfaces for the GUI).
  • Items - This guy technically existed last release. It was the newest written code, hence being formed as a separate module. This guy handles creating items and exposing their behavior via Attributes.
  • StatusEffect - This guy handles short and long term status effects, things like poison, haste, and the like. It acts by using the exposed interfaces in IGameEngineCore and attributes.
  • Actors - Technically, this module contains monsters (and their AI), along with the Character base class. Characters can wield equipment (Melee for all monsters right now though) and have StatusEffects upon them.  Player lives in GameEngine since it has a lot of other stuff (Spells, Skills, etc).
  • Maps - This was the guy I wanted to pull out. It exposes the map data structures, and the multiple ways to generate maps. Maps place monsters onto them self, and can contain items on the ground.
  • GameEngine - This is where everything else lives. It handles physics (who can move where, etc), combat (resolve attacks), magic (what does the spell do), and the like. 
This is a rough outline of MageCrawl's internal structure. I'll talk about it more in future posts.

Saturday, August 21, 2010

libtcod 1.5.1b1 released!

As many may know, Magecrawl uses libtcod (via libtcod-net) for both graphics and engine support (FOV, LOS, etc). Months ago, I created a SWIG'ed version of libtcod-net, so that I could stop supporting a hand-rolled wrapper. A (beta) release featuring that has now come out.

If you use libtcod via c#, I highly recommend upgrading to the new wrapper, as the old one is deprecated and no new work will be done on it. Also, the new version has OSX versions for both C# and native C/C++ developers.

Get the hotness here.

Thursday, August 19, 2010

Iteration 10 - The long road to slices (want to get out and help push)?

So I've spent this week doing "research" on what next lies in store for Magecrawl.

The first thing I've realized is I now have a good "family tree" for Magecrawl. While Magecrawl isn't developed enough for Crawl to consider it a legitimize offspring, it provides much of the inspiration and root ideas. Things like tactical gameplay, high difficulty, removal of any "grinding" gameplay, and a crazy good auto-explore are all things I aspire to have. Borderlands takes the role of the crazy uncle that rubs of a little bit. It provides such a varied equipment set that playing the game a second (and third) playthrough is fun and interesting. Diablo can be considered one of the grandfather figures. It to me was one of the great dungeon delve games of my youth.

My serious hope is that is the last "iteration" in the series to build up a game engine. Tasks I want to finish to put me in a great place include:
  • 55 open issues in my bug database, mostly minor and a few major features. Some major ones include:
    • Better monster AI using sounds or smell
    • Status effects from various schools
    • Better use of spell effect areas to differentiate the schools
    • "Typed" damage, just as fire or physical. Resistances to various damage types.
  • Refactor the GameEngine library into multiple separate libraries, pulling out:
    • Monster creation/behavior
    • Status effects
    • Map creation
  • Some form of basic integration testing for common operations.
  • Some form of "arena" for testing the weights of various skill tree nodes, along with the possibility of an awesome screen saver.
So yeah, that's a lot of work. I'm in no hurry to start working a masses of content for a "slice" game, so if it takes me multiple months, it isn't the end of the world.

While I'm still planning on working on Magecrawl (a lot), I feel like I'm in a good place to open up development to others if they are interested. Developing on Magecrawl offers:
  • A relatively clean/nice C# codebase
  • Licensed BSD
  • Works on Windows/Mac/Linux, development is possible on any platform
  • The possibility to implement high level functionality on a working game, as opposed to starting at square one with an @ walking around the screen (not that there is anything wrong with that)
If this sounds interesting, feel free to contact me at chris dot hamons at gmail dot com.

One last thing, I re-realized how awesome Ascii Dreams is. The "Designing a Magic System" serious of articles and the follow ups should be on the required reading list for any future roguelike developer (or game developer in general). I wish he updated it more often these days, the content is golden.

Sunday, August 15, 2010

Release aftermath and thoughts

So, the new release has been on the interwebs for a few days now. I figured a post with thoughts and future plans was in order.

  • Some people had issues getting things to run. All of them involved needing either the MSVC 2010 C runtime, or the required mac frameworks. I didn't have them listed on the release page, which has been fixed. In the far future, and installer for magecrawl would be nice to take care of stuff like this.
  • Very little feedback so far. Maybe the summer and quick release since the last tech demo have something to do with that...
  • No crashes or savegame corruption reports so far. If people got the game working, it seems to be working fine.
Now that it is out the door, the next question is "now what?". Here are my current thoughts:
  • Spend the next week collecting game play ideas. My wife pointed out this means I can play video games and call it "research". Magecrawl has matured past the point that calling it a tech demo is becoming a stretch, yet the gameplay is kinda bland. I want to come up with interesting mechanics to make combat more than "jam damage spell, unless I can hit more than one with a bigger spell".
  • Iteration 10 - Yes, one more. I have a ton of things I need to do, refactors, cleanup, and minor feature polish. 
  • Slice 1- Once I get the base in good shape, I need to come up with a "theme" for my slice. I plan on picking one skill tree, and one/a few map types, and create a lot of content. For example, maybe the arcane tree and ruins maps, or the fire tree and interesting caves. I'll jam it out to be a "full length" game, seriously this time. It might be shallow, but it'll be complete.

Thursday, August 12, 2010

Magecrawl Tech Demo III v2 Demo Video

I've wanted to put together a quick video demo'ing magecrawl for those who want to see the game before downloading it or are having trouble getting started.

I found some decent software which made creating the video easy enough to tackle tonight. If anybody has a pointer to free software that captures screen video and sound and outputs to youtube, please let me know in the comments. Jing, the software I used was easy, but it outputs only to a flash file unless you buy the pro version.

Eitherway, check it out here.

Magecrawl Tech Demo III v2 released!

I am pleased to announce the release of "Magecrawl Tech Demo III v2". Released two months after the previous Tech Demo III release, it adds features that I wished were part of that release, but not enough I feel to bump it up to number "IV". Highlights of the user visible changes in this release include:
  • Difficulty that won't melt your face
  • Concurrent Mac/Linux/Windows release with a single release zipfile
  • Monster and Items that scale as the game progresses
  • Long term persistent effects
  • "Backgrounds" - Starting configurations of skills and items
  • New skill trees with tons more skills
  • Smarter AI
  • New spells, items, and monsters
  • Bug fixes, and balance fixes
One important note for Linux users, due to a last minute found bug, you will be unable to save unless you add the following string into your Preferences.xml file

< UseSavegameCompression > False < /UseSavegameCompression >

If you run into any crashes, please send the created file "DebuggingLog.txt" to me (chris dot hamons at gmail dot com), along with any save file you have.

One last thing, please seriously consider filing a comment or sending me an e-mail both letting me know you checked out my game and your thoughts. Feedback is the breakfast of champions you know.

Now that I've made you read though all of that, binaries can be found here.

If you haven't run Magecrawl before, here's is what you need installed to make things work:
  • Windows - .Net 3.5 found here. You might need to 2010 C RTE here.
  • Mac - Mono found here. You probably need the frameworks SDL, and libpng.
  • Linux - Also mono found here, however you might want to try a copy installed by your package manager first
Here is how you run Magecrawl:
  • Windows - Unzip the zip file somewhere, and double click MageCrawl.exe
  • Mac/Linux - Unzip the zip file somewhere, open a terminal and cd to that directory, and run "mono ./MageCrawl.exe"

Wednesday, August 11, 2010

"Leaky" stamina, and other "balance" changes

So, I'm still hacking out changes to make Magecrawl playable.

The major change of the night implements what I hope is a solution to the HP problem I talked about last post. I decided the underlying problem was that going from 100% stamina to 5% stamina involved zero risk. Now, once your stamina goes below a cutoff (currently 80%), there is a chance that some of the damage will "leak" through and apply directly to the underlying health. The chance is inversely proportional to the amount of stamina, so you are much more likely to leak at 20% stamina than 75%. This changes make combat more dangerous overall, but having lots of stamina is still useful but not overpowering.

Other changes I've implemented this week include:
  • Map generator won't generate a horde of monsters on top of the player starting position
  • Monsters will notice the player from farther away when they are wearing heavy armor (noise).
  • Toughness skill will now give health instead of stamina, giving the player the option to "buy" more long term health.
  • Bug fixes, seriously lots of bug fixes.

Monday, August 9, 2010

The problem with HP...

I know I've linked to this tv trope, but it is seriously still true in magecrawl. For those not playing along at home, here's what the current system is:

HP is divided into health and stamina. Damage taken is drained from stamina first. Stamina quickly recovers in between battles (assuming you aren't noticed by enemies, you can't rest then). Health damage requires magical healing to fix up. Stamina represents your ability to dodge and block damage enough to get out only with scrapes, bruises, and surface cuts. Health represents actual wounds, while bandaged up enough not to get worse, would normally require weeks to heal on their own.

Let me show you my current problem with an example:

Given 100 health and 60 stamina, you fight a monster which on average does 20 damage per round and takes 4 rounds to kill. Given these stats, you'll exhaust your stamina every fight, taking 20 damage to your health. In five fights, excluding magical healing, you will be dead.

Now repeat with 80 stamina, you on average take little to no health damage, extending the number of one-on-ones to tens or hundreds. If you repeat with 100 or more stamina, you'll extend the theoretical number of battle you can last, but you'll never get close to the "jump" between 60 and 80.

This creates a problem with skills and armor that increase your stamina, at some point you'll be able to solo monsters with no danger of taking semi-permanent health damage. I have a few solutions I'm playing around with:

  • Make the line between stamina and health less clear cut. When you are at 100% stamina, you are sure any damage you take will be stamina related. As it decrease, there is a higher chance some of the damage goes to your health.
    • Advantages - Makes battles less one sided, as any blow after a round or two can be lasting.
    • Disadvantages - Adds a significant luck factor
  • Make healing stamina take resources
    • Advantages - Makes every battle matter
    • Disadvantages - Makes every battle matter, makes it easy to want to micro optimize which isn't fun. Starts to approach the dreaded "food" system in other roguelikes.
  • Make low stamina penalize certain attributes, such as mp total or time in between actions.
    • Advantages - Makes stamina damage matter.
    • Disadvantages - Can snowball, making you more likely to take even more damage. In a game with permadeath, this can get nasty.
  • Make the stamina and health levels relativity constant (they increase at a rate similar to monsters damage output). Skills/armor give other benefits than more stamina.
    • Advantages - Makes balancing easier. One you have a good setup, just make sure the rates of growth match.
    • Disadvantages - Intellectually unsatisfying. Keeps player from feeling any tougher, as at the beginning of the game to the end, the can pretty much only take x hits from a even level monster, where x stays constant.
I'm currently leaning towards the first option, but am unsure right now. 

Thursday, August 5, 2010

All primary feature work is done for iteration 9, finally...

So this morning I finished up the last issues I had targeted for iteration 9 in fogbugz. The release isn't yet ready to go out, as I have to play with the numbers to make the game fun/winnable. However, outside of bug fixes, I should be done make code changes for now.

I'm hoping that balancing should be "easy" now that I have filled in tech trees and have a reasonable spread of items, but as I've said before balancing games is hard. Do any other game developers have trouble balancing stats, abilities, items, and such to make a fun game? Any suggestions on ways to make it easier outside playing the game a bunch and make lots of small tweaks?

Wednesday, August 4, 2010

Skill Trees "Filled Out"

I decided to spend some time "filling out" a few skill trees, and have simple but complete trees for five sub-trees: Arcane, Fire, Light, Martial, Attributes. Each tree has between 7 and 10 node (except martial which has 37), and each node provides a new skill or improves an existing one. I still at some point need to write descriptions for the martial skills, but beyond that the skill tree is done for this iteration.

Sunday, August 1, 2010

Class vs Struct - It actually can matter

So, the second of my optimization realizations today involves the difference between structs and classes. For those who've been with this blog for awhile, you might remember a post I made half a year ago, here. In that post, I realized that a list of structs uses a lot less memory than a list of classes when each item is crazy small and there are a huge number of them.

Today, I've ran into the inverse. I made Point a struct back when I made that realization, thinking that it was small and therefore memory savings were worth the savings. However, when you stick an item into a dictionary as a key, it apparently makes a copy if it is a struct. It also makes a copy if you query the dictionary with a struct as the key. This meant I could rack up half a million or more point copies by scrolling for 15 seconds in my skill tree. This caused the memory manager to go crazy, and introduce the lag I was seeing. Switching it to a class helped a bunch.

When should you use struct vs when should you use class? Here's my current huristic:

If the item is large or you won't be having a crazy huge number of them - Use class, the possible optimization isn't worth it.
If a large number of the items will be stored in memory in a list - Try struct, as you'll save a pointer sized (4 or 8 bytes) amount for each item.
If you will be using it as a key (or value to a lesser extent) in a dictionary - Use a class, as each query on the dictionary and every access will make a copy.

GetHashCode's preformance really matters if you use it as a dictionary key alot

Just a quick post about a surprisingly small change that improved performance in magecrawl's skill tree view. I have a custom point class since there doesn't exist one inside c# outside of some GUI toolkits I don't want to force dependencies on.Since I overrode Equals, the compiler told me to override GetHashCode. I did so the naive way:
public override int GetHashCode()
{
    return X ^ Y ^ base.GetHashCode();
}

I have a spot in a tight loop that needs to lookup information based upon its position. I was previously using a List with a where LINQ call, which was insanely slow when I scaled up the number of skills. I figured this out using profiling and changed it to a dictionary. However, it was still too slow, so I read up on GetHashCode more and realized I could change GetHashCode for point to read:

public override int GetHashCode()
{
    return X ^ Y;
}

I didn't keep track of the numbers, but this very visibly made a huge difference. Keep GetHashCode in mind when you have data structures that are used as keys in large dictionaries. A small change can make a big improvement.

Wednesday, July 28, 2010

Iteration 9 and 10 - The new plan

So, I'm changing my iteration plans around the release of a video game. Let's just put it out there. Final Fantasy 14 is being released September 30th (early access on 22nd), and I am excited enough to pre-order it. Due to that, and the expected week or two post-release that I won't involve much coding, here's the new plan.

Iteration 9 - Finishes asap. As soon as I get the game balance reasonable, and a spread of items/weapons for the 5 levels of the current dungeon, kick it out of the door. I'm planning on calling it tech demo 3.1 or something similar, just for those readers of the blog who want to see the new stuff.

Iteration 10 - Get as much done in August and September. Things like diminishing returns, school specific debufs, sound drawing monsters, etc. Also get enough of the small features done that the next "iteration" will be more of a "slice". Something where I create more interesting gameplay content and less concern on the game engine.

Tuesday, July 27, 2010

Generic can be the enemy of progress

As it was said on coding horror, "a blog without comments is not a blog". Earlier today Jotaf posted a comment on my last post that got me thinking. The post was on my work making changes to the skill tree easier, here's the meat of it:

"Nice, I agree completely, although you must always ask yourself the obvious question: "is it worth it?". Since you're gonna change the skill tree many times during balancing the answer is yes. This is almost always true for data-driven gameplay features (ie, stats, skills...). It's almost always not true ("it's not worth it!") for things that are more or less set in stone, like game mechanics, combat, AI, and I've seen many developers getting themselves into an endless loop of refactoring, because you can obviously always make future changes easier by changing your design to be more generic/plugin-driven/offloading more data or logic into external files."

I think this is true and in some cases can prevent roguelikes from ever getting completed. Since none of us get paid to work on our pet projects, the temptation is to never set deadlines or abide by them. The desire to make the code "perfect" can make us spent all of our time making the code more generic to the point we're creating a game engine more that game itself. While this can sometimes be successful (ToME being the most obvious example), for 95% of us it doesn't buy us much.

If I spend 10 hours refactoring the AI to move it to external files, and then spend only 5 hours tweaking it over the next year, the change was obviously a loss. Even if I save some time, that needs to be balanced by the fact that the code is more complicated. As opposed to a function you can debug, a problem can be in the file parser, the external file itself, the code implementing the behavior expressed in the file, etc.

I have a few suggestions for other developers based on my experiences with magecrawl that so far have mitigated this issue for me (beyond my general pragmatic attitude).

  • Set deadlines, preferably short ones - When you want to finish your iteration in three months, spending a month and a half on something like swig'ing libtcod or converting libtcod's build system to cmake, makes you at least think about the trade off you are making.
  • Use bug tracking software - I love fogbugz myself, but the one built into google code or even bugzilla is better than nothing. When you find something you'd like to refactor or make more generic that would take longer than 15 minutes, go add an entry for this or a later iteration and get back to what you were originally working on.
  • Things that change often or by users should live in external configuration files, things that don't shouldn't - How often are you planning on changing your physics system? Even if you think this'd more more often than once, leave it hard coded for now. After the third time you mess with it, then go make it generic. By the time that third time happens, you'll probably have a better view on what to pull into data files anyway.
  • You can ignore any of these rules if you want to - beyond the fact that I'm just a random blogger on the internet, you are writing your game. While I think getting a working game done early is the best way to do things, realize you are doing it for enjoyment. If spending a year writing a engine that can make toast, run a neural net AI, or show pong on the screen, all with just changing configuration files sounds fun, go get coding.
One final node, I love comments on my blog. They are the breakfast of champions. Please feel free to leave them, they make things more interesting around here.

    Sunday, July 25, 2010

    When making a type of change in your game is tedious, first fix things so that it isn't anymore

    So part of my balancing work involved buffing the player's abilities when it makes sense. One way to do this is to add new skills on the skill tree. However, the system I had in place for read/displaying the skill tree made me hesitant to do so, as even a simple change was a lot of work.

    The previous system involved a text file with a grid of ascii characters laying out the exact location for each node, along with a list of positions below to match each one up with the associated skill. If I wanted to add more nodes, I'd have to manually place it, then calculate the offset and write it below. If I needed to make the grid bigger, I'd have to recalculate the offset of every node for that tree. It pretty much never should have gotten submitted in that state, but it was "good enough" for the simple trees I had implemented. The horror can be found here for those who are morbidly curious.

    I noticed that all my nodes were in a grid, so I converted each text file into an xml file describing the skill tree. One example can be found here. I then wrote the xml reader and which would generate from the stored information the grid of characters to display on the screen. Overall it took about three hours to write, test, and submit.

    In less time, I probably could have made my balancing changes and "got out" without making things better, but I would have been more likely to not add new skills in the future. Now adding a new skill is as easy as copy pasting an xml node and changing a few lines of text.

    Saturday, July 24, 2010

    "Backgrounds" - The compromise of class selection and skill tree

    One of the unwritten design guides I've followed in magecrawl has been to not ask the player for choices they can't answer before the game starts. The first time I launch a game and am ambushed by something like this (care of Crawl Stone Soup):


    I get overwhelmed with choices. What the difference between fighers and gladiators? What is the difference fire/ice/air/earth elementalists? These choices are ones that are difficult to make before playing (multiple) times.

    The reason this came up during my initial balancing effort is that I realized balancing some options were difficult. For example, how much should the heavy armor skill be? I didn't want to start the player with equipment they couldn't use, so by default they'd have to scavenge for at least part of a set before taking the option would make sense. It'd need to be powerful enough that it'd be worth going to all that trouble, but not so broken as that'd be the only logical choice.

    Letting the player choose to use armor/heavy armor before the game makes some sense, as I could start them with a set of said armor at the beginning of the game. I've decided to try to take some of the nice features of crawl's system and pair them down to something more reasonable:


    Opinions? These starting backgrounds would provide the initial equipment and preselect some skills in the skill tree. However, there's nothing to prevent a Templar from selecting skills from a tree and become a ranged attacker, beyond the penalty from using heavy armor.

    Friday, July 23, 2010

    Current plans on dealing with game balance, with the first step being spelling it correctly...

    (Potential bloggers out there, don't write new entries when you are tired or else you might blast everyone's RSS reader with blatant misspellings like my last post)

    So as I mentioned, balancing roguelikes is hard since doing so involves balancing multiple variables (with a significant amount of randomness thrown in). In an effort to motivate myself into finishing this work, I'm writing up a quick post on my decisions and strategy.

    The first variable I focused on was damage output. I decided on a "base" damage an average attack should do, 10d3. For those not initiated in the "d" notation, 10d3 refers to rolling 10 dice with three sides, and summing them all up. 10d3 produces a range of 10-30, with 20 being the center average.

    I chose d3s since they produce a nice range with some variability but don't have extreme variability. 5d6, for example, produces a range of 6-30, which is somewhat close to 10d3's range. However the possible "burst" of a good roll means five times the low roll or twice the average for 5d6, compared to three times the low roll or 1.5 times the average in 10d3.

    Once I had the damage set, I needed to guess how many hit points monsters and players should have. I started with a guess that the average combat should last five to six rounds, which with twenty points being the average round means 100-120 hit points. For the player, I split these up in health, stamina, and bonuses from the average set of equipment I'd guess one would have.

    The next variable is the rate of growth as the game progresses. Magecrawl doesn't have "levels" per say, but I assign an internal level to monsters and items. Each "level" of monster and equipment is currently scheduled to increase in damage and/or stamina by about 25%. This doesn't exactly work, I realized as I wrote the previous paragraph, since the player receives a majority of their hp from their initial stamina and health. Increasing damage monsters do by 50% while increases the stamina bonus of equipment by 50% doesn't even out. Still more to hammer out apparently...

    Now that I have some guesses of numbers, I coded them in and forced the map generator to produce only a single type of monster. I'm planning on playing a good number of games, tweaking the numbers so that I can "win" a decent percentage of the time but not always. Once I have that single pairing balanced, I'll continue with others until I have a good feel on the numbers that are fun....

    Tuesday, July 20, 2010

    The trouble with game balencing is that it is hard....seriously

    So part of the long delay between this and the last post was a (hopefully?) well deserved break after a mammoth week of coding. However, part of it is related to my lack of progress in balancing the new monster/weapon/quality types. Trying to keep individual fights interesting while keeping ambushes from turning into two turn player-deaths and making it scale after (for now) 5 levels is hard. Like harder than writing the code that allowed it.

    Part of the problem is I want to get rid of the issue I call "rounding-error bonuses". For example, let's say that having a quality weapon improves the damage by 15%. If your sword base damage is 1d4, then 15% is less than 1 point of damage. It'd have effectively no effect. One could solve this by increasing all the numbers by a factor, say 10, then the sword base damage would be 10d4 (10-40) and 15% is on average 3-4 additional damage. Getting these numbers correct, along with making them look reasonable isn't going so well. It seems weird to have the starting sword do 10d3 damage and average swings totaling 18 or more (maybe that is my experience in d&d based roguelikes and games talking).

    Does anyone have a good system or set of tools for figuring this out? Bonus points if it has been proven in a shipping game or one at least farther along than magecrawl...

    Saturday, July 10, 2010

    7DOMC - Day 7 - Monsters and thoughts on this week

    With my commit here I'm done with my XML generation changes this iteration. Monsters now have different names that are level dependent, with base stats and some stats that go up each level. The "trait" system has been booted to iteration 10 due to my exhaustion in this area of magecrawl. I need to create some content for items still, item levels for each armor/weapon from 1-6 or so, but otherwise I have the base material for a sane difficulty curve.

    So, if you've read this blog any this week, you probably can tell that I've been busy. With my wonderful wife coming home tomorrow and family in town next weekend, it'll probably be a few weeks before I implement anything major.

    Looking back on this week, I think the fact that I announced my intentions and wrote about them every day was useful. There were days that I didn't want to program, I would have rather played TF2 or Borderlands all night. However, the idea of skipping a day's post or admitting I didn't get anything accomplished pushed me to do some programming. Once I overcame the initial hump of launching Visual Studio, I generally started to enjoy my work.

    In some regards I got less done that I expected, but I think that was due to me vastly underestimating how much work some of my tasks would take. Item generation based on levels took three or four times longer that I would have initially assumed. I think it would have taken even longer if I had to break it up over a week or two's evenings.

    I have 26 items left targeted for this iteration. With the possible exception to my "field" idea for improving monster AI, each of them should involve significantly less work that either the item or monster changes this week. They should be "bite sized" enough to tackle one or two after work some night.

    Friday, July 9, 2010

    7DOMC - Day 6 - I thought I was done with items, but I made them better.

    So on day three I said I was done with the item rewrite. While this was a true statement, I realized today that there was one way I could improve items even more. The current system had each material list the base stats for a weapon/armor made of it. Something roughly:

    Wood Club - 3d3  CTCost=1.0
    Iron Sword - 4d6 CTCost=1.25
    Cloth Armor -  +5 stamina

    The issues is that I had to list out each statistic for each material. If I know that say leather is 20% more stamina than cloth (the base type), I'd need to calculate that and put both values into the XML. If I decided to increase the base later, I'd need to update all the values again.

    To fix this, I now have materials list a percentage or linear amount better they are than base. For example, Wood adds 1d3 damage and leather adds 20% more stamina than base. If I update the base values, the change will propagate to all armors/weapons.

    C# - The dangers of int.Parse() on non-english systems

    I ran into this issue in a similar for way back in January here, but I stumbled upon in again today and I figured another post wouldn't be a bad idea.

    This simple function

    double ParseString(string s)
    {
         return double.Parse(s);
    }
     
    is a timebomb waiting for one of your fans or customers to run into if s comes from a a source that isn't translated into the specific language. For my C/C++ fans, int.Parse() is similar to atoi() with a twist we're about to get to.

    My part of the world uses a period to separate the whole from the fractional part of a number, "10.0", other parts of the world uses a comma, "10,0". C# will helpfully use the latter on systems who's language is set to be one that uses this system. This can wreck you, if for example, the string comes from xml data files that you don't want to change for each language.

    There are two solutions. The simplest is to rewrite the function as follows:


    double ParseString(string s)
    {
         return double.Parse(s, CultureInfo.InvariantCulture);
    }

    That will use the "standard" english system of period for decimal seperate.

    The second is one that works if you are about to do some operation that is going to call Parse a large number of times (e.g. Save/Load).


    double ParseString(string s)
    {
         // Save off previous culture and switch to invariant for serialization.
         CultureInfo previousCulture = Thread.CurrentThread.CurrentCulture;
         Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
    
         double result = double.Parse(s, CultureInfo.InvariantCulture);
    
         Thread.CurrentThread.CurrentCulture = previousCulture;
    
         return result;
    }

    Just be careful that if you expect your code inside the culture setting blocks to throw an exception that you plan to survive from, to rewrite this to use finally so that it always happens.

    Now I have to go check every Parse() and fix up the ones that don't happen inside a save/load call...

    Thursday, July 8, 2010

    7DOMC - Day 5 - Monsters AI changes wrapping up

    So, all the great AI work that I did a few iterations back can be distilled into this chunk of code now:
    switch(typeName)
                {
                    case "Bruiser":
                        tactics.Add(new DoubleSwingTactic());
                        tactics.Add(new DefaultTactic());
                        break;
                    case "Healer":
                        tactics.Add(new UseFirstAidTactic());
                        tactics.Add(new MoveToWoundedAllyTactic());
                        tactics.Add(new DefaultTactic());
                        break;
                    case "Ranged":
                        tactics.Add(new KeepAwayFromMeleeRangeIfAbleTactic());
                        tactics.Add(new UseSlingStoneTactic());
                        tactics.Add(new KeepAwayFromPlayerIfAbleTactic());
                        tactics.Add(new PossiblyRunFromPlayerTactic());
                        tactics.Add(new WaitTactic());
                        break;
                    case "Sprinter":
                        tactics.Add(new RushTactic());
                        tactics.Add(new DefaultTactic());
                        break;
                    default:
                        tactics.Add(new DefaultTactic());
                        break;
                }

    I obviously plan on pulling this out into an XML list or something similar, and add more intelligent "tactics" so I can make the AI even smarter. One idea I had would have slingers who don't have a line of sight for a shot to move to one more likely. Another would have healers find bruisers and stay togeater, kinda like heavies and medics in TF2.

    Now that I have a "flat" monster hierarchy, I need to write generators similar to the ones I wrote for items that'll create level dependent monsters.

    Wednesday, July 7, 2010

    7DOMC - Day 4 - Planning and Monsters

    So, after the craziness of the last two days, today is a bit more subdued. Part of that is a bit of burnout and part of it is busyness at work.

    Even with the work {I've/I'm going to} accomplish, my chosen tasks for iteration 9 were a bit much. I pushed back 12 minor features to another iteration, giving me 28 total. For those doing math, that doesn't exactly add up to previous posts, which is due to me splitting a few tasks up into smaller bites.

    Speaking on smaller bites, I'm working on refactoring monsters completely as well. I want them to be more attribute based, like skills and items, and have more flexible behavior. Since they touch a smaller portion of the code base, I'm doing my refactoring in smaller bit sized pieces.

    Update -
    So I'm not done yet, but here's the jist of it.

    There is a set of tactics, which are discrete single actions that could or could not be preformed. Each tactics can be asked if it could apply now and ask to do it. Then a loop like this runs:

                m_tactics.ForEach(x => x.NewTurn(this));
    
                foreach (IMonsterTactic tactic in m_tactics)
                {
                    if (tactic.CouldUseTactic(engine, this))
                    {
                        if (tactic.UseTactic(engine, this))
                            return;
                    }
                }

    Each monster would have a set of possible tactics, for example, my healer AI can be stated as: UseFirstAidTactic, MoveToWoundedAllyTactic, DefaultActionTactic.

    Each tactic setups the required attributes on the Attributes dictionary of the monster, which are serialized, so things are remembered past save/load like the cooldown on the first aid ability.

    The cute thing about this is once i code up a great new behavior, I can slip it in the monster behavior list and it'll start acting that way. Once I'm "done", I'm going to be pulling the list of behaviors a given monster has out to XML.

    Tuesday, July 6, 2010

    7DOMC - Day 3 - The item rewrite is done...finally.

    So the patch I submitted was six thousand lines long, and took a grueling day of coding yesterday and half a day today cleaning up loose ends, but it's done. Much of the work involved moving a hierarchy of classes that defined weapon, armor, and consumable types into a flatter set of classes that allowed more dynamic changes.

    A quick overview of the way I generate items follows:

    For armor/weapons:
    We start with an expected item "level", determining how "good" the item should be. We first calculate a quality grade, which falls from -2 to +4 on a normal distribution. We then determine how many "levels" we have left to choose the material. Each material, for example wood, iron, or leather, states what items can be made of it and what their properties are. Some materials have higher level modifiers, so a bronze would be lower level than say cold-forged iron. The material determines the base damage/speed/protection of the item, while the quality increases or decreases it by percentages.

    For potions/scrolls/wands.

    A slightly different approach is taken. An effect is first determined, using the requested level item as a range to select from. Wands cut the level in half, since they allow the effect to be produced multiple times. For any left over levels we increase either the caster level of the effect (for potions/scrolls) or the number of charges in wands.

    I still need to implement the bulk of the content, for example material types for each weapon  varying over the ranges, and a ton of playtesting to find bugs and determine values for each material/quality. However, the coding for this headlining feature is done. :)

    Monday, July 5, 2010

    7DOMC - Day 2 - The great item rewrite

    My first task today has been completed, which is moving all the skills to use the new attribute based system detailed here.

    I looked at doing the same with items, when I realized that I'm going to have to rewrite pretty much my entire item hierarchy to do things right. I ripped out (with a backup copy for reference) all the item, armor, and weapon classes from the game engine, and commented out or "throw new System.NotImplementedException()"'ed all the code using them. Now I can start again from scratch and when the diffs show no commented out code, I'll be back where I started.

    I very rarely try a rip out and rewrite. In general, I find a set of small incremental changes work best. However, the shear size of the item hierarchy was daunting to say the least. We'll see how this goes, I'll update later.

    Update 1 (10 hours later)

    So I have the weapon system up again. I've got generated weapons of various qualities and materials. The weapons damage is base speed comes from the material, with the quality affecting things as well. Descriptions are built up from the various parts, along with the names. Save/load works again for weapons. Much of the work was creating a brand new hierarchy for weapons, and the generator for materials and quality.

    I'm hoping to get armor up quickly now that I have this base. Then I need to rework consumables, such as potions/scrolls/wands.

    Update 2 (1 hour later)
    Armor works, with quality, materials and the like. Now onto consumables.

    Update 3 (1 1/2 hours later)
    Obviously things are taking longer than I'd expect. I'm almost all the way through consumables but I'll have to wait for tomorrow to finish up and submit.

    Sunday, July 4, 2010

    7DOMC - Day 1 Status

    I'm winding down for the night, and I'm pretty happy what I accomplished today. Here's what I accomplished today:
    • Magecrawl for Linux - This single task involved hours of work. rpath's still leave a bad taste in my mouth.
    • 14 open tasks - I went from around 51 open items to 37. Some of these work items were tiny, while others involve entire features, so you can't say that I'm 27% complete however. 
    • One of those open tasks required me bringing some sanity to how MagicEffectsEngine::DoEffect outputted text to the log. It look awhile, but now looking at that file no longer makes me wince.
    However, other that the Linux task, I didn't touch any of my head lining features.


    There is still much to be done this iteration (and this week).

    Will the penguin in the room please stand up...

    Magecrawl now works on Linux again. You'll need a new copy of mono (one that isn't released yet but will be before my next release), but it works!

    For those who care about the bad things I had to do to make this work, read on...

    So, the major issues were causing problems was the libtcod-net-unmanaged library was not working as expecting.

    The first issues was both mac and linux wanted to create a library called libtcod-net-unmanaged.so. I modified the make files to create to new files and used mono's dllmap to point the right platform to the right binary.

    Once I fixed that, I was getting missing symbol errors. I had forgotten that libtcod.so doesn't have the C++ symbols under Linux. I linked against libtcodxx.so, copied that in, and fixed that.

    The final issue, which took three of four hours to solve, invoked this bug in cmake. I had to use an internal "don't use this, it could break on new versions" macro to work around it. The code in question is:


    IF(UNIX)
         SET_TARGET_PROPERTIES(${SWIG_MODULE_${CSHARP_LIB_NAME}_REAL_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath,.")
    ENDIF()
    with SWIG_MODULE_${NAME}_REAL_NAME being the forbidden fruit.

    Saturday, July 3, 2010

    7DOMC - Seven days of magecrawl coding

    As I mentioned in my previous post, I have a huge list of things I'd like to accomplish in magecrawl in the short term. It just happens to be such that my wonderful wife is going to be visiting friends out of state until next Sunday. Combine this with a Monday/Tuesday holiday off work, and I have a significant amount of free time this week.

    My hope is to stay productive (not just play Eve online and TF2) for most of the upcoming week. We'll see how much I get accomplished. I'll be posting updates as the week progresses.

    Friday, July 2, 2010

    "Iteration", I don't think that means what I think it means...

    So I have some time next week to work on magecrawl, and so I'm looking at my task list and realizing I currently have a ton of things targeted for iteration 9. Ignore the bug fixing and corner cases issues, I have these high level goals currently:
    • Create level dependent items and monsters
    • Refactor how skills and items are handled to combine with new traits for monsters
    • More effect work, including debuffs specific to various schools attack spells.
    • "Field" effect to model sound/smell to make monsters seem more realistic.
    In addition to this, I currently have 51 open issues targeted to iteration 9. Some of these issues are minor, but some include creating new classes of items, major new spell types, and other significant chunks of work.

    I'll talk about my short term programming goals later this weekend, but the short answer is unless I seriously knock a lot of this work out soon, I'm going to have to punt on stuff to an iteration10 or have a bloated schedule.

    Monday, June 21, 2010

    A generic system for implementing skills, traits, and item bonuses...

    I know the title is a mouthful, but if beyond it is an idea I'm excited about. Like most ideas, it came to me when I was doing something other than programming.

    This iteration I'm planning on implementing varying difficulty monsters and hopefully items of varying strengths. In my previous post, I suggested using a "trait" system to implement some of the monster characteristics. For example, one wolf might be "fast"-er or "strong"-er than another, trading that off against some additional base attributes. In my head I hoped to sneak in items with enchantments; a sword that could make you tougher or a staff that made you case spells better.

    It came to me that both of these use cases are very similar to the skill tree attributes I implemented last iteration. Those skills could increase base stats or allow new skills. As a programmer, when I hear of three different implementations of an idea, I get an itch to make a generic framework or factor out the pattern or something.

    The crux of the idea is that all of these ideas can be implemented as a system of tags and values. For example, a skill that increases the characters base hitpoints by 5 could be:

    m_player["HPBonus"] = 5;

    Then to calculate the number of hitpoints in this simple example one can do something like:

    // Player
    int GetSkillTags(string tagName)
    {
        int total = 0;
        foreach(ISkill s in Skills)
        {
             if(s.attributes.Contains(tagName))
                 total += s.attributes[tagName];
        }
    
        foreach(IItem i in Equipment)
        {
             if(i.attributes.Contains(tagName))
                 total += s.attributes[tagName];
        }
        return total;
    }
    
    // Monster
    int GetSkillTags(string tagName)
    {
        int total = 0;
        foreach(Dictionary<string, int> d in Traits)
        {
             if(d.Contains(tagName))
                 total += d[tagName];
        }
        return total;
    } 

    Once I implement a given skill or trait checking in one section of the game engine using this API, creating a new skill, item attribute, or monster trait to do the same thing is trivial. Also, since checking if a dictionary contains a key is fast, it should be efficient as well.

    Thoughts?

    Sunday, June 20, 2010

    MEF is now cross platform friendly, kinda

    So in February I noted some attempts at using MEF and the disappointment that it was Windows only at the time. MEF in short is a way to break up your C# application into smaller pieces that are loosely connected.

    Since multiple of the tasks I have for iteration 9 involve refactoring, I figured I'd take a look at MEF again and see if it is in better shape. The short answer answer is that it works with mono, but only in their development branch. A kind fellow in the mono IRC channel pointed me to a copy he built of System.ComponentModel.Composition.dll that I could use. It works under Windows, Mac, and Linux.

    In the next release of Mono it seems likely that this will be built into the .NET 4 client profile, but packaging a single assembly along with your application seems to be an easy solution for now.

    Once I break up magecrawl into smaller components, I'm planning on making another post describing MEF and showing how I used it.

    Saturday, June 19, 2010

    Iteration 9 - "Levels" and polish

    So, I haven't had the time I wanted to work on magecrawl this week, but the ideas keep coming. I have over 50 major/minor/bug fixes I wish I could get into this iteration. Before an iteration, I try to come up with a "theme" tying together what I hope to accomplish in the next few months. This iteration (9), the theme is "Levels and polish". It also may be the last iteration before I move onto the next stage of my development plan.

    The "levels" in the theme refer to varying levels of difficulty in challenges, not different floors connected by stairs (which I already have). For example, the wolf that attacks you at the very beginning of the game should be different than the wolf pack that hounds you a few levels later when you have better equipment and skills. The quality of treasure should also vary based on depth.

    My current idea is to create an engine that creates these monsters and items on the fly. For example, asking for a level 3 monster could create a fast (+1 lv, 25% faster), strong (+1 lv 25% dmg) base kobold (base creature). Or it could create a experience goblin (+2 stat levels). A combination of traits (such as fast, strong, special abilities) and stat levels (more hp, etc). A similar system would exist for items, so creating a level 5 sword could return a masterwork wooden sword or a crude iron sword. Each quality grade and material would contribute to the effective level of the item, along with any enchantments.

    I think this system should help me balance magecrawl's difficult curve. Manually creating monster and item stats based on paper calculations is difficult and time consuming.

    In addition to "levels", I have a huge number of polish issues that I'd like to implement. They range from the status effect ideas I listed here to internal refactoring to improving monster AI.

    As I mentioned, this might be the last "iteration" of magecrawl. I think I laid this out on some other post, but finding it escaped me. The idea of iterations are to fill out functionality needed in the game engine and GUI needed for a "real" game. After I feel like I have enough functionality, I'm planning on moving to "slices". Slice would be a portion of the full planned game, from top to bottom. For example, the first slice could be implementing the entire fire skill tree and all its spells, and flushing out sections of the dungeon. The game itself would be a full (albeit shallow) game. After releasing that, I'd take another slice of say the water tree and more dungeon sections.

    Well I should get off to coding...

    Saturday, June 12, 2010

    Status Effects 2.0

    The initial implementation of status effects, the one you may have seen in the first three tech demos of magecrawl, was almost an exact reimplementation of the model used in crawl. Effects when cast have a length (in turns or ticks or whatever) at which time they disappear. Some effects are positive, some are negative. If you have a positive effect (say haste) that you want to have on you permanently, you need to recast it was it expires. Some games automate this step, but in the end it is the same model.

    While simple and easy, I don't really like this model for magecrawl. Mages in books and legend sometimes were wrapped in layers of magical protection, and the idea that you need to stop walking every five minutes to recast all your buffs seems silly. I'm stealing a page from dragon age, and separating effects into two orthogonal categories: length and type.

    Sustained effects (long term) are ones that persist until canceled, however have a continuing cost. My current implementation reduces the player's maximum MP by an amount for each effect that persists. This provides a nice trade off; keep no effects up and have access to your entire mana pool, keep some up and have only part, or keep a bunch up and be able to maybe only cast one spell.

    Temporary effects are effects that use the traditional effect model of a deadline time and no additional cost while in effect. Unlike sustained effects, where having a sustained negative effect doesn't make sense, temporary effects can be positive or negative in nature. Positive effects that are too powerful or come from items could be temporary. 

    Another status effect idea I had, which I haven't implemented yet, are school specific debufs for common attack spells. An simple example would be the school of fire. Fire attack spells could have a chance to apply a "burning" negative status effect upon targets. Some spells (like sticky flames) might have a higher chance to apply effects than others. In the case of burning, it would do damage over time to the target. If attacked by any water or ice damage damage, the effect would end early. 

    Some effects I have in mind would reduce damage taken by some schools and increase others (e.g. being frozen reduces fire damage but a good earth spell would shatter the target nicely).

    Effects might be a trait added on by skills in the skill tree, so the initiates fireblast might do damage but not be powerful enough to set things on fire. It also brings up the possibility of branches in the skill tree, where some could specialize in damage over time or status effects while others specialize in raw power.

    I think status effects will be on the areas I focus on for this iteration. I think it can be used to bring out a lot of flavor and interesting choices in magecrawl.

    Wednesday, June 9, 2010

    What I've been up to the last few weeks...


    In the age of please rob me and other such sites that make it easy to find people's home location, stating online that I was going to take a 10 day trip out of the country didn't seem like a good idea. Hence the "things are going to be crazy" excuse. My trip to Russia was wonderful if your are curious.

    Given the 12 hour flight both ways, I did get some hacking on magecrawl done. I refactored and redesigned how status effects work. I'll get around to writing it up as a long post hopefully this week.

    Now that I am back, and mostly recovered from jet lag, more forward progress on magecrawl seems likely. I have an idea list a mile long I need to enter into fogbugz, and I need to come up with a high level plan of what I'm going to accomplish this iteration.

    Tuesday, May 25, 2010

    Magecrawl Tech Demo III release for Windows/Mac

    Magecrawl Tech Demo III is available for download. The difficulty is a bit harder that I would have liked, but should be playable. You can find it for Windows and Mac here.

    The new features compared to the last release include:
    To play magecrawl, a few dependencies need to be installed.
    • For Windows - the .NET 3.5 runtime is all that is needed.
    • For Mac - Install mono, SDL, and libpng
      • Since libtcod uses .dylibs for mac, the dependent frameworks need to be installed, not next to the program. I think there is a way around this, but I haven't had time to look into it.
      • On some mac laptops the default resolution will place magecrawl overlapping the dock.  Two workarounds for this include setting the dock to auto-hide or uncommenting the line in Preferences.xml "True" so that magecrawl will run full screen.
      • To run open a terminal to the folder you unziped, and run "mono MageCrawl.exe"
    If magecrawl happens to crash, a file called DebuggingLog.txt should be created in the magecrawl directory. Please note that this release is using an SVN version of libtcod, so be forgiving of any issues that crop up. Please send that file along with any description of the issue to chris dot hamons at gmail dot com.

    I'm sure there are some Linux fans out there that are wondering why Linux got left in cold. The short answer is that I ran into a last minute issue preventing the new SWIG'ed libtcod from working on my test vmware. As I won't get much time to work on it for the next two weeks, it was either delay the entire release or skip Linux.

    I'd love to hear feedback on Magecrawl; the good, the bad, and the flames about using .NET and how it made your goldfish sick. Send them to: chris dot hamons at gmail dot com

    Things are going to be be pretty crazy personally for the next two weeks, so if you comment on a post or send me feedback/bug reports, please forgive the long reply times. Once I get past the next two weeks, I should be back on starting for iteration 9.