Suikoden Duel System - mageone - 11-21-2009
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
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
|