As the main theme of ECATB is to give you as much control and freedom as possible while still keeping it as user-friendly as possible, while the reality is that you can easily get lost in its gigantic user configurations, this tutorial is made. Although fully utilizing ECATB needs decent scripting proficiency, it still tries to target as many of you as possible, so this tutorial is divided into various levels targeting users with various scripting proficiencies. If you think you belong to level x, you're advised to read from Level 1 to Level x, although you might learn something extra if you read Level x + y as well. Bear in mind that you can always freely ask me for help, so it's ok if you still can't figure out things yourselves even after reading this tutorial. I'll try to give you a working answers for your needs, and I'll even try to explain how things work if you want.

Level 1(No scripting proficiency)

I'm sorry to say that ECATB can only give you really limited control and freedom, but that doesn't mean you won't be able to use ECATB at all. I hope the below guidelines can help you at least a bit.

 

1. Check every last bit of the core feature
It's because ECATB won't function properly as a decent atb system without it. For example, without <ecatb rate: RX> notetags, all battlers will use the same base atb fill rate, effectively killing the essence of any atb system.

 

2. Learn from the instructions
While being able to follow the instructions are excellent, being able to learn from them is even better.
While learning something like this would be way too advanced for you:

# Mutliplies the atb fill rate by the battler's agi / all battlers'
    # average agi
    # all battlers is def_sum_battlers
    R1 = %Q(#{R0}base[1][:val] * agi * base[1][:size] / base[1][:sum][:agi])
# Checks if the member is charging the party escape
    ECC1 = -> member { member.ecatb_esc }
You can still learn some of the basics like:
# Sets the action cost as x
    AC1 = %Q(x)

    # Sets the action cost as the value of variable with id x
    AC2 = %Q($game_variables[x])
You should be able to learn that x in AC1 is a variable in mathematics and it needs to be substituted with valid values, and $game_variables[x] in AC2 is the value of variable with id x.
The same applies to these:
# Sets the atb bar colors as text color c and r, g, b, a rgba values
    C1 = %Q(Colour.text_colour(c))

    # Sets the atb bar colors as r, g, b, a rgba values
    C2 = %Q(Color.new(r, g, b, a))
# Sets the force action cost as the state of switch with id x
    FAC3 = %Q($game_switches[x])
# Sets the battler ready se as se with name "name", volume volume and pitch
    # pitch
    SERA1 = %Q(RPG::SE.new("file", volume, pitch))
You should be able to learn that Colour.text_colour( c ) is the text color c and Color.new(r, g, b, a) is the color with r, g, b, a rgba values; You should also be able to learn that $game_switches[x] in FAC3 is the state of switch with id x; You should be able to learn that RPG::SE.new("file", volume, pitch) is SE using file with name file, volume volume and pitch pitch as well.

 

3. Don't worry too much about things you can't understand yet
For example, it's completely ok if you don't know what information like the below means:

# RX are used at:
    # 1. Game_BattlerBase
    #    - @ecatb_notes[:rate].each { |rate| eval(rate) } in ecatb_gain_rate
# Its corresponding method's created under BattleManager
As you can't use them yet anyway. They're for those having at least some scripting proficiency, and you can still use the basics without even bothering them.

 

4. Don't worry too much about using script calls
Although being able to use script calls is a prerequisite of using ECATB, doing so actually needs little scripting proficiency and you don't have that yet. Although quite some features can only be done via script calls, you can still use many of its basics. If you want to use them anyway, you can either learning the scripting basics, or ask me for help.

 

5. Don't be afraid of testing the configuration and notetag values
While you should have at least a vague idea after reading the instructions, you'll have to actually test them to check their effects yourselves in order to really understand what they do. As long as you stick to only using what you know, their effects shouldn't confuse you too much. For example:

# Sets the battler sprite atb bar text x and y positions
      # Its corresponding method's created under Game_Battler
      # It must return an array of real numbers and should return an array of
      # integers
      # Example: To set the battler sprite atb bar x and y positions as the
      #          values of variables with id x and y respectively, set this as
      #          %Q(%Q([$game_variables[x], $game_variables[y]]))
      :ecatb_bar_text_xy => %Q(%Q([-1, -7])),
Even I, the ECATB author, will have to test several times in order to get a suitable value for me, so if you're unsure what the effects of those values are, just test them and you'll probably know better.


Level 2(Little scripting proficiency)

As you know the Ruby basics like basic syntax and concepts and have at least a bit of basic Ruby coding experience, you should be able to use most, if not all, script calls listed in the Script Call Info.
Also, as you shouldn't be new to reading and writing basic Ruby codes, you should be able to use them as configuration or notetag values.
ECATB can still only give you limited control and freedom, however, as you can't use advanced RGSS3 codes yet. Nevertheless, I hope that the below guidelines can help you at least a bit.

 

1. Thinking of the script call contexts
While some script calls like this has only 1 context:

#    1. $game_system.set_battle_system(:system)                                |
#       - Changes the battle system to those supported by                      |
#         Yanfly Engine Ace - Ace Battle Engine                                |
#       - It can only be used outside battles
Some like this has more:
#    7. ecatb_reset(boolean)                                                   |
#       - Cancels the battler's charging actions                               |
#       - The battler's atb and action points will be reset as well if boolean |
#         is true                                                              |
#       - It applies to all battlers belonging to Game_Battler                 |
It can be used in damage formulae like this:
act = b.ecatb_act_times; b.ecatb_reset(true); a.ecatb_act_times += act; damage_formula # Take all the action points from the target to the user
It can also be used in script calls like this:
$game_troop.members.each { |member| member.ecatb_reset } # Cancels all enemies' charging actions
Note the difference between the contexts of the above 2 examples.

 

2. Using string interpolations
While you should be able to use this technique already, I've to emphasize that it's extremely important for using ECATB effectively and efficiently, as almost all configuration and notetag values are stored in strings. For example, you should know what these mean:

# Don't edit this unless you understand what it does and how it works
    SV0 = %Q(@ecatb_val[:color] = )

    # Sets the starting atb value as x%
    SV1 = %Q(#{SV0}x)
# Sets the action cost as x
    AC1 = %Q(x)

    # Sets the action cost as the value of variable with id x
    AC2 = %Q($game_variables[x])

    # Sets the action cost as AC1 + AC2
    AC3 = %Q(#{AC1} + #{AC2})
While you're not expected to know what @ecatb_val[:color] is yet, you should at least know that %Q(#{SV0}x) is equal to %Q(@ecatb_val[:color] = x), and %Q(#{AC1} + #{AC2}) is equal to %Q(x + $game_variables[x]).
You may have noticed that the SVX and ACX are actually building blocks of notetag values, as they can be reused and become some parts of the whole by using string interpolations.
As they're constants which can't be changed once set, the more fundamental ones must be placed above the less fundamental ones. For example, SV0 must be placed above SV1 and AC1 and AC2 must be placed above AC3.

 

3. Using basic Ruby codes in configuration and notetag values
For example, you should know what simple Ruby codes like these mean:

# Sets the action cost as x
    AC1 = %Q($game_switches[x] ? $game_variables[y] : $game_variables[z])
:ecatb_pool_val => %Q(%Q(
        return 0 if vals.empty?
        avg = 0
        vals.each { |val| avg += val }
        avg / vals.size
      )),
AC1 returns the value of variable with id y and z if switch with id x is on and off respectively, while ecatb_pool_val returns the average of all values in vals.
Also, note that notetag values are RGSS3 codes to be evaluated upon usage by using eval, while almost all configuration values are strings of the method contents, and those methods are created on the fly by using eval. So writing notetag values are writing expressions(although they can be more than 1 lines), while writing most configuration values are writing method contents.

 

4. Validating the configuration and notetag values
While ECATB can check the validity of most configuration values for you, notetag values won't be checked as I don't know how to check them effectively and efficiently. So until I find such means if there's any, you'll have to check the validity of the notetag values yourselves. If you stick to only using the basic Ruby codes in notetag values, you should be able to use the information like this to check their validity:

# It must return an array
      # Its 1st element must return a positive real number and should return a
      # natural number
      # Its 2nd element must return either :tick or :act
Also, it'd be excellent if you check the validity of the configuration values yourselves as well, as the ECATB validity check isn't 100% fool proof.

 

5. Don't worry too much about learning how the default or custom RMVXA scripts work
While you know that information like these are to tell you where, when and how the configuration and notetag values are used(i.e., informing you the contexts behind those values):

# RX are used at:
    # 1. Game_BattlerBase
    #    - @ecatb_notes[:rate].each { |rate| eval(rate) } in ecatb_gain_rate
# Its corresponding method's created under BattleManager
You also know that you need to understand the mentioned parts to use the above information, and doing so is still likely beyond your current scripting proficiency. However, you can still use Ruby codes that work under any context by only using globally available elements like global variables.


Level 3(Some scripting proficiency)

As you should have a basic understanding of how the default RMVXA scripts work(at least the battle related parts) and should have some actual scripting experience(you've probably released at least few simple original scripts), you should be able to use all but the most advanced ECATB features.
Also, as you should be able to read others' custom scripts, you should be able to read the ECATB implementations locally(i.e., specific methods) and have at least a vague idea about what they do locally. You're not needed to understand them or read the ECATB implementations globally(i.e., as a whole).
Although you still don't have the full control and freedom ECATB gives yet, I hope that the below guidelines can help you at least a bit.

 

1. Read the contexts of the configuration and notetag values
While you're not needed to understand those contexts, you should at least have a vague idea about them. For example:

# RX are used at:
    # 1. Game_BattlerBase
    #    - @ecatb_notes[:rate].each { |rate| eval(rate) } in ecatb_gain_rate
# Its corresponding method's created under BattleManager
The former tells you that your RX must work in ecatb_gain_rate, and the latter tells you that your method contents must work under BattleManager. While you're not expected to fully utilize new methods and/or variables in ECATB yet, you should at least be able to use the ones in the default RMVXA scripts. You should also be able to tell if your configuration and notetag values are valid in the mentioned contexts as long as you know what those values are.

 

2. Use the default RMVXA script methods and variables
For example, you should know what these mean:

# Checks if the party command window is active
    WC5 = %Q(@party_command_window.active)

    # Checks if the actor target window is active
    WC6 = %Q(@actor_window.active)

    # Checks if the enemy target window is active
    WC7 = %Q(@enemy_window.active)

    # Checks if the skill window is active
    WC8 = %Q(@skill_window.active)

    # Checks if the item window is active
    WC9 = %Q(@item_window.active)

    # Checks if the actor command window is active
    WC10 = %Q(@actor_command_window.active)
:ecatb_battler_count => %Q(%Q($game_party.alive_members.size + 
                                    $game_troop.alive_members.size)),
# It must return an array of battlers
# Sets the battler methods to use the unison method rules
    # It must be a hash of strings of the battler method arguments
    # Its keys must be the battler method name symbols
    # Methods with name method_name will be aliased to method_name_ecatb
    # Example: 
    UNISON_DEFS = {

      # General Form:
      # [:method_class, :super_class] => {
      #   :method_name => "method_arguments"
      # }

      [:Game_BattlerBase] => {

        :param => "param_id"
        
        # Adds new methods here
        

      }
      
      # Adds new classes here
      

    }
You should also know where, when and how they're used, although you're not expected to understand the contexts behind them yet. Also, as some default RMVXA script methods are aliased or rewritten, you should note their behavior change before using them, to ensure you know what you're doing. Both aliased and rewritten methods are clearly stated by their documentations that they're aliased or rewritten respectively.

 

3. Understand the relations between the configuration and notetag values
For example, you should know how the below notetag and configuration values are related:

#--------------------------------------------------------------------------|
    #  Unison Method Rule Notetag Values                                       |
    #  - Setups UDRX used by <ecatb unison def rule: UDRX> notetags            |
    #--------------------------------------------------------------------------|
    # UDRX are used at:
    # 1. Game_BattlerBase
    #    - rule = eval(item.ecatb_unison_def_rule) in set_ecatb_unison_defs
    # UDRX are strings of RGSS3 codes
    # UDRX must return a symbol
    # You must implement the rule in ecatb_unison_rules
    # UDRX names can only use alphanumeric characters
    # The below UDRX are examples added to help you set your UDRX
    # You can freely use, rewrite and/or delete these examples

    # Adds new UDRX here
    

    # Sets the default unison method rule
    # It'll be used for def only if it's no UDRX to use
    # Example: To set the default unison mthod rule as returning the minimum,
    # set this as %Q(:min)
    ECATB_UNISON_DEF_RULE = %Q(:avg)

    # Sets the battler methods to use the unison method rules
    # It must be a hash of strings of the battler method arguments
    # Its keys must be the battler method name symbols
    # Methods with name method_name will be aliased to method_name_ecatb
    # Example: 
    UNISON_DEFS = {

      # General Form:
      # [:method_class, :super_class] => {
      #   :method_name => "method_arguments"
      # }

      [:Game_BattlerBase] => {

        :param => "param_id"
        
        # Adds new methods here
        

      }
      
      # Adds new classes here
      

    }

      # Implements the unison method rules
      # The unison method of all unison battlers can be referneced by vals
      # The unison method rule can be referenced by rule
      # Its corresponding method's created under Game_Battler
      # It must return a real number
      # Example: 
      :ecatb_unison_rules => %Q(%Q(
        if rule == :min
          vals.min
        elsif rule == :avg
          avg = 0
          vals.each { |val| avg += val }
          avg / vals.size
        elsif rule == :max
          vals.max
        else
          0
        end
      ))
UDRX set the method rule used by the skills/items using those UDRX, UNISON_DEFS sets all methods under their classes that can use the unison method rules, and ecatb_unison_rules sets all unison method rules that can be used by UDRX and UNISON_DEFS. There are quite some other configuration and notetag values that are related, and some ECATB features can only be used via using those relations. Unfortunately, some relations are rather elusive and using some of the relations needs decent scripting proficiency, in which you don't have yet. But you can still ask me for using those relations you found.

 

4. Reading ECATB new methods and variables
While you're not expected to understand them yet, you should at least have a vague idea about them. The documentations should help you at least a bit:

#    2. Method documentation                                                   |
#       - The 1st part informs whether the method's rewritten, aliased or new  |
#       - The 2nd part describes what the method does for new methods only     |
#       - The 3rd part describes what the arguments of the method are          |
#       - The 4th part describes how this method works for new methods only,   |
#         and describes the parts added or rewritten for rewritten or aliased  |
#         methods only                                                         |
#       Example:                                                               |
# #----------------------------------------------------------------------------|
# #  Rewrite/Alias/New method: def_name                                        |
# #  - What this method does                                                   |
# #----------------------------------------------------------------------------|
# # *args: What these arguments are                                            |
# def def_name(*args)                                                          |
#   # How this method works                                                    |
#   def_name_code                                                              |
#   #                                                                          |
# end # def_name                                                               |
For example:
#----------------------------------------------------------------------------|
  #  New method: exec_ecatb_act_cost                                           |
  #  - Sets the action cost and atb reset value                                |
  #----------------------------------------------------------------------------|
  # forced: The action force flag
  def exec_ecatb_act_cost(forced)
    return unless current_action && current_action.item
    force_act_cost = eval(current_action.item.ecatb_force_act_cost)
    if !forced || force_act_cost
      # Sets the action cost if charge prior action cost is true
      if eval(current_action.item.ecatb_charge_prior_act_cost)
        if @ecatb_unison_actors.size > 1
          @ecatb_unison_actors.each(
          &DoubleX_RMVXA::ECATB::BLOCK[:exec_ecatb_act_cost])
        else
          pay_ecatb_act_cost
        end
      end
      #
      # Sets the atb reset value
      set_ecatb_reset_val
      #
    end
    force_act_cost
  end # exec_ecatb_act_cost
attr_reader :ecatb_act_times # Stores the number of action points
You should at least know that exec_ecatb_act_cost sets the battler's action cost and atb reset value and @ecatb_act_times stores the number of action points of its battler, although you're not expected to understand how exec_ecatb_act_cost works yet. Now you should have a better idea of how to set FACX and CPACX(like what new methods and variables can be used), although fully comprehending their contexts are still likely beyond your scripting proficiency. Just bear in mind that you only need to focus on figuring out what a new method/variable does and how you can use it.

 

5. Using new methods set by you
You should already know that the configuration values are actually method contents, and the method name is actually the configuration name. You should also know that those methods are created on the fly. So you can actually use them in notetag values or even other configuration values. For example:

:pre_ecatb_update => %Q(%Q(
        BattleManager.ecatb_def_sum_battlers.each { |battler|
          [:color, :charge, :cooldown].each { |type| battler.ecatb_note_change[type] = true }
        }
      )),
The above allows all battlers' atb, charge and cooldown bar colors to be different per frame. Note that pre_ecatb_update uses the configuration value ecatb_def_sum_battlers and the script call ecatb_note_change[note] = true. The above must be used if you want the atb, charge and cooldown bar colors to be different per frame.
By thinking and experimenting how to mix new methods, script calls and notetag value expressions together, you might end up finding new relations between some of them.


Level 4(Decent scripting proficiency)

As you've quite a lot of scripting experience and have probably written at least dozens of really useful scripts, you should have little trouble understanding others' custom scripts locally(i.e. method level). Also, as you've a solid understanding of how the default RMVXA scripts work(at least the battle related parts), you should've little trouble understanding how the default RMVXA battle system works as well. So you should be able to almost fully use the control and freedom ECATB gives. You'll still probably gain from reading the below guidelines, however, as they should help you better understanding ECATB implementations locally more effectively and efficiently. Nevertheless, you're not expected to understand ECATB globally yet.

 

1. Using anonymous functions
Specifically, you should know how to use this:

anonymous_function = -> iterator { block }
iterator_method(&anonymous_function)
Which is the same as this:
iterator_method { |iterator| block }
It's because it's an extremely important optimization technique used in ECATB. For example:
# Checks if the member is charging the party escape
    ECC1 = -> member { member.ecatb_esc }
# Checks if the member has fully charged a skill/item
    EEC1 = -> member { member.ecatb_val[:charge] >= 100.0 }
You should know what they do, how to use them and what their limitations are.
You'll find that the ECATB implementations uses anonymous functions heavily. For example, the constant BLOCK in the ECATB implementation part of DoubleX_RMVXA::ECATB is an array of anonymous functions.

 

2. Understanding new methods and variables
While you're not expected to understand ECATB as a whole yet, you should be able to understand any new method and variable in ECATB locally. For example, you should understand what the below does, how they work and how to use them:

# Mutliplies the atb fill rate by the battler's agi / all battlers'
    # average agi
    # all battlers is def_sum_battlers
    R1 = %Q(#{R0}base[1][:val] * agi * base[1][:size] / base[1][:sum][:agi])
#----------------------------------------------------------------------------|
  #  New method: ecatb_gain_rate                                               |
  #  - Returns the atb gain value per frame                                    |
  #----------------------------------------------------------------------------|
  def ecatb_gain_rate
    base = update_ecatb_base
    # Reevaluates the atb rate only if any of its components' changed
    if base[0] || ecatb_battler_change?(:rate)
      set_ecatb_rate
      @ecatb_notes[:rate].each { |rate| eval(rate) }
      @ecatb_rate[:color] = base[1][:val]
    end
    #
    @ecatb_rate[:color]
  end # ecatb_gain_rate
#----------------------------------------------------------------------------|
  #  New method: update_ecatb_base                                             |
  #  - Checks if the atb rate needs to be reevaluated                          |
  #----------------------------------------------------------------------------|
  def update_ecatb_base
    # Checks if the number of battlers, methods sums or the fill time's changed
    change = false
    types = {
      size: BattleManager.ecatb_def_sum_battlers.size,
      sum: BattleManager.ecatb_battlers_def_sums,
      val: 100.0 / (BattleManager.ecatb_base_fill_t * Graphics.frame_rate)
    }
    types.each { |key, val|
      next if @last_ecatb_base[key] == val
      @last_ecatb_base[key] = val
      change = true
    }
    [change, types]
    #
  end # update_ecatb_base
#----------------------------------------------------------------------------|
  #  New method: set_ecatb_rate                                                |
  #  - Sets the current atb gain rate when its notetags change                 |
  #----------------------------------------------------------------------------|
  def set_ecatb_rate
    # Updates the atb gain rate notetags using the current order
    @ecatb_notes[:rate] = []
    ecatb_rate_ord.each { |note|
      next unless send(@ecatb_item[note][0])
      set_ecatb_notes(send(@ecatb_item[note][1]), :rate, 1, true)
    }
    #
  end # set_ecatb_rate
You should know that @ecatb_notes[:rate] stores all <ecatb rate: RX> notetags used by the battler, @ecatb_rate[:color] is the cached result of all those evaluations, etc. Upon further understanding, you should understand how @ecatb_notes[:rate] stores those notetags by understanding set_ecatb_notes, and that understand is crucial for fully utilizing those notetags. You only need to focus on comprehending what a new method/variable does, how they work locally and how you can use them.

 

3. Understanding how to use other scripts along with ECATB
When using others' custom scripts' features with ECATB's ones, you've to pay extra attention on possible compatibility issues raised by your configuration and notetag values.
For example, with DoubleX RMVXA State Triggers, you can replicate the CATB Clear and parts of the CATB Countdown feature. Specifically:

# Sets the state trigger action as clearing its owner's atb value and action points
    STA1 = "ecatb_reset(true)"

    # Sets the state trigger action as clearing its owner's charging actions only
    STA2 = "ecatb_reset"

    # Sets the state trigger action as resetting its owner's charge value to x
    STA3 = "@ecatb_val[:charge] = x"

    # Sets the state trigger action as resetting its owner's cooldown value to x
    STA4 = "@ecatb_val[:cooldown] = x"

    # Sets the state trigger action as resetting its owner's action points as x
    STA5 = "ecatb_act_times = x"
You should understand what these STAX do, how they work and how to use them.
Another example(with DoubleX RMVXA Intercept Magic):
AC1 = %Q(states.any? { |state| state.intercept_tier > x } ? y : z)
AC1 returns y and z if the battler has and hasn't intercept states with tier above x respectively.
While you're not expected to know how other custom scripts interact with ECATB as a whole, you should be able to figure out how parts of other custom scripts interacts with parts of ECATB, and how you can use those interactions.

 

4. Using hidden script calls
Although the Script Calls Info already has a long script call list, there are actually some more ones that aren't mentioned. It's because they're not supposed to be used as script calls and doing so can easily cause chaos and/or crashes. But as you already have decent scripting proficiency, if you understand what they do, how they work locally and how to use them, you can still use them as long as utmost caution is exercised. For example:

attr_accessor :ecatb_refresh # Stores the refreshing calling flag
It's used to notify the windows(status window, status aid window, help window, actor window, cancel window, etc) that the battler's displayed information changed and needs to be redrawn. So calling battler.ecatb_refresh = true will redraw all those windows. But as you know, redrawing windows are expensive, redrawing them too frequently can cause significant average fps drop. So it should only be used when they need to be redrawn and those needs aren't covered by ECATB already. This can be the case when you use others' custom scripts that have those needs.
When using unmentioned script calls, you should always clearly know what you're doing and have clear reasons behind them, otherwise can will most likely end up wreaking havoc. But if you're lucky or smart, you might end up finding well-hidden ECATB capabilities which is even hidden to me, the ECATB author.

 

5. Don't be too insane on setting configuration and/or notetag values
While you've almost full control and freedom when using ECATB, ECATB itself can't give you unlimited control and freedom, so you should bear in mind that every configuration and notetag value has their limitations, and you should be able to find at least some of them. For example:
- While variable action costs are supported, random action costs aren't.
- Variable maximum atb/charge/cooldown values aren't supported, they're always 100.0.
- Changing battle systems during battles aren't supported.
There are more, but listing them all would be too exhaustive.
Also, always think of the performance impact when you set the configuration and notetag values. For example, the below value will extremely likely cause significant average fps drop:

# Sets something to happen right before updating the atb clock
      # Its corresponding method's created under Scene_Battle
      # Example: To support changing atb, charge and cooldown bar colors of all
      #          battlers per frame, set this as
      #          %Q(%Q(all_battle_members.each { |member|
      #                  member.ecatb_note_change[:color] = true
      #                }))
      :pre_ecatb_update => %Q(%Q(all_battle_members.each { |battler|
        battler.ecatb_refresh = true
      })),
After all, when you're trying to fully utilize ECATB, you're actually coding quite some parts of it, so the proper coding practices should be exercised to prevent making the configuration and notetag values out of your control. One especially important programming aspect you should always bear in mind is code performance, as ECATB needs extremely performant codes to work well.


Level 5(Advanced Scripting Proficiency)

This part is dedicated for those going to edit ECATB, write compatibility fixes and/or addons to it, and/or tweaking it to suit specific projects' needs. Other users don't need to read this part, but they might still learn something useful for using ECATB if they do read this part.
As you've been a scripting veteran for quite some time and has written at least 1 advanced complex script like a custom battle system, you can probably write an excellent atb system yourselves. Such capability is extremely useful for fully comprehending how ECATB works. With the below guidelines, you should be able to deal with the entire ECATB system as a whole.

 

1. Understand the design patterns
ECATB tries to conform to the MVC(Model View Controller) pattern. Specifically:
- DataManager, RPG::Actor, RPG::Class, RPG::Enemy, RPG::EquipItem, RPG::State, RPG::UsableItem and Game_System are almost entirely Data
- BattleManager are mainly Model although it's some Control functions
- Game_Action, Game_BattlerBase(closer to Data), Game_Battler(closer to Control), Game_Actor, Game_Enemy, Game_Party and Game_Troop are almost entirely Model
- Sprite_Battler, ECATB_Bar, ECATB_Clock_Bar, Window_ItemList, Window_BattleLog, Window_ActorCommand, Window_BattleStatus, Window_BattleActor, Window_BattleEnemy, ECATB_Clock_Window, ECATB_Force_Window and ECATB_Pool_Window are almost entirely View
- Scene_Battle is mainly Control, although it's some Model functions
ECATB also tries to be as compact as possible. For example:

# Stores create_ecatb_defs, check_ecatb_def and reset_ecatb_def under all
    # classes and modules having methods created using the configurations
    CHECK_RESET_DEF = {}
    [:BATTLEMANAGER, :GAME_BATTLER, :GAME_ACTOR, :GAME_PARTY_TROOP, 
    :WINDOW_BATTLESTATUS, :ECATB_CLOCK_WINDOW, :ECATB_CLOCK_BAR, 
    :ECATB_FORCE_WINDOW, :ECATB_POOL_WINDOW, :SCENE_BATTLE].each { |key|
      CHECK_RESET_DEF[key] = %Q(
  def create_ecatb_defs
    #{key == :GAME_ACTOR || key == :GAME_ENEMY ? "super" : ""}
    DoubleX_RMVXA::ECATB::#{key.id2name}.each_key { |config|
      create_ecatb_def(config)
    }
  end

  def check_ecatb_def(config, check)
    percent = act = ""
    cur_clock = max_clock = turn_count = index = rule = 0
    vals = []
    val = eval(config + check[0])
    reset_ecatb_def(config, check, "is invalid.") unless eval(check[1])
    #{RESCUE_CONFIG_VAL ? %Q(rescue
    reset_ecatb_def(config, check, "could crash the game.")) : ""}
  end

  def reset_ecatb_def(config, check, type)
    #{SUPPRESS_RESET_CONFIG_VAL_TEXT ? "" : %Q(msgbox("The value of " + 
    config + " is\n" + eval("$game_system." + config) + "\nwhich " + type))}
    eval("$game_system." + config + " = " + check[2])
    create_ecatb_def(config.to_sym, false)
    #{SUPPRESS_RESET_CONFIG_VAL_TEXT ? "" : %Q(msgbox(
    "Its value is reset to its default:\n" + eval(check[2])))}
  end
      )
    }
It's an abstract method creator and validator, which is somehow similar to an abstract factory.
Its concrete counterparts are implemented in classes registered in CHECK_RESET_DEF. For example:
#----------------------------------------------------------------------------|
  #  New method: create_ecatb_def                                              |
  #  - Creates a and checks that new method using configuration config         |
  #----------------------------------------------------------------------------|
  # config: The configuration used to create a new method
  #         It must be a string containing the name of a configuration
  # validate: The indicator of whether the configuration will be checked
  #           It should be either false or true
  def create_ecatb_def(config, validate = true)
    # Creates a new method with its contents being its configuration value
    method = config.id2name
    eval(%Q(
  def #{method}#{DoubleX_RMVXA::ECATB::BATTLEMANAGER[config][0]}
    #{eval("$game_system.#{method}")}
  end
    ))
    #
    # Checks if that new method can crash the game and returns a valid value
    return unless validate
    check_ecatb_def(method, DoubleX_RMVXA::ECATB::BATTLEMANAGER[config])
    #
  end # create_ecatb_def

  # Checks the new method and resets it to its default if it's invalid
  module_eval(DoubleX_RMVXA::ECATB::CHECK_RESET_DEF[:BATTLEMANAGER])
It's the concrete counterparts used by BattleManager.
Another abstract method aliasing generator is this:
# Aliases methods that use unison method rules
  DoubleX_RMVXA::ECATB::UNISON_DEFS.each { |klass, defs|
    defs.each { |name, args|
      name = name.id2name
      eval(%Q(
class #{klass[0].id2name}#{klass[1] ? " < #{klass[1].id2name}" : ""}

  alias #{name}_ecatb #{name}
  def #{name}(#{args})
    @ecatb_unison_defs[:#{name}] || #{name}_ecatb(#{args})
  end

end
     ))
    }
  }
For the same reason, an abstract notetag value reader's used:
#----------------------------------------------------------------------------|
  #  New method: set_ecatb_notes                                               |
  #  - Stores the value of all specified notetags preserving their orders      |
  #----------------------------------------------------------------------------|
  # items: The data containing the notetags
  # note: The notetag type
  # size: The maximum size of notetag values to be stored
  # add: The truth value of if more than 1 notetag values can be used
  def set_ecatb_notes(items, note, size, add = false)
    # Reads all item's speficied notetag values until the maximum size's reached
    items.each { |item|
      size = item.ecatb_notes[note].size if add
      (0..(size - 1)).each { |index|
        next unless item.ecatb_notes[note][index]
        if add
          @ecatb_notes[note].push(item.ecatb_notes[note][index])
          next
        end
        return if @ecatb_notes[note].size == size
        @ecatb_notes[note][index] ||= item.ecatb_notes[note][index]
      }
    }
    #
  end # set_ecatb_notes
You should have a clear understanding of how the above templates works when concrete information are given by its callers. You should also know how to edit and/or call them without breaking anything unnoticed by you.

 

2. Understand the core structures
All features must be registered here:

# Stores all types of configurations
    CONFIG = [CORE, BAR, CANCEL, CHARGE, CLOCK, COOLDOWN, FORCE, HOTKEY, POOL, 
             SE, UNISON]
Their configurations are registered with their arguments, validation checks and default values in ECATB implementation part of DoubleX_RMVXA::ECATB. Most configurations need to be registered in a class to be used under that class, and all those classes need to be registered in the above CHECK_RESET_DEF. Unregistered ones won't have validation checks nor associated methods. For example:
    # Stores all configurations having corresponding methods in ECATB_Clock_Bar
    # General form: :config => [
    #                 %Q(arguments),
    #                 %Q(validation check),
    #                 %Q(default value)
    #               ]
    ECATB_CLOCK_BAR = {
      :ecatb_clock_bar_colors => [
        %Q(),
        %Q(val.is_a?(Array) && (val[0].is_a?(Color) || val[0].is_a?(Colour)) && 
           (val[1].is_a?(Color) || val[1].is_a?(Colour))),
        %Q(%Q([Colour.text_colour(7), Colour.text_colour(8)]))
      ],
      :ecatb_clock_bar_wh => [
        %Q(),
        %Q(val.is_a?(Array) && val[0].is_a?(Numeric) && val[0] >= 0 && 
           val[1].is_a?(Numeric) && val[1] >= 0),
        %Q(%Q([112, 16]))
      ],
      :ecatb_clock_bar_xy => [
        %Q(),
        %Q(val.is_a?(Array) && val[0].is_a?(Numeric) && val[1].is_a?(Numeric)),
        %Q(%Q([8, 8]))
      ]
    }
All configurations used under ECATB_Clock_Bar are registered in ECATB_CLOCK_BAR, which is registered in CHECK_RESET_DEF.
All configuration values are stored in Game_System and can be accessed by:
#----------------------------------------------------------------------------|
  #  New public instance variables                                             |
  #----------------------------------------------------------------------------|
  # Stores all configuration values
  DoubleX_RMVXA::ECATB::CONFIG.each { |configs|
    configs.each_key { |config| eval("attr_accessor :#{config.id2name}") }
  }
  #
When a save file's created, all the configuration values are saved in those accessors under Game_System, letting users change the configuration values on the fly.

 

3. Understand the basic principles
As an atb system, ECATB needs to be as performant as possible while still not sacrificing any other programming aspect too much, especially at hotspots(costly codes being run at least once per frame), otherwise the average fps will likely suffer. Some techniques such as lazy evaluations and memoizations are heavily used. For example:

#----------------------------------------------------------------------------|
  #  New method: ecatb_gain_rate                                               |
  #  - Returns the atb gain value per frame                                    |
  #----------------------------------------------------------------------------|
  def ecatb_gain_rate
    base = update_ecatb_base
    # Reevaluates the atb rate only if any of its components' changed
    if base[0] || ecatb_battler_change?(:rate)
      set_ecatb_rate
      @ecatb_notes[:rate].each { |rate| eval(rate) }
      @ecatb_rate[:color] = base[1][:val]
    end
    #
    @ecatb_rate[:color]
  end # ecatb_gain_rate
It's to prevent evaluating <ecatb rate: RX> notetags many times per frame, as eval is extremely expensive and a battler can have lots of such notetags. Therefore @ecatb_rate[:color] is used to cache the result and those notetags are only reevaluated when any result determining factor changes.
For this reason, methods like the below are used to check if reevaluations are needed:
#----------------------------------------------------------------------------|
  #  New method: ecatb_battler_change?                                         |
  #  - Checks if any notetag changed                                           |
  #----------------------------------------------------------------------------|
  # note: The notetag type to be checked
  def ecatb_battler_change?(note)
    change = false
    # Checks if any notetag's value's changed
    if @ecatb_note_change[note]
      @ecatb_note_change[note] = false
      change = true
    end
    #
    # Checks if any new notetag's added or old notetag's gone
    if @ecatb_battler_change[note]
      @ecatb_battler_change[note] = false
      change = true
    end
    #
    change
  end # ecatb_battler_change?
Again, performance isn't everything in ECATB implementations, and it indeed tries to have a working balance over all programming aspects, by properly prioritizing them at every part of it, as different parts have different priorities. Understanding those priorities is crucial for you to understand the design decisions behind ECATB.

 

4. Understand the relationship between features
Many features are related to each other, and editing any of those will likely lead to editing some others, so you should always keep an eye on those relationships before touching any of their methods. For example:

#----------------------------------------------------------------------------|
  #  New method: ecatb_unison_actor?                                           |
  #  - Checks if the actor can use the unison skill/item                       |
  #----------------------------------------------------------------------------|
  # type: The unison skill/item data type
  # item: The unison skill/item
  # actors: The unison actor list
  def ecatb_unison_actor?(type, item, actors)
    # Checks if the general skill/item usable conditions are met
    if type == :skill
      return false unless skills.include?(item) || skill_conditions_met?(item)
    else
      return false unless item_conditions_met?(item)
    end
    #
    # Checks if the actor's inputable and can pay the action cost
    return false if auto_battle? || confusion?
    battler = self
    cost = eval(item.ecatb_act_cost)
    cost *= actors.size if $game_party.ecatb_pool
    return true if @ecatb_act_times >= cost
    return false unless @ecatb_val[:charge] > 0
    !eval(current_action.item.ecatb_charge_prior_act_cost)
    #
  end # ecatb_unison_actor?
ecatb_unison_actor? shows that the pool, charge and unison features are closely related. In fact, changing the implementations of those will likely change those of the others.
The focus on these issues should be the high level concepts and mechanics of the features addressed and how they should interact with each other. Without realizing these high level relations and thinking those features as a whole, you're also impossible to figure out a working solution.

 

5. Don't break the changing battle system outside battles feature
You should always bear in mind that ECATB lets you change among battle systems supported by Yanfly Engine Ace - Ace Battle Engine outside battles, so any ECATB specific feature should be disabled when the battle system isn't ECATB. BattleManager.btype?(:ecatb) is your best friend here. For example:

#----------------------------------------------------------------------------|
  #  Alias method: create_all_windows                                          |
  #----------------------------------------------------------------------------|
  alias create_all_windows_ecatb create_all_windows
  def create_all_windows
    create_all_windows_ecatb
    # Added to create ecatb windows for ecatb battle system
    create_ecatb_windows if BattleManager.btype?(:ecatb)
    #
  end # create_all_windows
ECATB specific windows should only be created when the battle system is ECATB.
You should also pay extra attention on possible compatibility issues with other battle system scripts supported by Yanfly Engine Ace - Ace Battle Engine. You should have a clear vision on what should happen when the battle system changes from one to another, in order to ensure those change will always function properly, meaning that you've to comprehend each of those battle systems as a whole as well.


Share


About the Author

No Comments

Quick Reply

Guest

Enter a username

Security check: What is 8 plus 2?