Inside the Box serves as a forum for individuals involved in the production of Gearbox Software content to share personal motives, methods, process and results. Gearbox Software projects are created by a diverse range of individuals spanning a spectrum of different backgrounds, interests, objectives and world views. The views and opinions expressed in this article are those of the author and do not necessarily reflect the official policy or position of Gearbox Software or any of its individual members outside of the author.
Hello again! It’s me, Keith Schuler, one of the Senior Designers on Borderlands 2. Previously, I wrote about implementing the plot mission “Hunting the Firehawk” but I ended that article right before the best part: the battle alongside Lilith. Today’s Inside the Box focuses on that combat encounter and developing Lilith’s role within it.
You might be surprised to learn that there were originally no plans to include Buddy AI anywhere in Borderlands 2. “Buddy AI”, in this case, describes an allied NPC that is able to prioritize targets and attack them. This is different from a character like Claptrap who simply follows a path, speaks lines, and plays animations. We had plenty of that going on, but since nobody had had the time to explore whether Buddy AI was feasible in Borderlands 2, it was simply taken off the table as an unnecessary development risk.
Lilith was my first step towards implementing Buddy AI, which would ultimately play an important role in Borderlands 2, and require Anthony Burch (Lead Writer) to rewrite a lot of mission dialog.
When I shifted from another project onto Borderlands 2, I decided to tackle “Hunting the Firehawk” first. Of the missions for which I was responsible, the level where this one took place was the most complete. This mission was also a lot simpler than something like “Where Angels Fear to Tread,” so it was a good place to get my feet wet and familiarize myself with the team, their processes, and the custom toolset.
The script had been written with Lilith playing a much smaller role in the battle than what we eventually shipped. The plan was for her to Phase Blast once for her intro, and to Phase Blast a second time to conclude the fight. That was it! The rest of the time, she was supposed to be out of the action. In fact, all of her lines were written with that plan in mind, and Level Designer Ryan Heaton had already roughed in a combat encounter and some effects for Lilith’s two Phase Blasts.
The scripting for Lilith’s intro had a group of bandits shooting at nothing and yelling about some invisible devil. Then, Lilith Phase Blasted into their midst and gibbed the lot of them. Her introductory Title Card was displayed, whereafter she collapsed from exhaustion. I decided to start polishing up that scene before diving into the rest of the combat.
Some bandits were already set up to target an invisible object in the back of the Firehawk Lair. They hated that thing more than anything else, but they were locked in position, so they could do nothing but shoot at it forever. A problem with this setup was that the gunfire could be heard, but the player could see no indication of where it was coming from. I was worried that the player might think he was being shot at from behind and look in the opposite direction of where we wanted him to be looking.
The first thing I tried to do was to move that invisible target around to the top of the stairs that led up to the main platform. This definitely improved things, because now the player could see the bandits’ tracer fire.
This helped to keep the player looking in the right direction, but it still had problems. The gunfire could be sporadic, depending on what random weapon the bandits spawned with, and the player had no idea what they were shooting at. I thought we could tell a better story, and attract even more of the player’s attention, if there were some kind of attention-grabbing effect to represent the Firehawk. As a placeholder, I used a floating purple particle effect that had been created for some other purpose. Once that was in, the setup felt more solid: it felt like there was already a battle going on at the Firehawk’s Lair as the player approached.
Once the final effects were in, it was unlikely that the player would look the wrong way:
I had two problems to solve now. The first was that the purple effect was in the players’ path and blocking their access to the platform. The second was that the bandits were shooting in the direction of the players, and those guys were high enough level to kill a player with a single stray bullet. (After all, we wanted to show Lilith destroying bandits that were bigger than anything the player had yet seen.)
To solve both problems, I decided to make the purple effect move to the back of the Firehawk Lair when players came near. The effect would be out of the way, and the bandits would turn to aim at it, saving the players from getting hit by any stray crossfire. How to move the effect, though? As an experiment, I tried attaching it to the actual Lilith NPC. I replaced her skin with a weird purple material, and scripted her to run to the back of the room. It worked great! Just when the player reached the stairs and was about to get a better look at her, I turned her invisible. At that point, a cutscene takes over and shows her Phase Blasting the bandits into hamburger. The entire scene worked beautifully.
True story: Originally this screen didn’t say “aka The Firehawk”. It was added after our focus testers repeatedly complained that they were never able to find this “Firehawk” the mission was telling them to look for. Anthony also rewrote one of Lilith’s lines to clarify the point.
Lilith Joins the Battle
I spent some time working on the bandit encounter, but there’s not much to tell about that. It’s a pretty simple fight, just spawning some psychos, marauders, and badass psychos in increasingly difficult waves. I didn’t change it very much from what Ryan had originally put in.
One thing that continued to bother me, though, was Lilith’s lack of participation. The other designers expressed the same feeling. Here she was, supposedly a major asskicker, but the only thing she did after the intro was to pop in at the end of the fight. Worse, her final Phase Blast was scripted to outright gib any bandit that was still alive, so she was also stealing kills and XP that rightfully belonged to the players. She was the worst kind of buddy in a fight: never around when you need ’em, then steals all the glory at the end.
Remembering how I had moved that purple effect by attaching it to Lilith and running her to the back of the room, I tried making her do that during the course of the battle. I wasn’t really trying to make her helpful yet; I just wanted to give her a visible presence. I thought maybe if the players could see her, then at least we would have the illusion that she was helping. Video games often engage in this sort of stage magic, and what the player thinks or feels is going on is really a careful and deliberate misdirection. (Smart wizards know that you shouldn’t put all that effort into actually making the city fly when a little sleight of hand will suffice.)
Lilith is just a regular NPC, which means she has no weapon or combat AI. Like Claptrap, she’s generally only capable of moving to points and playing effects and animations. It was fortunate, then, that she was only supposed to be using her Siren powers during this battle. In the first Borderlands game, her Phase Walk ability allowed her to move fast and unseen, then pop back into “the real world” with a damaging explosion. This was perfect for what I needed: I could teleport her to a starting point, run her to another location, then teleport her away. I’d script her to linger out of sight for a few seconds, then repeat the process over and over again until the battle was done. I didn’t need any AI for that: a simple bit of scripting that randomly selected one path at a time for her was sufficient.
When Lilith reaches the end of a path and teleports away, this is where she goes. That’s her platform in the distance. I just needed a place for her to chill when she isn’t near the player. This location was out of sight, couldn’t yet be reached by players, and required no changes to the level. It also kept Lilith conveniently close by for debugging purposes.
Now it felt (sort of) like Lilith was in the fight with the player. This presented a new problem, though. Since I was picking locations for her to land at random, she was constantly running all over the place with no rhyme or reason. It was painfully obvious that she didn’t care about the bandits, and the bandits didn’t care about her. This is a recurring issue when designing games: features that are a little “off” or unpolished usually stand out more than a feature that’s missing altogether. I had made the battle feel worse by adding Lilith to it.
As I tried to stifle that growing dread that a major defeat was impending, I tried to think of a ways to preserve the work I’d already done. Lilith running around was awesome whenever she happened to run near some bandits! I tried to think of a way to give Lilith combat AI when she had none, at a time when we’d been told “no buddy AI in Borderlands 2.” So, late one night, I tried another experiment. It looked like this in the editor:
See the green boxes? We call them Trigger Volumes, and each time any bandit touches one of them, the level scripting keeps track of it. Each box is associated with one of Lilith’s teleport destinations. When she’s ready to pop into view, she does so inside the volume most recently touched by a bandit. I gave the entire battle space coverage, and Viola! It was artificial Artificial Intelligence; no programming required! Lilith now looked like she understood where bandits were, and her Phase Blast looked like it was directed at them.
The bandits still didn’t care about her, though. Also, remember that her Phase Blast worked in a cheesy way: it just gibbed every living bandit. Lilith was now extremely effective at killing bandits. So much so, that a player would have a hard time killing even one of them! They could stand on the sidelines and let Lilith make mincemeat all day long. This was unacceptable. We want the player to feel like a badass, not like a spectator!
I solved this problem by changing the way her Phase Blast worked. Instead of a script just auto-gibbing every bandit in sight, I spawned an explosion at Lilith’s location when she teleported in. This killed two birds with one stone. The first was that I could balance the strength of the explosion and let the player carry some of the load. The second was that bandits could survive a hit from Lilith, which meant they might choose to target her. This resulted in some bandits trying to chase and attack her until she teleported away.
Now Lilith was present and participating, and she looked like a badass without stealing all the gameplay and XP from the player. At this point, I asked Anthony to write a bunch of new dialog for her: she could call out fresh attack waves, taunt bandits she killed, and praise the players when they got a kill. Once everything was in place, the battle felt much better than when we’d started.
The Aftermath: If a player decided to talk to Lilith before cleaning up the battlefield, she would teleport them away from their loot. To fix this, I added a “Warrior Earthquake”, which causes a platform to fall into place and gives the player a way to hop back down.
Pausing the Battle for A.W.O.L. Players
There was one final problem to deal with. If the players died during the battle, or even if they just walked back to the vending machines, then Lilith would keep fighting and talking to herself. This made Lilith’s lack of real AI obvious; it was also an exploit where the game would play itself until the battle was over.
My solution was to add another Trigger Volume; a box that encompassed the entire battle area. Every time Lilith wants to Phase Blast back into the fight, she checks whether there’s a player inside the volume. If there’s no player, then she just hangs out in an unreachable area. (See image above.) The battle won’t continue, and quite often the bandits will chase the player down because he is now the only valid target.
Ugh, I’d better wrap this up now. I just realized that I’ve written an Inside the Box article that literally mentions keeping players inside a box. I don’t trust myself to write anything further today. Thanks for reading! I hope you found this peek behind the curtain interesting… up until that last bit, anyway!