ATB Engine Script
Authors: Longfellow
Version: 1.00
Type: Battle System Component
Key Term: Scripting Tool
IntroductionThis is a script utility to simplify the construction of ATB battle systems. Use it if you want.
Features
- Simple API, very easy to use
- Powerful, makes full use of the Object-Oriented paradigm
- Completely stand-alone, other than the fact that it does nothing on its own
Screenshotsn/a
ScriptThis script is for scripters only, and thus I needn't tell you where it should go:
#============================================================================================
# ** ATB
#============================================================================================
module ATB
#========================================================================================
# * Group
#----------------------------------------------------------------------------------------
# Group is a simple subclass of Array, meant to be used to hold clients and
# update them easily. Can also be overwritten to alter methods such as modifier,
# which allows for much more flexible control.
#========================================================================================
class Group < Array
#------------------------------------------------------------------------------------
# modifier
#------------------------------------------------------------------------------------
def modifier
return 1.0
end
#------------------------------------------------------------------------------------
# update
#------------------------------------------------------------------------------------
def update(mod = 1.0)
self.each do |c|
c.update self.modifier * mod
end
end
end
#========================================================================================
# * Client
#----------------------------------------------------------------------------------------
# This is a custom-written class that can be used both on its own and as a
# a superclass for more specialized client classes. It holds data on ATB state
# and the callback that should be called when the client's ATB bar has filled.
#========================================================================================
class Client
attr_accessor :rate, :progress, :callback
#------------------------------------------------------------------------------------
# initialize(rate)
#------------------------------------------------------------------------------------
def initialize rate
@rate = rate
@progress = 0
@callback = Proc.new
end
#------------------------------------------------------------------------------------
# modifier
# - This method is called by Client#update to dynamically generate
# the rate modifier for the client.
# - This can be overwritten by subclasses to allow for interesting effects,
# i.e. lowering the speed of a character when their HP/MP is low, etc
# - Defaults to simply returning 1.0.
#------------------------------------------------------------------------------------
def modifier
return 1.0
end
#------------------------------------------------------------------------------------
# variance
# - This method is called by Client#upate to dynamically generate the
# amount of variance for the ATB update.
# - This can be overwritten by subclasses to allow for interesting effects,
# i.e. significantly boosting the maximum variance for actors with high luck
# - Defaults to adding or subtracting up to 1 TP from the client.
#------------------------------------------------------------------------------------
def variance
return (rand(21) - 10) / 10
end
#------------------------------------------------------------------------------------
# update
#------------------------------------------------------------------------------------
def update mod = 1.0
@progress += @rate * self.modifier * mod
@progress += self.variance
if @progress >= 100
@callback.call self
@progress = 0
end
end
end
end
InstructionsThis scriptlet has a single function: Simplify the "Active Time" part of "Active Time Battle." To achieve this, it uses two classes: ATB::Group, and ATB::Client.
ATB::Group is a subclass of Array that allows for updating of held clients and has support for advanced subclassing tricks (namely, overwriting ATB::Group#modifier to dynamically change the rate at which clients update), and you use it exactly the same as Array except for the presence of Group#update, which you call every time you want to update the clients in the group.
ATB::Client is a custom class I wrote that holds data on an ATB "client," which is one of the battlers or actions involved in the ATB that has something to do and a rate at which it prepares to do it. To create one, you call ATB::Client.new with one argument, which is the rate that it should prepare at in percentage. In addition, you pass a block that takes the client as an argument. This block is called when the client finishes preparing.
client = ATB::Client.new(1.0) do |client|
client.rate = 0 # Client stops doing things when it does the first thing
end
When creating your ATB, you will simply use these two classes to handle the ATB interactions - create groups and clients for your enemies and actors, and update them accordingly.
CompatibilityUnless you declared an ATB constant somewhere, it'll be fine.
Credits and Thanks
- Blizzard, for being Blizzard
- Willy Wonka, for his amazing taffy
Author's Notesn/a
HOLY SHIT, 90 LINES! I LOVE YOU! :cclove:
...you know it's only for the ATB engine, no actual Battle System code, right?
but I do like this part:
(@count = 0 ; @progress += 1) if @count >= @rate.round
... -_- I just noticed. I thought this would be enough to add into the editor plus a few lines of code and voila, there goes a new ATB.
This can still reduce the code for one quite a bit.
Sorry I'm a dissappointment, Blizz :(
No, not at all. You created an engine, this isn't "nothing". That means you had to consider and plan in advance. You had to analyze the system and how it works in order to create a versatile piece of code that is supposed to work with "anything". Show me another scripter who has done the same and you'll know that you found an equal. You will find out that only the "better" scripters have done or are able to do something like this.
That's what happens to you after two years of constantly modding Ubuntutu.
whats atb?
active time battle system.
Neat. I'm certain someone will find good use for it.
I wish I understood this more to make my own ATB... ;_____;
Quote from: Aqua on October 14, 2009, 06:46:24 pm
I wish I understood this more to make my own ATB... ;_____;
To be honest, I'm not even sure this works... Lemme write up something new to replace this, 'kay? :P
And here it is...
class ATB
class Group
attr_accessor :modifier
def initialize
@clients = []
@modifier = 1.0
end
def add_client client
@clients.push client
end
def empty
@clients = []
end
def update(mod = 1.0)
@clients.each do |c|
c.update(@modifier * mod)
end
end
end
class Client
attr_accessor :modifier, :callback, :rate
def initialize(rate, mod = 1.0)
@rate = rate
@modifier = mod
@callback = Proc.new
@count = 0
end
def update(mod = 1.0)
@count += rate * @modifier * mod
if @count >= 100
@callback.call(self)
@count = 0
end
end
end
def initialize
@groups = []
end
def add_group g
@groups.push g
end
def empty
@groups = 0
end
def update
@groups.each do |g|
g.upate
end
end
end
To use it, you create an ATB handler with ATB.new, then populate it with however many groups you need (at least one). Each group is just a way to handle clients conveniently; you can start or stop all members of a group by setting that group's modifier to 0.0. Then, you populate each group with whatever clients by creating them like so:
# You give .new an argument of the client's "rate," or what percentage of their bar should fill each update.
# You can also preset the "modifier" setting here; it is a multiplier used on the rate each frame.
c = ATB::Client.new(3) do |atb_client|
print "Hello, world!\n"
end
# You also give it a callback, which is called, obviously enough, back by the ATB engine when the bar is filled.
# The block is passed with the client as an argument, allowing
# you to reconfigure the client is need at the end of an action (say,
# setting their modified to 0 so they won't move until you want them to)
Simple enough, don't you think?
EDIT: Blah, ATB::Group should be a subclass of Array. Here you go:
class ATB < Array
class Group < Array
attr_accessor :modifier
def initialize(mod = 1.0)
super()
@modifier = mod
end
def update(mod = 1.0)
self.each do |c|
c.update @modifier * mod
end
end
end
class Client
attr_accessor :modifier, :callback, :rate
def initialize(rate, mod = 1.0)
@rate = rate
@modifier = mod
@callback = Proc.new
@count = 0
end
def update(mod = 1.0)
@count += rate * mod
if @count >= 100
@callback.call(self)
@count = 0
end
end
end
def initialize
@groups = []
end
def add_group g
@groups.push g
end
def remove_group g
@groups.delete g
end
def empty
@groups = 0
end
def update
@groups.each do |g|
g.upate
end
end
end
I appreciate you doing this :)
Just to be sure...
This only handles the actual time counting of the ATB, right?
Quote from: Aqua on October 14, 2009, 09:41:41 pm
I appreciate you doing this :)
Just to be sure...
This only handles the actual time counting of the ATB, right?
Yep, but it standardizes it and gives you a clean API for it. This makes it much easier to create ATB-centric effects; the version I'm about to release emphasizes that.
ATB doesn't have to be a subclass of Array. Also, I think you're kinda overcomplicating this.
Quote from: Blizzard on October 15, 2009, 04:39:47 am
ATB doesn't have to be a subclass of Array. Also, I think you're kinda overcomplicating this.
That version is outdated :/