[Tutorial Series] Hime ATB #2: Customizing ATB Fill Rates
This tutorial is part of a tutorial series on Active Time Battle (ATB) System development. In this series, you will learn how to build your own ATB system from scratch, and add new functionality to create a unique battle system based on ATB.
At the end of the tutorial, you should have an ATB where the fill rates for each battler can be manipulated during battle.
Preparation
In this tutorial, we continue to build on the results from the first part, which lays out the foundations for an ATB system. If you haven’t read the first tutorial, I would highly recommend doing so in order to understand how it was designed.
You can get a copy of the base code that we will be using in this tutorial from here.
Re-Cap
In the first tutorial, we defined something called an “ATB Fill Rate”, which is basically how fast your active time bar filled up over-time.
We defined “time” in terms of frame updates, and therefore our fill rate is how much your ATB fills up per frames.
For simplicity, we assumed that the fill rate was simply 1, which means all battlers are able to perform actions in the same order, at the same rate. You can see it your code:
Game_Battler.prototype.atbFillRate = function() { return 1; };
Now, we will look at some ways to customize this fill rate so that we can have faster battlers performing more actions in the same amount of time compared to slower battlers. We will also look at ways to alter a battler’s fill rate during battle, such as applying states that affect the battler’s ATB.
When Can a Battler Perform an Action?
At this point, we have created a simple ATB that ranges from 0 to 100. These numbers were arbitrarily chosen in the first tutorial.
We have also defined a rule that says depending on the value of the ATB, the battler can either be waiting for their next action, or can execute an action. If the ATB is not full, then they must wait.
So now the question is, how can we make it so that “how long” a battler waits is affected by different factors?
Applying Agility to ATB
Let us define a rule that says the higher the agility parameter, the faster your ATB fills up. So for example, instead of increasing by 1 per frame, we increase by some value equal to the battler’s agility.
Now, you could write
Game_Battler.prototype.atbFillRate = function() { return this.agi; };
And that will work. However, what happens if your agi values average about 20, and your highest agi values could go beyond 100. If the ATB fill rate is equal to your agi, then someone with 100 agi would basically be performing immediately as long as the battle is running.
You would need to figure out a good way to balance the fill rate based on your game mechanics. You might have to increase the upperbound on the ATB, so that instead of ranging from 0 to 100, you might range from 0 to 1000. However, again if your average AGI value was 20, then waiting until it fills up to 1000 will take a long time.
For now, let us assume that our average AGI is 20, and can go up to 100. We will say that the fill rate is equal to a base rate of 1, plus 1 for every 10 points of AGI. This means that if you have zero AGI, you would still progress at a rate of 1 per frame, but everyone else would probably be progressing at a rate of 2 or 3 per frame.
Here is how it will look
Game_Battler.prototype.atbFillRate = function() { return 1 + this.agi / 10; };
It is up to you to determine how the fill rate will be calculated. I might even modify this method to split up into different parts:
Game_Battler.prototype.atbFillRate = function() { return this.baseAtbFillRate() + this.agiFillRate(); }; Game_Battler.prototype.baseAtbFillRate = function() { return 1; }; Game_Battler.prototype.agiFillRate = function() { return this.agi / 10; };
It is not necessary to abstract the method like this. Some programmers would even call it bad practice since it adds unnecessary performance overhead which in theory could slow down the game. From my point of view, this is more organized and if I needed to change certain parts of the code, it would be easier to do so.
Either way, it is up to you how you wish to structure your code.
Adding More ATB Modifiers
Let’s say we had a spell called “Slow” that slows down your ATB fill rate. There are several ways we can implement this.
One way is to have the spell add a state that increases the battler’s agility.
This approach requires no extra work on our end, because our fill rate formula already includes the battler’s agility. You can go ahead and create a state that will that cuts agility to 50%, and you should see it slow down a bit, but not by much, because our values are already relatively small compared to the base rate of 1.
Another approach would be to extend the method to include additional modifiers.
For example, you might define a method called “isSlowed”, which returns whether the battler is currently affected by a “slow” effect. You would then define what it means for a battler to be slowed (eg: maybe a state has been applied, or maybe they’re wearing some heavy equipment). We will assume that when state 12 is applied, then the battler is effectively “slowed”, and as a result of being slowed, their ATB fill rate is halved.
Game_Battler.prototype.isSlowed = function() { return this.isStateAffected(12); // assume 12 is "slow" state }; Game_Battler.prototype.applySlowAtbFillRateModifier = function(rate) { if (this.isSlowed()) { return rate / 2; } else { return rate; } }; Game_Battler.prototype.atbFillRate = function() { var rate = this.baseAtbFillRate() + this.agiFillRate(); rate = this.applySlowAtbFillRateModifier(rate); return rate; };
Would there be any advantage to writing it out this way? Maybe. If you wanted the status window to change the color of the bar depending on any special effects, you could simply query the battler for any modifiers like whether they’re slowed or not. Let’s take a look at how that might look in our own AT bars.
Customizing AT Bars based on Battler Effects
In the first tutorial, we put together some simple bars so that we could visualize it instead of printing it to the console. Here’s the code we wrote:
Window_BattleStatus.prototype.drawActorAtb = function(actor, x, y, width) { width = width || 186; var color1 = this.hpGaugeColor1(); var color2 = this.hpGaugeColor2(); this.drawGauge(x, y, width, actor.atbRate(), color1, color2); this.changeTextColor(this.systemColor()); this.drawText("ATB", x, y, 44); };
We just picked some arbitrary colors and moved on, because all we needed was something to show.
Now, if we want to do a conditional check to determine which bars to show, we can just use a conditional branch:
Window_BattleStatus.prototype.drawActorAtb = function(actor, x, y, width) { var color1; var color2; width = width || 186; if (actor.isSlowed()) { color1 = 'rgb(0, 128, 0)'; color2 = 'rgb(0, 224, 0)'; } else { color1 = this.hpGaugeColor1(); color2 = this.hpGaugeColor2(); } this.drawGauge(x, y, width, actor.atbRate(), color1, color2); this.changeTextColor(this.systemColor()); this.drawText("ATB", x, y, 44); };
Summary
That’s about it for customizing fill rates. The game updates the battler’s ATB once per frame, increasing it by the fill rate for that battler. By providing different values for the fill rate, you can change the order that battlers perform actions in battle. You can then create mechanics centered around this idea, allowing players to include this in their strategy when they take on enemies.
You might notice that in the video, I had a state called “Haste” which sped up my battlers. I will leave that up to you to figure out.
A copy of the code from this tutorial can be found here, and includes sample implementation for “haste” modifiers.
Feedback
Do you have any questions or comments? Perhaps there is something that is unclear, or could be implemented in a better way? Let me know in the comments!
Share the Tutorial
If you know anyone that is interested in writing battle systems for RPG Maker, share this with them!
You can also follow me on Twitter, Facebook, or Youtube for the latest posts and videos.
Support HimeWorks
If you would like to support me in writing these tutorials, you can put in a monthly pledge on Patreon! Every little bit helps, and becoming a supporter allows you to gain access to some exclusive content like development logs/rants, closed beta tests, and other things that I offer.