Knoxville, TN

Prototyping a card game with nanDECK, part 1

August 8, 2014

Sometime last year, I started playing around with prototyping a card game. At its core, it’s a hidden-loyalty game strongly influenced by The Resistance and Battlestar Galacticabut with combat influenced Lunch MoneyAs such, it’s required a lot of tweaking for the little playtesting I’ve done.

I recently dug up and updated my prototype, throwing away long-removed cards and reprinting heavily marked-up cards.

This has all been a rather painless process because I chose to use nanDECK for printing my prototypes. This allowed me to manage my deck lists in spreadsheets, which I then feed into nanDECK whenever I want to do a printing. (And deck list management was a concern for me, since I had three decks–Loyalty, Player Actions, and Encounters.)

I won’t say nanDECK is a useful tool for every deck you need to prototype. There are other programs that will spit out printable cards from a CSV–likely much, much easier to configure. nanDECK’s configuration is rather esoteric, and some of it feels like it slowly evolved out of bolted-on user requests.

In part 2 I’ll talk about how to actually write these configurations. But for now, let’s talk about the reasons you would (and wouldn’t) want to use nanDECK.

Reasons I used nanDECK

Testing card probabilities: My game contains multiple copies of the same card, so I wanted to be able to adjust the numbers to tweak the “feel” of the randomness (ideally, without having to print up cards). Fortunately, nanDECK has a “Virtual Table” feature that allows you to draw cards from a shuffled version of the deck.

nanDECK Virtual Table

My own card layouts and spreadsheets: My Encounter cards don’t fit into a simple title-and-description format. Some (but not all) Encounter cards include some numeric values.

While I could simply embed these in one long description, I wanted to make them columns in my CSV file. I also wanted my card template to conditionally hide these fields (and their labels) if they were empty in the spreadsheet.

Custom card formats: For simplicity and uniformity, I prototype with perforated Avery business card templates. This is extremely convenient for me, so long as I can make the cards fit the template. (If I was using Word, this would be easier, but it would also require me to copy-and-paste a lot of cards.)

I needed to be able to force my cards into a non-standard 2″ x 3.5″ format, and (more importantly) ensure these cards were laid out matching the perforations.

Cases where nanDECK wouldn’t be useful

Simple title-and-text cards: If your cards don’t benefit from a custom layout, then it’s probably not worth wrangling nanDECK’s templating system.

Unique cards: If there will be one and only one copy of each card in your deck, nanDECK isn’t going to be worthwhile. You’re better off using something like word (even if trying to maintain your card list might be a bit awkward).

Anything beyond initial prototyping: If you’re adding card art or you’re no longer juggling card text on a regular basis, nanDECK is more complicated than helpful. At this stage, you’re better off laying out cards in a desktop publishing or graphics application.

(Continued in part 2.)

Reactions to the D&D “5E” announcements/rumors

January 9, 2012

I’ve heard some rumblings about a new edition of D&D today, and finally caught a couple of links in my Twitter feed. (I could just Google this stuff, but I’m lazy and feel like I can trust re-tweeted links from known sources better.)

I’m having two reactions to these rumors, and I think these apply to not only gaming, but technology and programming and all sorts of other things. (Admittedly, they are gut reactions.)

Learn to recognize when you’re being sold the “next big thing” line, but don’t overreact. 4E’s marketing was all about how it makes the game more accessible and easier to play. And it did that, mainly by adopting some game mechanics from MMOs. Fundamentally, this isn’t a bad thing. Rumors pointing to a more old-school approach suggest either it didn’t work or it went too far.

This seems to be the fundamental problem with a lot of leaps in design/technology: to ease the uncertainty, it’s hailed as the “next big thing” (the implication usually being that those who don’t like it don’t “get it”). For other examples, look at WPF vs. WinForms and .NET vs. WinRT. Or look at any new programming methodology that gets some good buzz behind it. Maybe we’d do well to consciously remember almost every “next big thing” will somehow, someday be “old and busted,” if only because it loses its novelty, and that you can’t say with certainty what “the next big thing” will be until well after it actually becomes “the next big thing”.

But being a naysayer may be as bad as being sold on the party line. 4E was a different system than 3E. It did some things better and some things worse, but it wasn’t on the whole a huge step back–more like a lateral move. Ultimately, I hope the update will capitialize on the good things while dropping the things that didn’t work. But if you deny that an about-face means the whole thing wasn’t as successful as hoped, you might end up missing the “next small, iterative thing” because it’s not the much-heralded “next big thing.”

My point, I suppose, is that the best response is to realize it is a line and ignore it. And railing against it is not ignoring it–you’re still allowing the line to dictate the terms of the conversation.

As an aside, I think companies damage trust with their customers when they play a strong “next big thing” line and it fizzles. Of course, that’s just me–I’m overly literal and I have a strong reaction to trying to reframe reality in ways that turn out to be decidedly unrealistic. But I have a feeling the “reality-based community” is not a large portion of anyone’s target audience.

WotC is doing well to frame this announcement by focusing on the fact that game development is an iterative, sometimes opinionated process, rather than playing “the next big thing” card again. I don’t know if that will convince people to buy a new set of books.

There is no universal system for anything. I find the talk of a single system a bit disconcerting. 3E was a very tools-oriented system and 4E was a very game-experience-oriented system. Both of these are valid approaches for different types of people, the success of which depends upon whether a niche will buy enough to support the product line. And the quality of each approach depends on making design choices that support that approach–it’s nearly impossible to create a good restricted, simplified system and cater to people who want an open, free-form toolbox.

To put it another way, even if it’s community-driven, it will not necessarily be universal.

4E was divisive is because it told 3E D&D fans “this is what we’re about now.” That didn’t sit well with me, but I recognized 3E and 4E were the right tools for different types of campaigns (in terms of genre, feel, player types, and scheduling/effort). No matter what the company line was, I was free to choose which tools I would use.

The two approaches could almost be separate product lines, or maybe alternate rules sets of rules à la Unearthed Arcana. (And it appears this is not too far off.) But any attempt to say “this is the secret formula” will end up looking dated in a few years, even if it was borne out of community involvement and playtesting.

Of course, the rub in WotC’s case is that you have to have a business model to go along with whatever decision you make. Will subscriptions work as well as they hope? I’m not sure. I only recently decided to shell out for D&D Insider, but $9.95/month is painful for one semi-regular game. Is there a middle way between a subscription-based model and model based on endless splatbooks? I don’t know.

Anyway, that’s my two cents. I haven’t played a lot of 4E. For reasons I’m not entirely sure of (and which may have little to do with the game itself) I haven’t been all that excited about learning the rules in depth as I was with 3E. Will these updates fix that for me, or will it make me say “screw it, I’m sticking with 3E”?

(EDIT: I actually went back and read some of the original source articles and updated this post.)

Managing collections of objects in XNA: Structs vs. Classes

February 3, 2010
space shooter

Obviously, these aren’t the final graphics.

A couple of weeks ago, I started working on an XNA space shooter game. It’s 2D and completely sprite based–the type of thing that you wouldn’t think was that hard to do. And yet, I put most of the inner workings of the gameplay through two rewrites in that time.

The first draft

At first, I wrote a nice class structure: every gameplay object originated from an abstract class called GameObjectBase, which defined methods to handle Update, Draw, and intersection with other types of game objects (projectiles, the player’s ship, etc.). Then, each additional type of game object had its own abstract base class that, again, defined key pieces of behavior: EnemyBase, ProjectileBase, PowerupBase. The main game loop itself would keep track of all of these game objects, calling Update and Draw on them as necessary.

The plan here was to be able to define a new class for each type of enemy and weapon so that I can define whatever behavior I need for them. That’s what I’m really going for here: I want the option to do interesting things with various weapon powerups. And I think I’d actually hit upon an elegant solution.

When you first fired it up, the game ran fine for a while. But there was a problem: garbage collection. Each new enemy or bullet created a new object and stuffed it into the main game object list; each time one of these enemies was destroyed it was removed. Considering that the player can fire ten bullets per second, that’s a lot of objects. Eventually, the garbage collector had to clean up all of these old objects, essentially freezing up the game for a few seconds.

Continue reading

Crash issues after installing VS2010 Beta 2 / .NET 4.0 Beta 2

November 17, 2009

This is a random post, but I figure it might help someone, since I couldn’t figure out what was going on for the longest time.

I installed Visual Studio 2010 / .NET 4.0 Beta 2 last night. When I restarted my laptop, I noticed that both the Microsoft Online Services Sign-In app and the Curse-Gaming Client crashed. When I tried to start them manually, the same thing happened.

There were no errors in the Event viewer and no log files, so there was no obvious reasoning. Repairing the .NET 4.0 and .NET 3.5 SP1 installations didn’t fix anything either. The only clue I had was from trying to debug the crash in Visual Studio when prompted by Windows. Even then, the error was still cryptic: The type initializer for 'MS.Win32.Penimc.UnsafeNativeMethods' threw an exception.

Several Google searches later, I found the following fix:

  1. Run Command Prompt as Administrator.
  2. cd \windows\microsoft.net\framework\v3.0\wpf
  3. regsvr32 PenIMC.dll
  4. cd \windows\microsoft.net\framework\v4.0.21006\wpf
  5. regsvr32 PenIMC.dll

Once that was done, I was able to run both applications without error.

IncaBlocks Releases on Xbox Live Indie Games!

October 14, 2009
IncaBlocks

I’m proud to announce that today IncaBlocks, FuncWorks‘ first game, released on the Xbox Live Indie Games marketplace. It’s a block-stacking family board game for 1-4 players.

This represents a few months’ work on the part of Mike, Cicelie, and myself (you can read more over on Mike’s blog), and it’s exciting that it’s finally paid off. It’s amazing to think that code I wrote is not only running on a real game console, it’s being sold on Microsoft’s online service.

So if you have a 360, please check it out. There’s a free trial available, and the full game is just 80 points ($1). And if you like it, rating it would be much appreciated!

The Value of Cross-Training

November 3, 2008

While my job focuses on ASP.NET development, I still find myself going back to Python and SnakeSkin for personal web development projects. There’s really two reasons for this. One, I’ve got a pretty nice Linux virtual server hosting account through OpenHosting, so hosting on Apache gives me a lot of freedom. Two, I like the fact that it’s a bit lower-level than ASP.NET (so I’m a little closer to the HTML code) and not as opinionated as an MVC framework like Rails or CakePHP. Three, real men code in vi from the command line.

One of the great strengths of SnakeSkin/Albatross is its handling of form and session state. It’s roughly equivalent to ASP.NET’s ViewState. However, this makes AJAX work a little tricky. When a form is submitted, the posted fields are validated against the original structure of the form on the page; if they don’t match, SnakeSkin throws an exception. Great for keeping spammers out of your contact forms–but not so hot for changing page structure on the fly. And for years, I’ve sort of had to deal with this limitation. Usually, my workaround was to use a separate controller that returned XML data, which I then used to update the page through JavaScript. Fine for small things (and certainly less bandwidth-intensive), but not convenient.

I could go into the complexity of the problem even more, but it boils down to this: you can’t easily update one portion of the page directly. It’s all-or-nothing.

I eventually hit upon half of the solution to the problem a few months ago. If I updated an entire <form> tag in its entirety using prototype’s Ajax.Updater, then the form data would remain intact, and wouldn’t break when I submitted it again. But this was a very limiting solution. If you used multiple <form> tags on a page, then their session state (stored in hidden fields) would get out of sync as you updated each one individually. So, the only way to really make this solution work was to include only one <form> tag on the page. And if you’re doing that, you might as well not use AJAX at all.

It took some time, but the solution finally hit me. It was during Wally McClure‘s ASP.NET AJAX presentation at ETNUG. I had a pretty good idea of what was going on behind the scenes with ASP.NET AJAX, but I’d never really thought about it too much up to that point–the details were safely hidden from me in the Microsoft library, so there was no point in delving into the complexity.

But part of Wally’s presentation was to open up Fiddler and show the actual text of an ASP.NET AJAX response. The response contained the HTML code to be inserted into each UpdatePanel–which was pretty much what I expected. But it also included the updated ViewState as a separate field in the response. And that’s when it clicked.

All I had to do was modify SnakeSkin to spit out both the session state and the HTML response as part of an AJAX call. Then, when the response came in, I would iterate through the <input> tags on the page, and replace the contents of each hidden session state field. This didn’t require a lot of work on the back end (surprisingly, as I’d imagined the code to generate session state was hidden deep within the bowels of SnakeSkin), and only some minor tweaks on the front-end code I’d been using for AJAX.

So, last night, I actually got two-panel demo working. It’s obviously nowhere near as complicated as ASP.NET AJAX’s UpdatePanel–modifying my SnakeSkin page class to support updating multiple sections of the page in one call would just overcomplicate it at this point. But it is a somewhat elegant solution to the problem–that is to say, it’s encapsulated enough that the details of “how” are nearly invisible when you’re creating a page class.

I’ll post some samples if anyone’s interested, but SnakeSkin (and probably Albatross, the project it forked) is so obscure this doesn’t really matter to anyone but me.

The point is, I found it interesting that I solved a problem in one framework just by looking at another. I didn’t copy the solution directly, but it gave me a new way of looking at the problem. So, while you shouldn’t learn every framework, language, and platform out there, it helps to know more than one.

This is especially true in web development, because in a sense, web frameworks don’t matter. Every web application–every HTML-based application that is, since Flash and Silverlight aren’t constrained by the same limitations–is basically working with the same set of inputs, outputs, and limitations. From the user’s perspective, what you can do with one, you can do with any other framework, whether you’re using PHP or ASP.NET or Rails or SnakeSkin or Perl. Obviously, that doesn’t mean they’re all equally suited to every task. The value in the framework is on the back end–maintainability, productivity, data, and support. So as different as they are, all web frameworks can’t be that different in their fundamentals, which means it’s easier to compare, contrast, and borrow concepts in the web arena than it is on the desktop or server.

Outlining roles in maintaining a SharePoint site

October 7, 2008

I ran across an article today on SharePoint Magazine about Leveraging the SharePoint Platform. Overall, it’s a good (and realistic) discussion of how a SharePoint deployment must be planned supported within a company.

The section on people really stood out, because this was a point I made in my SharePoint presentation–if your deployment grows to any decent size, you can’t have just one person doing everything. Number of man-hours aside, it’s not reasonable for a single person to do configuration, administration, organization, development, and training. You’re trying to jump between a number of very different skillsets, so no matter how smart and capable your all-in-one SharePoint guy is, it’s not going to come out very good.

The article links to blog posts by Becky Isserman and Eric Harlan that attempt to define these roles a little more clearly. And for that reason, I think it’s a good read for anyone just getting started in a company that’s adopting SharePoint. Even if you won’t have a team of 4-6 people working on your SharePoint installation (and let’s face it, most people won’t), the division of skills is useful to divide up responsibilities between the team you do have–whatever size it is.

SharePoint Gotcha: Debugging Code Blocks and Event Handlers (or the lack thereof) in Site Pages

August 8, 2008

Here’s a problem one of the other developers here ran into–if you create your own site pages in SharePoint, you’re bound to see an error like this pop up:

An error occurred during the processing of /mypage.aspx. Code blocks are not allowed in this file.

… wait, what?

Yup, that’s what it says. You can’t use code blocks in ASPX files that are stored in SharePoint. No <% Response.Write("Hello World!") %>. No <%# Eval("Name") %>. As an added bonus, <asp:Button runat="server" ID="MyButton" OnClick="MyButton_Click" /> doesn’t even work because it declares an event handler.

That’s not really the gotcha here. This is well-documented in Inside Microsoft Windows SharePoint Services 3.0: check page 81, if you’re following along in your books at home. SharePoint has a very good reason for this security setting to be there: users can create and modify ASPX files that are stored within the SharePoint database. So, if you could run arbitrary code within an ASPX file, a user with no access to the server could potentially run malicious code.

So where does that code go? Well, it goes in the *.cs or *.vb code-behind file. That means to declare an event handler, you’re going to have to do something like this:

protected override void CreateChildControls()
{
    base.CreateChildControls();
    SaveButton.Click += SaveButton_Click;
    CancelButton.Click += CancelButton_Click;
}

And rather than displaying data in a GridView or Repeater using Eval() or Bind(), you have to give it an OnRowDataBound or OnItemDataBound handler. So that means, rather than doing this:

<asp:Repeater runat="server" ID="MyRepeater">
    <ItemTemplate>
        <asp:Literal runat="server" Text='<%# Eval("Name") %>' />
    </ItemTemplate>
</asp:Repeater>

You do this:

protected void MyRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    // Make sure we have a data item in this row
    if (e.Item.DataItem == null) { return; }

    // Convert the data item to its original type
    DataRowView dr = (DataRowView)e.Item.DataItem;

    // Find our literal control in the current repeater item
    Literal NameLiteral = e.Item.FindControl("NameLiteral") as Literal;

    // If it was found, set its value
    if (NameLiteral != null) { NameLiteral.Text = dr["Name"].ToString(); }
}

I can imagine you’re griping already. It’s easy to see the security reason for doing this–you don’t want users to be able to run arbitrary code on your server. But it’s so freaking complicated. (Well, it is until you get used to the idea.) But as I said, that’s not the real gotcha here. So what is the point of this post?

The real gotcha here is that this doesn’t seem to be a default security setting, at least in the development environments we’re using. (Andy’s using a VirtualPC image he set up himself; I’m using Microsoft’s WSS3 VirtualPC image.) We only ran into this issue after he tried to install a project on the client’s server.

I don’t think we’ve figured out exactly what turns on this security setting in SharePoint configuration, but I have found out how you can force your development environment to throw these sort of errors. All you have to do is dig into your development site’s web.config file and add the following node:

<configuration>
    <SharePoint>
        <SafeMode>
            <PageParserPaths>
                <PageParserPath VirtualPath="/*" CompilationMode="Always" AllowServerSideScript="false" IncludeSubFolders="true" />
            </PageParserPaths>
        </SafeMode>
    </SharePoint>
</configuration>

Once that’s done, you can now catch yourself using stuff that’s not allowed in ASPX pages before it gets to your client’s server.

How did I get started in software development?

July 13, 2008

OK, Mike just tagged me with this meme, so here we go:

How old were you when you started programming?

I was in 5th grade. (I don’t remember my age at the time, but if someone’s really interested, I can do the math.) I started out by typing in programs from 3-2-1 Contact magazine’s “BASIC Training” column into QBasic. QBasic has a pretty good help feature, so I just moved on from there. Oddly enough, my main drive was to learn how to program video games, which (obviously) never really happened.

What was your first language?

QBasic. I later ended up picking up another BASIC variation called ASIC (because you could compile it), and then Visual Basic 4 from there.

After several failed attempts to pick up other languages (Java, and basically whatever free compilers I could get my hands on), I got into web programming with Perl. From there I went to PHP, then Python (after I took a job with Mediapulse), and finally C#.

What was the first real program you wrote?

I can’t remember. I had a couple of little DOS games that I did in QBasic and ASIC that were pretty polished (relatively speaking).

In 8th grade, a friend and I created a customizable quiz program for a school project and we tried to sell that. It was in ASIC 1.0, which kind of sucked compared to QBasic. Didn’t sell a single copy, but I eventually wrote a more polished version with mouse support and color after ASIC 5.0 released.

If you knew then what you know now, would you have started programming?

Definitely. And I would have had a better idea of what the next step was after BASIC. (Hint: it wasn’t picking up a “Java by Example” book and trying to write graphical browser-based applets.)

Whether I would have made it my career, that’s a different story. Likely so, but I might not have felt as sure that it was what I needed to do. (More on that in the next item.)

If there is one thing you learned along the way that you would tell new developers, what would it be?

Software development is a business, just like any other. New developers tend to think they can solve all the world’s problems–simplifying and automating business processes, creating applications to manage data that’s currently sprawled across several Excel spreadsheets, and things like that. I know; I’ve been there. The reality is, things are like they are not because no one’s ever offered to box them up in a pretty little application. The problem is they’re either very complex problems, or they’re simple, but people don’t take the time and effort to streamline and fix them. And if you want to fix the problem, you’ll have to understand why it’s like that in the first place, or you’ll just be adding to it.

You will have to learn a little bit of business analysis. You will have to deal with people climbing the corporate ladder. It sucks, but just because you’re an IT geek doesn’t mean you get to live in a world full of nothing but code and idealism. You’ll be able to accomplish a lot more good if you prepare for this–just don’t get sucked into it.

What’s the most fun you’ve ever had … programming?

When I was at Mediapulse, they pulled me off of contract work to work on a product called DealStream. Basically, it was a web application that would let funds handle applications for funding. They pulled me in after doing all the high-level planning, so I got to refine the application process and figure out how it translated to a web application. Then I got to code it, and had a lot more leeway to do it right (since it was a product we’d be maintaining and reselling) and make it really customizable. I built the database, then created a Python module to handle the data and process (using a ORM library I’d written), tested the crap out of it (not actual unit tests, but I did step through every possible path in the process), and then built the web application. The great thing was, we’d been working with MySQL, Python, and Apache so long that we really knew our stuff, and so I streamlined deployment and configuration quite a bit.

I worked with our first client to refine it into something that met their needs. Once the first site launched, I took versioning very seriously, since every client had to have their own copy of the software deployed to our web server, and I wanted to avoid branching as much as possible for maintenance reasons. (It’s not a product if every instance of the software is a customized version.) I even started writing a full documentation of the object model.

It was one of those projects that I put a lot of effort into, and just turned out great. (Well, from my perspective; I’m not sure how well it actually sold after I left.) Every time I write JavaScript, I wish I had a copy of the code. I had some really sweet text validation and formatting functions in there.

Who am I calling out?

Since I’m not sure who reads my blog regularly, and Mike has called out most of the usual suspects, let’s go with…

Creating SharePoint Workflows with WSPBuilder and WSS

July 11, 2008

As I mentioned in my previous post, WSPBuilder is a great tool for SharePoint development. Between its built-in commands and its project templates, it takes a lot of the hassle out of setting up SharePoint configuration files for your features and solutions.

However, it’s a little tricky to get it working for workflows, especially if you’re using Windows SharePoint Services instead of MOSS. Here’s what I eventually worked out:

  • Make sure you’re using the “WSPBuilder Project with Workflow” template for your project. I made this mistake this first time through, and nothing worked.
  • Remove references to Microsoft.Office.* Pull out the “ReceiverClass” and “ReceiverAssembly” references in feature.xml; you don’t need them anyway for a basic workflow. (If you do, you can always add them in later.)
  • Remove the AssociationUrl, InstantiationUrl, and ModificationUrl attributes from elements.xml. You’ll need to add them back in if you create forms for this workflow, but not for a basic workflow.
×