Jump to content
Shiggy

Advanced Battle Order ( inspired by FF 10)

Recommended Posts


This script modify the way battle order works. Now each batter acts separately from the other and the time before its next action is determined by its speed .

It modify heavily the way the battle systems works so it may not be compatible with a lot of battle scripts.

I will try to work on compatibility patches in the next days , first with my own scripts and then with yanfly battle engine .(It's almost like there is  more people that use this than people using the default engine)

I'm still releasing now to gather some feedback first on the UI , should I hide the battle order window and only show it on a button press? How would you put in the interface a preview of how an action will affect the battle order? (I'm really bad at imagining at UI)

 

Second I would also like to know what kind of skills affecting the battle order would you like to see ? I have some ideas but if you have suggestions,I will start with them . Also should the agility stat affect the speed whith which a battle recover its action . If yes,how?

 

 

 

=begin
#===============================================================================
Title: Advanced Battle Order
Author: Shiggy
Date: Jan 24, 2015
--------------------------------------------------------------------------------
** Change log
Jan 25, 2015
-Initial release of the script
--------------------------------------------------------------------------------
** Terms of Use
* Free to use in non-commercial projects
* Commercial uses
  * Ask permission
  * I may ask for a small fee
  * I may ask a free copy of your game 
  * I may ask for other stuff like the right to use some assets
* Will do bug fixes
* Compatibility patches may be requested but no guarantees 
* Please report any compatibility issues anyway
* Features may be requested but no guarantees, especially if it is non-trivial
* Credits to Shiggy in your project
* Preserve this header
* Be nice to other people ( I don't want mean people to use my scripts)

--------------------------------------------------------------------------------
** Description

This script modify the turn order in battle . At the beginning of the fight,
agility detemines turn order,then action speed determines when a battler will 
be able to attack again. A window is showing the battle order.



--------------------------------------------------------------------------------
** Usage

There is no real turn (in the way  the deafult engine understands it) in this
mode so for states and AI purposes ,it is considered that a turn has passed 
in the time necessary for a battler to recover after a 0 speed attack (default 
is 100 time units). This may lead to weird situation sometimes so be careful with this.


Note that buffs/debuffs as well as states that end at the end of actions should 
still work normally.But if a state that end at the end of an action prevent the
battler to act,he will never act again so be carefult with that.

The default guard skill has 2000 speed which means the battler will ba able to 
attack automaticallly just after,it is advised to put guard speed to 0 or lower 
if you want it to be relevant.
  
  
--------------------------------------------------------------------------------
** Installation

Place this script below Materials and above Main

This script modifies heavily a lot of the combat system,it will likely be 
incompatible with other scripts affecting combat

#===============================================================================
=end

module FFX
  
  ActionSpeed = 100
  SurpriseBonus = 100
  
  Active_Color = Color.new(255,255,0)
  Bonus_Color = Color.new(0,255,0)
  Malus_Color = Color.new(255,0,0)
  
  def self.action_time(battler,speed)
    return [(ActionSpeed-speed),1].max
  end
end

module BattleManager
 
  attr_reader :action_battlers
  
  def self.make_action_list
      preemptive = [] 
      preemptive = $game_troop.members if @surprise
      preemptive = $game_party.members if @preemptive
      preemptive.sort!{|a,b| b.agi - a.agi }
      
      
      
      return preemptive 
  end
  
  def self.turn_start
    @phase = :turn
   
  end
  
  def self.actor_index=(index)
    @actor_index = index
  end
  
end

class Game_Action
  
  def speed
    speed = 0
    speed += item.speed if item
    speed += subject.atk_speed if attack?
   # speed -= subject.agi/100.0
    speed = FFX.action_time(subject,speed)
  end
  
  
end

class Game_Battler < Game_BattlerBase
  attr_accessor :speed
  
  alias ffx_reset_state_counts reset_state_counts
  def reset_state_counts(state_id)
    ffx_reset_state_counts(state_id)
    if $data_states[state_id].auto_removal_timing == 2
      @state_turns[state_id] = (@state_turns[state_id]-1)*FFX::ActionSpeed
    end
  end
  
  alias ffx_overwrite_buff_turns overwrite_buff_turns
  def overwrite_buff_turns(param_id, turns)
    ffx_overwrite_buff_turns(param_id,(turns-1)*FFX::ActionSpeed)
    
  end
  
  def update_speed
    @speed-=1
    update_buff_states
  end
  
  def update_buff_states
    update_state_time
    update_buff_turns
   end 
    
  def update_state_time
    states.each do |state|
      if @state_turns[state.id] > 0 && state.auto_removal_timing == 2
        @state_turns[state.id] -= 1
        remove_state(state.id) if @state_turns[state.id] == 0
      end
    end    
  end
  
  def update_state_turns
     states.each do |state|
      if @state_turns[state.id] > 0 && state.auto_removal_timing == 1
        @state_turns[state.id] -= 1 
      end
    end
  end
  
end

class Scene_Battle < Scene_Base
  
  alias ffx_create_all_window create_all_windows
  def create_all_windows
    ffx_create_all_window
    create_action_list_window 
  end
  
  
  
  def create_action_list_window
    @action_list_window = Window_ActionList.new(Graphics.height-@status_window.height)  
  end
  
  
  def increase_turn
    troop.pages.each {|page| @event_flags

 


 = false if page.span == 1 }
    @turn_count += 1
  end
  
  def battle_start
    @timer = FFX::ActionSpeed-1
    BattleManager.battle_start    
    @action_battlers = [] 

    preemptive = BattleManager.make_action_list
    
    all_battle_members.each { |battler| 
      battler.speed = 0 - battler.agi
    }
    
    preemptive.each{ |battler| battler.speed -= FFX::SurpriseBonus }
    
    battler_turn
  end
  
  def speed_order(a,
    diff = a.speed - b.speed
    if diff < 0
      return -1
    elsif diff > 0
      return 1
    else
      return a.name <=> b.name
    end
  end
  
  
  def update_action_order
    @active_battlers = []
    @alive_members = []
      all_battle_members.each { |battler|
        @active_battlers.push(battler) if battler.alive? && battler.movable? 
        @alive_members.push(battler) if battler.alive?
      } 
      
      @active_battlers.sort! {|a,b| speed_order(a, }      
      while @active_battlers[0].speed > 0
        @active_battlers.each{|m| m.speed -=1 }
        @alive_members.each{|m| m.update_buff_states }  
        
        @timer+=1
        $game_troop.increase_turn if @timer%FFX::ActionSpeed == 0
      end
      update_list
  end
  
  def update_list
    list = []
    @active_battlers.each { |battler|
      for i in 0 .. 3
        list.push(Info_Battler.new(battler,i))
      end
    }
    list.sort! {|a,b| speed_order(a, }
    
    @action_list_window.refresh(list)
  end
  
  def battler_turn    
      update_action_order
     
      @subject = @active_battlers.shift      
      @subject.make_actions
      
      if @subject.actor?
        BattleManager.actor_index = @subject.index 
        
        start_actor_command_selection        
      else
        turn_start
      end
    
  end
  
  def command_attack
    BattleManager.actor.make_actions
    BattleManager.actor.input.set_attack
    select_enemy_selection
  end
  
  def command_guard
    BattleManager.actor.make_actions
    BattleManager.actor.input.set_guard
    next_command
  end
  
  alias ffx_on_skill_ok on_skill_ok
  def on_skill_ok
    BattleManager.actor.make_actions
    ffx_on_skill_ok
  end
  
  alias ffx_on_item_ok on_item_ok
  def on_item_ok
    BattleManager.actor.make_actions
    ffx_on_item_ok
  end
  
  def next_command
    turn_start    
  end
  
  def turn_start
    @party_command_window.close
    @actor_command_window.close
    @status_window.unselect
    BattleManager.turn_start
    @log_window.wait
    @log_window.clear
  end
  
  def start_actor_command_selection
    unless scene_changing?
     
      refresh_status
      @status_window.unselect
      @status_window.open
      
      @status_window.select(BattleManager.actor.index)
      @party_command_window.close
      @actor_command_window.setup(BattleManager.actor)
      
    end
    
  end
  
  def process_action
    return if scene_changing?
    if !@subject || !@subject.current_action
      turn_end
    end
        
    return turn_end unless @subject
    if @subject.current_action
      @subject.current_action.prepare
      if @subject.current_action.valid?
        @status_window.open
        @subject.speed += @subject.current_action.speed
        execute_action
      end
      @subject.remove_current_action
    end
    process_action_end unless @subject.current_action
  end
  
  def turn_end
        
    BattleManager.turn_end
    process_event    
    battler_turn
    
  end
  
  
  def process_action_end
    
    @subject.on_action_end

    refresh_status
    @log_window.display_auto_affected_status(@subject)
    @log_window.wait_and_clear
    @log_window.display_current_state(@subject)
    @log_window.wait_and_clear
    BattleManager.judge_win_loss  
    
  end
  
end  
  
class Window_ActionList < Window_Selectable
  
  def initialize(height)
    @list=[]
    super(Graphics.width-100,50,100,height-100)
    
    
  end
  
  def refresh(list)
    
    @list=list
    contents.clear
    draw_all_items
  end
  
  def item_max
    @list.size
  end
  
  def draw_item(index)
    rect = item_rect(index)
    string = @list[index].name
    change_color(FFX::Active_Color) #if @list[index] == @list[0]
    draw_text_ex(rect.x,rect.y,string)
    draw_horz_line(rect.y+rect.height/2)
    #change_color(normal_color)
  end
  
  def draw_horz_line(y)
    line_y = y + line_height / 2 - 1
    contents.fill_rect(0, line_y, width, 2, line_color)
  end
  
  def line_color
    color = normal_color
    color.alpha = 128
    color
  end
  
end

class Info_Battler
  attr_reader :name
  attr_reader :battler
  attr_accessor :speed
  
  def initialize(battler,turn)
    @name  = battler.name
    @battler = battler
    @speed =  battler.speed + turn * FFX.action_time(battler,battler.atk_speed)
    
  end
    
end

 

 

post-62845-0-06470900-1453683066_thumb.png

  • Like 3

Share this post


Link to post
Share on other sites

Great script! CTB systems are very fun to play and add alot of depth to combat tactics. Of course AGI should be considered while determening turn frequenzy. I'm not sure however, what formula is best to use but I'll make a suggestion as food for thought.

n * x / y = z
  • n = 1+('previous skill speed'/100)
     
  • x = AGI of the character
     
  • y = Total AGI and speed of all participants (enemies + partymembers) * 'their respective skill multipliers' or n
     
  • z = each characters proportional number of actions (their % share)

Other things to consider are how to implement insta cast abilitys. 

 

Maybe you could make it so that they get to act imediately after your action. But with the catch being that, you are sloted in behind the next in line if you use consecutive insta casts. Mostly to prevent exploitation from being built in to the engine. As for delay turn, I'll suggest another possible formula.

(AGI+Skillspeed)/2

Also with a catch though. No more than 2 reductions can stack, and the debuff will last until the next action.

 

Note: The CTB systems are fun because it lets the player control the flow of battle and anticipate what is to come. So they work best if there is little to no random variance. (I didn't see any of that while glancing over your script, just saying) Some developers like to have MAX and MIN caps on the proportion that any individual may take of the overall action turns. Mainly to prevent some actors/enemys from taking over the show completely (looking at you Rikku :angry:) aswell as preventing some actors to fall behind and get very few action times (looking at you Auron :angry:). JK

 

I for one didn't mind Rikku acting 50 times in a row between every other caracters turn! xD But some do, could be worth considering ;)

 

No matter what type of formulas you finally decide on using, keep in mind what makes CTBs great and nurture those aspects.

 

Finally, GREAT WORK! Your contributions are awsome, thanks alot for your efforts.^^

 

Hope all this helps to some extent! :ph34r:

Edited by Cookie Ninja

Share this post


Link to post
Share on other sites

Thanks for the feedback,Cookie.

I'll see what can I do, the problem is everytime i publish a script thinking to myself I will polish it later. I think of a new script and start working on something else.

 

 

 

The thing I'm working on right now is pretty awesome in my opinion and should be released later today

 

 

 

Ps: Oh god it's been less than 2 months and I already have more than 500 posts

Edited by Shiggy

Share this post


Link to post
Share on other sites

I'll see what can I do, the problem is everytime i publish a script thinking to myself I will polish it later. I think of a new script and start working on something else.

I know that feeling. :D

 

Regarding the battle order UI, I think it should be shown all the time. I mean, it is a CTB system, so it is pretty mandatory to show the order.

Eventually, you can put in a toggle button for it, in case someone would like to see the scenery without the UI.

 

And here is how you could show where the actor would jump on the order list graphically:

http://postimg.org/image/sozbinl3d/

My Paint skills are awesome, right? :P

 

So, that arrow thingy would be put between the two characters on the order table, indicating that that is the spot the actor will jump after performing the action.

 

Alternatively, you can take a look on the game called "Legend of Heroes - Trails in the Sky". That game uses a CTB system with a pretty solid UI for it.

Note that it uses images instead of character names, and when someone is targeted, it's image on the order list will be highlighted.

 

FF10... One and a half hour spent in a single battle just to be able to say that I beat the ultimate boss in it. Good old times! :D

  • Like 1

Share this post


Link to post
Share on other sites

@Sixth I had FF 10 in mind but showing only the order for each battler once instead of showing several next attacks will be simpler , and if i can't manage to get the arrow,I will try using some kind of color code. Thanks for the idea . I need to look at legend of heroes now.

Share this post


Link to post
Share on other sites

I was wondering if anyone can help me. It's probably really simple but I know next to nothing about programming.
I keep getting this error: https://postimg.org/image/twcvewjwf/442556b4/
It has to do with how the script is split in two and how I don't understand programming syntax. I've tried fiddling around with it, but I'm lost.
Help would be appreciated.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
Top ArrowTop Arrow Highlighted