Ananias introspection: Content Creation and Balance

This new series of blog posts will be based on /r/roguelikedev FAQ Fridays, a long standing series of discussions where roguelike developers share their techniques and experiences around a single topic.

FAQ Fridays Revisited # 6 Content Creation and Balance (original)

How do you decide what mobs/items/abilities/terrain/etc to add to your game? In any good roguelike content creation is inseparable from the concept of balance, so your methods of balancing content are certainly within the scope of this discussion.

Ananias has a fairly static collections of monster races. They were first added based on the original rogue monsters and with a single criteria on mind: each race should have an unique feature or ability.

Sometimes implementing an ability is costly and there’s the temptation of parameterizing it so it can be reused with slight variations, but I think it gives more character to the monsters having their distinctive skills. This means Ananias doesn’t have Ice, Fire, Water, Earth and Thunder dragons whose only distinction is the “type” of their attacks, I’d rather have a single Dragon monster distinguished by a strong ranged attack.

The uniqueness of an enemy race is not defined only by their active skills, their stats are also put in consideration. In this case they are assigned relative values first (i.e. orcs have high attack and medium hp, Lizardmen have extreme high attack and low hp). This is balanced so that races without cool active skills get some advantage stats-wise.

The dungeon is then split into 5 areas with increasing difficulty. Mob races are grouped thematically on these areas and then assigned final values for their stats by scaling their relative values to the difficulty level of the group they are in. In order to do this, I do a projection of the average stats for the player on each one of these areas and then I apply some simple general rules (for example, a strong monster may kill the player in 5 hits, a monster with low HP should be killed by the player in a single attack). These define ranges within which the stats of the final monster will be placed.

Items follow a similar model. For weapons and armor I started with a list of preexisting graphics (the artist made them on advance for a different game using his own creative criteria) then based on they appearance I assigned them relative values (high/mid/low) for damage and integrity (how likely they are to break), and then I grouped them on power tiers to define their final stats. They also get assigned a generation weight representing how likely they are to be added to the levels, this value is used in level generation along with the power tier to select the items to be added.

Player abilities are guided by the same principles of uniqueness. Ananias is strongly classed, and each class has unique passive skills that guide players into adapting different playstyles for each one. The process for player classes is similar as with the monster races, they are balanced based on their skills and relative values for their stats. (Except for the shepherd ;)).

On a final note, I’d like to say that while seeking to balance the different stats is worthwhile (to prevent your game from being utterly broken), it’s also to some point a futile exercise, since the variability of the game and the player’s choices create a lot of unpredictability, specially as journeys progress in games which provide long and open experiences. This is not necessarily a bad thing, and a little bit of unbalance is not always harmless since it allows the players to find strategies and challenges within the game.

 

A better build and deploy process for hybrid apps?

The current build and deploy process for Ananias takes a lot of time and requires lots of focus and bandwidth. Everything is done manually (and is thus prone to errors). Most of times I just can’t afford to release for all platforms, and I forget to announce thru all channels.

The cocoon.io parts are a bit cumbersome since they don’t have a CLI and it requires some back and forth, while also adding a dependency to an online service (for how long is it going to work?) I’m going to experiment with some native crosswalk builds to see if that step can be saved.

But probably what takes more time is the manual process to be done for each different storefront via its own web interface. Each one requires different info, and all uploads have to be started and monitored manually. It’s pretty uncommon for a store to supply a command line tool.

May be I should automatize parts of this? Someday I may do that, in any case it’d simplify packaging but wouldn’t make distribution any easier.

This is the current process executed for each new release of Ananias:

  • Mark the new version in the source code (client and server)
  • Generate a new JS bundle using browserify
  • Upload new build to web (ananiasgame.com/play) (About 15MB) (Only Standard edition)
  • Deploy new server version and restart (About 1MB) (including executing migration database scripts)
  • Use nwbuild to generate the executable packages for Windows, Mac and Linux
  • Rename the directories and zip them
  • Upload to itch.io via web interface (About 200MB )
  • Zip web directory
  • Update config on cocoon.io for next version
  • Upload web directory to cocoon.io (About 15MB)
  • Hit the build button on cocoon.io, wait for build to finish
  • Download APK packages from cocoon.io (About 150 MB)
  • Unzip package, copy release APKs (one per architecture, x86+arm7) to APK directory
  • Run script to sign and align APKs
  • Sign in to google play developers console
  • Upload both APK (About 100 MB)
  • Build change log from git commit messages
  • Summarize change log for Google Play
  • Upload both APKs to Amazon via web interface (About 100MB)
  • Upload to indiegamestand via web interface (About 200MB)
  • Upload to gamejolt via web interface (About 200MB) (Only Standard Edition)
  • Upload to IndieDB via web interface (About 200MB) (Only Standard Edition)
  • Set cocoon.io for iOS builds
  • Hit the build button, wait for build to finish
  • Download xcarchive (About 50MB)
  • Open xcarchive in xcode organizer
  • Submit to App Store
  • Wait for processing
  • Go to iTunes Connect
  • Go to Testflight / External Testing
  • Select new build to test
  • Wait for beta review
  • Go back to Testflight / External Testing
  • Set the new build as active.

The process should be executed twice, once for the Standard Edition and then again for the Fellowship edition.

THIS IS A LOT OF WORK. WHY CAN’T IT BE SIMPLER? This process takes out HOURS (Not exaggerating) of valuable and scarce development time for an Indie dev.

Why can’t I just simply update a single web endpoint, and have all the clients deal with the updating? they have to deal with it anyways, they just have to do it with their own, different store.

Also, the game is already multiplatform, if your platform has an HTML5 browser, like all modern platforms, you can play the game (Yes, you can even play the game on a PS4), then why go through all this?

I understand the advantages of having a downloaded app… people wants to feel they own the app, and they want to play their games while offline or in poor network conditions.

It would be awesome if the app could automatically check and download the updated scripts and required assets. This is not a new idea… some people has already tried but there are some obstacles:

  • Both Play Store and the AppStore are not very clear about their support of this model. You may be risking your app being taken down for not complying with the terms of service. They are also not MEANT to work like this, so you are always fighting against their nature.
  • For in-dev games, the player wouldn’t be notified a new version exists unless he runs the game or you implement some kind of push notifications.
  • The system has to work perfectly, if it doesn’t then your players will be stuck with an old version, or will be unable to play offline, or will end up with a malfunctioning app.
  • Another thing to consider is that this would prevent players from updating the web runtime in which the game runs, although I guess that may be fixed via a normal update.
  • If the player uninstalls the app or erases its data cache, they will have to redownload all assets.

There is a cordova plugin (cordova-app-loader) which adds support for “hot updates”. It seems to work but has some issues (based on what people reports). I don’t know of any similar tool for node-webkit / NW.js, I guess it’d have to be done manually.

Any thoughts?