Building an Adaptive Music System for a Dynamically Generated Game
by David Steinwedel, October 2007
Hellgate: London provides unique opportunities and challenges in implementing a successful, modern, adaptive music system. Below I’ll provide insight on the goals of Hellgate’s system, how a music ‘Set’ is built, how it is altered dynamically, and what we use to change it.
We set off with three basic but important goals for music in Hellgate: The music should not be repetitive, it should change dynamically with what the player is doing, and the player should not notice any sleight of hand used to achieve the first two goals.
Keeping it Varied—Music Sets from Building Blocks
The basic elements of a Music Set are full length loops called Full Mixes, which are divided into two categories: Action and Ambient. All Mixes in all categories are exactly the same length and tempo (or half/double time). Each Full Mix can have any number of Sub-Mixes (usually one) which are lighter variations of the Full Mix. Only one Mix is playing at any time.
We took this approach for a few reasons. First, it allows ambient and action cues to be drastically different from each other. In many adaptive music systems, separate tracks will stack, adding elements as the action changes. Having multiple interchangeable tracks allows more flexibility for the composer to try different things and gives better control over the final Mix (of both full and sub versions). So a typical Set would start off with four tracks:
A stinger is a one-shot sound that combines seamlessly with a playing Mix. Hellgate employs three types of stingers: Overlay, Interrupt, and Breakdown. Overlay Stingers fall transparently on top of the current Mix. Interrupt Stingers mute the current track while playing, effectively replacing a section of music. Breakdown Stingers pause the current Mix and continue it when the Stinger finishes, interjecting a new section of music and lengthening the Mix.
An Overlay Stinger
An Interrupt Stinger
A Breakdown Stinger
Stingers are used to smooth transitions when switching Mixes or to add variety to a Mix. They can be any length and are assignable to certain areas of a Mix. (An Interrupt stinger, for example, can be written for a specific portion of the track, or used for transitions only in certain areas.) This behavior keeps the music feeling natural as it transitions.
Each music Set has up to 25 or 30 stingers. A typical set might look like this (with multiple instances of each type of stinger):
Hellgate has a number of unique design elements that greatly affected how the music control system was built and hooked to the game. First is randomization—the game is completely randomized from top to bottom and, in a sense, we wanted music to follow this tradition. Second is that Hellgate’s fundamental client/server design limited our ability to use Level Zones, the Questing System, or AI as music controllers. We decided to work as best we could with the given design limitations and base our music control strictly on player actions.
To this end, we took whatever game stats we thought were valuable and created a scripting language to direct state changes in the music. Our system uses a series of If, Then, Else statements to ask questions about the game state and then evaluate what the music should do. Some of the most useful stats include:
If Music==Ambient && monsters_killed(32) >= 10 && monsters_pct_left() >= 50 && enemies_in_radius(50) >= 20 && ( hp_cur*100/hp_max ) >= 65 && rand(0,100) >= 50; then Music==Action; else …..
There is no game state that directly encapsulates ‘quickly and easily moving through a lot of monsters,’ so we examine what happens while playing the game to determine what combination of state values describes the situation. This script is saying (in order) that if the music is currently playing an ambient Mix, and you’ve been killing a lot of monsters lately, and there are a lot of monsters left both in the level and near you, and you’ve got most of your health left, then, pending a throw of the dice, switch the music to the action Mix. If any of those conditions fails, evaluate the next set of conditions.
We wrote a whole series of subroutines to handle moving in and out of each Mix for generic gameplay. Then we created routines to handle specific events, such as boss fights or special quests. As the game developed we found that each class played at a different pace, requiring subroutines balanced for each class. Failsafe systems were added (such as Max Playtime, so a track can’t stay on forever and Minimum Playtime, so a player can’t somehow trigger a ‘music mini game’).
A typical music script for one character class.
Does it Work?
Yes and no.
In terms of our goals, we met all of them to some degree. The music consistently changes and it does so based on the player. I’ve received comments from both users and developers indicating the sleight of hand works. “I was playing and really into it and all of a sudden I realized the music was blasting away! Where did it come from?”
However, there’s plenty that can be improved.
Since Hellgate can’t be pinned into a certain game category (is it an ARPG, FPS, MMO, or something else altogether?) and has customizable skill trees and over 100 viable weapons, it makes for an infinite number of play styles. Our system, which was scripted and balanced by one person, works well as long as you play the game somewhat like I do (a badass, nonstop killing machine). Stopping to inspect every item, playing tepidly, warping into town to sell loot, and tons of other actions can stop or slow the pace of the game enough to reset the system and keep music from working as intended.
Where our system shines is in micro-managing music. It allows for constant music cue changes according to the scope of a battle and how it’s going for the player. We can write cues and stingers for specific actions and conditions and switch to them instantaneously. As our audio programmer says, “It’s a good reactive music system.” And he’s right in most cases. However there are times when music needs to be proactive, looking ahead at what’s coming.
For the system to completely shine, we need to add a macro-level controller. For example, approaching a known battle in a pre-designed level would turn the music system on and start running a music script, which would then micro-control music for the encounter’s duration.
Such a design is never going to happen because it’s against Hellgate’s core design, so we’re working on other methods and technologies to do the same thing within our available toolset. Fortunately, we can continue to iterate on Hellgate: London and work our way to Music 2.0.