Suikoden Duel System
#1
Introduction

For those who know Suikoden Saga this script allow you to use the 1 Vs 1 Duel System from this game.
If you don't know Suikoden... you should try it ! Seriously.. this is a duel system based on a "rock, paper, cisor"-kind system. In very short let's say that you can choose between 3 commands as "Attack", "Wilde attack" or "Defend" where Attack kills Defend, Defend kills Wild Attack, Wilde Attack kills Attack, etc



Screenshots

[Image: Suiko-duel.png]

Code:
#==============================================================================
#  Suikoden Dueling System (SDS) v 0.9 (Bug Testing Edition)
#  Author: modern algebra
#  Date: June 2, 2007
#  Thanks: Ikzai and dollmage, for the request and specifications
#------------------------------------------------------------------------------
# Instructions:
#
# Place in a new script above Main
#
# It is very easy to use, just place this in a call script:
#
# $scene = Scene_Suikoden_Duel.new (XXX)
#
# where XXX is the ID of the enemy you wish to duel. Keep in mind that unlike
# the event command to run a battle, everything below this command in the event
# will not run.
#==============================================================================
# ** Sprite_SuikodenBattler
#------------------------------------------------------------------------------
#  This class is used to display the battlers and controls animation. Basically
# just a shortened version of Sprite_Battler
#==============================================================================

class Sprite_SuikodenBattler < RPG::Sprite
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :battler                  # battler
  #--------------------------------------------------------------------------
  # * Object Initialization
  #     viewport : viewport
  #     battler  : battler (Game_Battler)
  #--------------------------------------------------------------------------
  def initialize(viewport, battler = nil)
    super(viewport)
    @battler = battler
    @battler_visible = false
  end
  #--------------------------------------------------------------------------
  # * Dispose
  #--------------------------------------------------------------------------
  def dispose
    if self.bitmap != nil
      self.bitmap.dispose
    end
    super
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    super
    # If battler is nil
    if @battler == nil
      self.bitmap = nil
      loop_animation(nil)
      return
    end
    # If file name or hue are different than current ones
    if @battler.battler_name != @battler_name or @battler.battler_hue != @battler_hue
      # Get and set bitmap
      @battler_name = @battler.battler_name
      @battler_hue = @battler.battler_hue
      self.bitmap = RPG::Cache.battler(@battler_name, @battler_hue)
      @width = bitmap.width
      @height = bitmap.height
      self.ox = @width / 2
      self.oy = @height
    end
  end
end


#==============================================================================
# ** Window_SuikodenHelp
#------------------------------------------------------------------------------
#  This class displays the actions taken by the enemy and the actor
#==============================================================================

class Window_SuikodenHelp < Window_Base
  def initialize (actor_choice, enemy_choice)
    super(200, 0, 240, 96)
    self.contents = Bitmap.new(width - 32, height - 32)
    @display = [actor_choice, enemy_choice]
    self.z=200
    self.opacity = 160
    refresh
  end
  
  def refresh
    self.contents.draw_text(0,0,120,32, $game_party.actors[0].name + ":")
    self.contents.draw_text(0,32,120,32, $data_enemies[$duel_enemy_id].name + ":")
    for i in 0...2
      case @display[i]
      when 0
        self.contents.draw_text(120,i*32,80,32, "Attack")
      when 1
        self.contents.draw_text(120,i*32,80,32, "Charge")
      when 2
        self.contents.draw_text(120,i*32,80,32, "Defense")
      end
    end
  end
  
  def dispose
    if self.contents != nil
      self.contents.clear
    end
    super
  end
end


#==============================================================================
# ** Window_SuikodenBattleStatus
#------------------------------------------------------------------------------
#  This window displays the status of all party members on the battle screen.
#  Basically a carbon copy of Window_BattleStatus, with a few minor modifications
#==============================================================================

class Window_SuikodenBattleStatus < Window_Base
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    super(0, 320, 640, 160)
    self.contents = Bitmap.new(width - 32, height - 32)
    @level_up_flags = [false]
    refresh
  end
  #--------------------------------------------------------------------------
  # * Set Level Up Flag
  #     actor_index : actor index
  #--------------------------------------------------------------------------
  def level_up(actor_index)
    @level_up_flags[actor_index] = true
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    self.contents.clear
    actor = $game_party.actors[0]
    actor_x = 244
    draw_actor_name(actor, actor_x, 0)
    draw_actor_hp(actor, actor_x, 32, 120)
    draw_actor_sp(actor, actor_x, 64, 120)
    if @level_up_flags[0]
      self.contents.font.color = normal_color
      self.contents.draw_text(actor_x, 96, 120, 32, "LEVEL UP!")
    else
      draw_actor_state(actor, actor_x, 96)
    end
  end
  
  def dispose
    if self.contents != nil
      self.contents.clear
    end
    super
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    super
    # Slightly lower opacity level during main phase
    if $game_temp.battle_main_phase
      self.contents_opacity -= 4 if self.contents_opacity > 191
    else
      self.contents_opacity += 4 if self.contents_opacity < 255
    end
  end
end

#==============================================================================
# ** Window_Damage
#------------------------------------------------------------------------------
#  This class displays damage
#==============================================================================

class Window_Damage < Window_Base
  
  def initialize (damage, decision1, decision2)
    super (240, 100, 160, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
    @damage = damage
    @decision = [decision1, decision2]
    self.z=500
    self.opacity = 0
    refresh
  end
  
  def refresh
    self.contents.font.color = Color.new(255, 75, 75, 255)
    case @decision[0]
    when 0
      case @decision[1]
      when 0
        self.contents.draw_text (0,0,160,32,@damage.to_s)
      when 1
        self.contents.draw_text (0,0,160,32,@damage.to_s)
      when 2
      end
    when 1
      case @decision[1]
      when 0
        self.contents.draw_text (0,0,160,32,"Attack Nullified!")
      when 1
        self.contents.draw_text (0,0,160,32,@damage.to_s)
      when 2
        self.contents.draw_text (0,0,160,32,@damage.to_s)
      end
    when 2
      case @decision[1]
      when 0
      self.contents.draw_text (0,0,160,32, @damage.to_s)
      when 1
        self.contents.draw_text (0,0,160,32,"Dodge and Attack!")
      when 2
      end
    end
  end
  
  def dispose
    if self.contents != nil
      self.contents.clear
    end
    super
  end
end

#==============================================================================
#  ** Scene_Suikoden_Duel
#------------------------------------------------------------------------------
# The main processing scene for the battle system
#==============================================================================

class Scene_Suikoden_Duel
  
  def initialize (enemy)
    $duel_enemy_id = enemy
    @enemy_hp = $data_enemies[enemy].maxhp
    @wait = 0
    @wait3 = 0
    @viewport_actor = Viewport.new(240,240,160,240)
    @viewport_enemy = Viewport.new(240,60,160,240)
  end
  
  def main
    $game_temp.battleback_name = $game_map.battleback_name
    $game_temp.in_battle = true
    s1 = "Attack"
    s2 = "Charge"
    s3 = "Defense"
    @actor_command_window = Window_Command.new(160, [s1, s2, s3])
    @actor_command_window.x = 240
    @actor_command_window.y = 160
    @actor_command_window.z = 260
    @actor_command_window.back_opacity = 160
    @actor_command_window.active = false
    @actor_command_window.visible = false
    if @status_window == nil
      @status_window = Window_SuikodenBattleStatus.new
      @status_window.z=255
    end
    if @actor_window == nil
      @actor_window = Sprite_SuikodenBattler.new(@viewport1, $game_party.actors[0])
      @enemy_window = Sprite_SuikodenBattler.new(@viewport1, $data_enemies[$duel_enemy_id])
    end
    @battleback = Sprite.new(Viewport.new(0,0,640, 480))
    if @battleback.bitmap != nil
      @battleback.bitmap.clear
    end
    @battleback.bitmap = RPG::Cache.battleback($game_map.battleback_name)
    @battleback.z=0
    # Initialize wait count
    @wait_count = 0
    # Execute transition
    if $data_system.battle_transition == ""
      Graphics.transition(20)
    else
      Graphics.transition(40, "Graphics/Transitions/" +
      $data_system.battle_transition)
    end
    # Main loop
    loop do
      @actor_window.battler = $game_party.actors[0]
      @actor_window.update
      @actor_window.x = 320
      @actor_window.y = 430
      @actor_window.z = 255
      @enemy_window.battler = $data_enemies[$duel_enemy_id]
      @enemy_window.update
      @enemy_window.x = 320
      @enemy_window.y = 210
      @enemy_window.z = 100
      if @turn_off_command != true
        @actor_command_window.active = true
        @actor_command_window.visible = true
      end
      # Update game screen
      Graphics.update
      # Update input information
      Input.update
      # update_battle_phase
      if @battle_over != true
        if @wait == 0
          duel_phase_update
        else
          attack_calculations
        end
      else
        update_battle_win
      end
      # Abort loop if screen is changed
      if $scene != self
        break
      end
    end
    # Refresh map
    $game_map.refresh
    # Prepare for transition
    Graphics.freeze
    # Dispose of windows
    windows = [@status_window, @actor_window, @enemy_window, @result_window,
    @battleback, @help_window, @actor_damage_window, @enemy_damage_window, @actor_command_window]
    for i in 0...windows.size
      windows[i].dispose
    end
  end
  
  def duel_phase_update
    @actor_command_window.update
    if Input.trigger?(Input::C)
      # Branch by command window cursor position
      case @actor_command_window.index
      when 0  # attack
        # Play decision SE
        $game_system.se_play($data_system.decision_se)
        @actor_decision = @actor_command_window.index
        duel_compare
      when 1  # wild attack
        # Play decision SE
        $game_system.se_play($data_system.decision_se)
        # Set actor choice
        @actor_decision = @actor_command_window.index
        duel_compare
      when 2  # defend
        # Play decision SE
        $game_system.se_play($data_system.decision_se)
        # Switch to status screen
        @actor_decision = @actor_command_window.index
        duel_compare
      end
    end
  end
  
  def duel_compare
    @actor_command_window.active = false
    @actor_command_window.visible = false
    @turn_off_command = true
    @enemy_decision = rand(100)
    if @enemy_decision < 50
      @enemy_decision = 0
    elsif @enemy_decision < 75
      @enemy_decision = 1
    else
      @enemy_decision = 2
    end
    case @actor_decision
    when 0
      case @enemy_decision
      when 0
        @actor_damage_modifier = 1
        @enemy_damage_modifier = 1
        @enemy_accuracy = true
        @actor_accuracy = true
      when 1
        @actor_damage_modifier = 0
        @enemy_damage_modifier = 1.5
        @enemy_accuracy = true
      when 2
        @actor_damage_modifier = 0.5
        @enemy_damage_modifier = 0
        @actor_accuracy = true
        @enemy_accuracy = false
      end
    when 1
      case @enemy_decision
      when 0
        @actor_damage_modifier = 1.5
        @enemy_damage_modifier = 0
        @actor_accuracy = true
        @enemy_accuracy = false
      when 1
        @actor_damage_modifier = 1.5
        @enemy_damage_modifier = 1.5
        @actor_accuracy = true
        @enemy_accuracy = true
      when 2
        @actor_damage_modifier = 0
        @enemy_damage_modifier = 1.5
        @actor_accuracy = false
        @enemy_accuracy = true
      end
    when 2
      case @enemy_decision
      when 0
        @actor_damage_modifier = 0
        @enemy_damage_modifier = 0.5
        @enemy_accuracy = true
        @actor_accuracy = false
      when 1
        @actor_damage_modifier = 1.5
        @enemy_damage_modifier = 0
        @enemy_accuracy = false
        @actor_accuracy = true
      when 2
        @actor_damage_modifier = 0
        @enemy_damage_modifier = 0
        @enemy_accuracy = false
        @actor_accuracy = false
      end
    end
    attack_calculations
  end
  
  def attack_calculations
    if @wait == 0
      @help_window = Window_SuikodenHelp.new (@actor_decision,@enemy_decision)
      actor = $game_actors[$game_party.actors[0].id]
      enemy = $data_enemies[$duel_enemy_id]
      @actor_damage = (@actor_damage_modifier*(actor.atk - (enemy.pdef/2) - 10 + rand(actor.str / 10))).round
      if @actor_damage < 0
        @actor_damage = 0
      end
      enemy_damage = (@enemy_damage_modifier*(enemy.atk - (actor.pdef/2)- 10 + rand(enemy.str / 10))).round
      if enemy_damage < 0
        enemy_damage = 0
      end
      @enemy_hp -= @actor_damage
      $game_actors[$game_party.actors[0].id].hp -= enemy_damage
      @wait = 80
      animation_enemy = $data_enemies[$duel_enemy_id].animation2_id
      @actor_damage_window = Window_Damage.new (enemy_damage, @actor_decision, @enemy_decision)
      @actor_damage_window.y = 280
      @status_window.refresh
      unless @enemy_damage_modifier == 0
        @actor_window.animation ($data_animations[animation_enemy], @enemy_accuracy)
      end
      return
    elsif @wait !=1
      @wait-=1
      if (@wait%3) == 0
        if @wait >= 40
          @actor_damage_window.y -= 1
        else
          @enemy_damage_window.y -= 1
        end
      end
      if @wait == 40
        @enemy_damage_window = Window_Damage.new (@actor_damage, @enemy_decision, @actor_decision)
        @actor_damage_window.visible = false
        unless @actor_damage_modifier == 0
          animation_actor = $data_weapons[$game_actors[$game_party.actors[0].id].weapon_id].animation2_id
          @enemy_window.animation ($data_animations[animation_actor], @actor_accuracy)
        end
      end
      return
    else
      @wait = 0
      @enemy_damage_window.visible = false
      @help_window.visible = false
      if $game_actors[$game_party.actors[0].id].hp <=0
        @actor_window.collapse
        $game_temp.gameover = true
      elsif @enemy_hp <=0
        @enemy_window.collapse
        battle_win
      else
        @turn_off_command = false
        return
      end
    end
  end

  def battle_win
    enemy = $data_enemies[$duel_enemy_id]
    exp = enemy.exp
    gold = enemy.gold
    # Determine if treasure appears
    if rand(100) < enemy.treasure_prob
      if enemy.item_id > 0
        treasures.push($data_items[enemy.item_id])
      end
      if enemy.weapon_id > 0
        treasures.push($data_weapons[enemy.weapon_id])
      end
      if enemy.armor_id > 0
        treasures.push($data_armors[enemy.armor_id])
      end
    end
    # Treasure is limited to a maximum of 6 items
    treasures = []
    # Obtaining EXP
    for i in 0...$game_party.actors.size
      actor = $game_party.actors[i]
      if actor.cant_get_exp? == false
        last_level = actor.level
        actor.exp += exp
        if actor.level > last_level
          @status_window.level_up(i)
        end
      end
    end
    # Obtaining gold
    $game_party.gain_gold(gold)
    # Obtaining treasure
    for item in treasures
      case item
      when RPG::Item
        $game_party.gain_item(item.id, 1)
      when RPG::Weapon
        $game_party.gain_weapon(item.id, 1)
      when RPG::Armor
        $game_party.gain_armor(item.id, 1)
      end
    end
    # Make battle result window
    @result_window = Window_BattleResult.new(exp, gold, treasures)
    @result_window.z = 2000
    $game_system.me_play($data_system.battle_end_me)
    @battle_over = true
    @battle_end_wait_count = 100
    update_battle_win
  end
  
  def update_battle_win
    @result_window.refresh
    if @battle_end_wait_count > 0
      @battle_end_wait_count -= 1
    else
      @result_window.visible = true
      if Input.trigger?(Input::C) or Input.trigger?(Input::B)
        $scene = Scene_Map.new
      end
    end
  end
end

Instructions

Place in a new script above Main.
Then use the script call in an event with the code :
$scene = Scene_Suikoden_Duel.new(XXX)
Where XXX stands for the ID of the enemy in your database that you want to fight.

Weapon damage and animations requires your party leader has a weapon equipped, so make sure he has one readied. It will crash otherwise.


Compatibility


I am not too sure about this part, but this script is rewriting the damage algorythm for the duel scene. Don't worry it won't affect the damage algorythm of your normal battle system. But the algorythm damage of the duel scene is based on the basic RMXP BS so i am not too sure how it s gona work if you're using a BS with different dmg algorythm.

for info here is the part of the code that is setting the damage system :

line 435 :
Code:
@actor_damage = (@actor_damage_modifier*(actor.atk - (enemy.pdef/2) - 10 + rand(actor.str / 10))).round
line 439 :
Code:
enemy_damage = (@enemy_damage_modifier*(enemy.atk - (actor.pdef/2)- 10 + rand(enemy.str / 10))).round


Credits and Thanks

Script created by Modern Algebra
Reply }


Possibly Related Threads…
Thread Author Replies Views Last Post
   The Wanderers: The Customizable Encounters System DerVVulfman 0 245 08-24-2024, 07:12 PM
Last Post: DerVVulfman
   Super Simple Vehicle System - Enhanced DerVVulfman 65 94,095 06-02-2023, 06:16 PM
Last Post: Sujabes467
   Zenith Tactical Battle System Plus (ZTBS+) DerVVulfman 0 2,818 05-10-2022, 10:42 PM
Last Post: DerVVulfman
   Commercial System Package DerVVulfman 11 14,239 01-04-2020, 12:37 AM
Last Post: Pelip
   ACBS - Atoa Custom Battle System 3.2 Victor Sant 150 254,879 03-02-2019, 04:47 AM
Last Post: dragonprincess44
   DerVV's Simple Popup System DerVVulfman 4 12,193 10-08-2017, 04:53 PM
Last Post: DerVVulfman
   Melly-Mel's Calendar System DerVVulfman 23 43,440 12-02-2016, 04:31 AM
Last Post: DerVVulfman
   The Magey Mage's Spellbook System DerVVulfman 3 9,948 10-31-2016, 01:45 AM
Last Post: Noctis
   CTB - A Final Fantasy X-like Battle System, Version 3.2 Charlie Fleed 572 752,476 05-19-2016, 05:38 PM
Last Post: Starmage
   Mousie: The Mouse System DerVVulfman 67 112,647 07-19-2015, 11:18 PM
Last Post: yamina-chan



Users browsing this thread: 2 Guest(s)