KursedVictory VX + ACE - kyonides - 09-06-2025
KursedVictory VX + ACE
by Kyonides
Introduction
You will either love this scriptlet or just hate it. 
Sometimes the heroes cannot simply obtain a flawless victory. That would be inconceivable!
Thus, they need some final punishment to make sure they learn their lesson!
Just add enemy ID's to the ENEMY_IDS constant to make this happen!
Or leave this note tag in the enemy's notebox: curse_victory
VX Script
Code: # * KursedVictory VX * #
# Scripter : Kyonides
# v1.2.0 - 2025-09-09
# Sometimes the heroes cannot simply obtain a flawless victory. Thus, they need
# some final punishment to make sure they learn their lesson!
# - Method #1
# Just add enemy ID's to the ENEMY_IDS constant to make this happen!
# - Method #2
# Leave a note tag in the enemy's notebox: curse_victory
# Warning: If you refuse to comply, you might have to fight another troop...
module KursedVictory
BGS = "Darkness"
CURSOR = "sword0132"
CURSOR_OY = 4
OPTION_BACKDROP = "box240"
MESSAGE = ["Flawless Victory!", "Now choose a curse victim!"]
OPTIONS = ["Comply", "Refuse"]
OUTCOME = ["You complied with the %s's demand.",
"You refused to listen to %s."]
CURSE_CHANCE = 100
WAIT_FRAMES = 40
ENEMY_NOTE_TAG = /curse_victory/i
ENEMY_IDS = []
ROUND2_ENEMY_IDS = {}
ROUND2_ENEMY_IDS[1] = { :name => "Basilisk", :troop_id => 2 }
end
class Game_Enemy
def cursed_victory_note
@cursed_victory ||= enemy.note[KursedVictory::ENEMY_NOTE_TAG]
end
def curse_victory?
return true if KursedVictory::ENEMY_IDS.include?(@enemy_id)
cursed_victory_note != nil
end
end
class Game_Party
def dead_members
members.select {|member| member.dead? }
end
def all_dead_now?
dead_members.size == @actors.size
end
end
class Game_Troop
def curse_flawless_victory?
enemy = @enemies.find {|enemy| enemy.curse_victory? }
enemy != nil
end
attr_reader :troop_id
end
class CursedMessageWindow < Window_Base
def initialize(wx, wy)
super(wx, wy, 280, 80)
refresh
end
def refresh
line1, line2 = KursedVictory::MESSAGE
font = self.contents.font
font.bold = true
font.color.set(220, 80, 0)
self.contents.draw_text(0, 0, width - 32, 24, line1, 1)
font.bold = false
font.color.set(255, 255, 255)
self.contents.draw_text(0, 24, width - 32, 24, line2, 1)
end
end
module KursedVictory
class TextBox
def initialize(pos, total, vp=nil)
@index = pos
@max = total
@row_max = 2
@col_max = 1
@viewport = vp
@backdrop = Sprite.new(vp)
@label = Sprite.new(vp)
@label.z = 50
end
def set_image(filename)
@filename = filename
set_bitmap
set_text_bitmap
reset_alignment
end
def set_bitmap
bitmap = Cache.picture(@filename)
@width = bitmap.width
@height = bitmap.height
@rect = bitmap.rect
@col_width = Graphics.width
@center_x = (@col_width - @width) / 2
@backdrop.bitmap = bitmap
end
def set_text_bitmap
@align_x = 1
@label.bitmap = Bitmap.new(@width, @height)
end
def set_align_xy
h = @height + 24
@backdrop.x = @center_x
@backdrop.y = 140 + @index * h
end
def reset_alignment
set_align_xy
@label.x = @backdrop.x
@label.y = @backdrop.y
end
def x
@backdrop.x
end
def y
@backdrop.y
end
def set_text(text)
@text = text
bit = @label.bitmap
bit.clear
bit.draw_text(@rect, text, @align_x)
end
def dispose
@label.bitmap.dispose
@label.dispose
@backdrop.bitmap.dispose
@backdrop.dispose
end
attr_reader :text
end
class Spriteset
def initialize
@curse_viewport = Viewport.new(0, 0, 640, 480)
@curse_viewport.z = 500
@curse_boxes = []
@curse_x = []
@curse_y = []
filename = KursedVictory::OPTION_BACKDROP
options = KursedVictory::OPTIONS
options.each_with_index do |choice, n|
box = KursedVictory::TextBox.new(n, options.size, @curse_viewport)
box.set_image(filename)
box.set_text(choice)
@curse_x << box.x
@curse_y << box.y + KursedVictory::CURSOR_OY
@curse_boxes << box
end
@cursed_cursor = Sprite.new(@curse_viewport)
@cursed_cursor.x = @curse_x[0]
@cursed_cursor.y = @curse_y[0]
@cursed_cursor.z = 100
@cursed_cursor.bitmap = Cache.picture(KursedVictory::CURSOR)
end
def move_cursor(index)
@cursed_cursor.y = @curse_y[index]
end
def dispose
@curse_boxes.each {|box| box.dispose }
@cursed_cursor.bitmap.dispose
@cursed_cursor.dispose
@curse_viewport.dispose
end
end
end
class Scene_Battle
alias :kyon_kurvic_scn_btl_proc_victor :process_victory
def process_victory
process_cursed_victory
if @cursed_victory and $game_party.all_dead_now?
process_defeat
return
end
kyon_kurvic_scn_btl_proc_victor
start_anti_curse_battle if @curse_lifted
end
def start_anti_curse_battle
RPG::BGM.stop
RPG::BGS.stop
$game_party.clear_actions
$game_troop.clear
$game_troop.setup(@round2_data[:troop_id])
Sound.play_battle_start
$game_system.battle_bgm.play
$scene = Scene_Battle.new
end
def process_cursed_victory
return if KursedVictory::CURSE_CHANCE < rand(100)
return unless $game_troop.curse_flawless_victory?
return if $game_party.dead_members.size > 0
RPG::BGM.stop
@bgs = RPG::BGS.new(KursedVictory::BGS)
@bgs.play
wx = (Graphics.width - 280) / 2
@cursed_message = CursedMessageWindow.new(wx, 40)
troop_id = $game_troop.troop_id
@round2_data = KursedVictory::ROUND2_ENEMY_IDS[troop_id]
if @round2_data
process_cursed_victory_options
return if @curse_lifted
end
process_cursed_victory_execution
end
def process_cursed_victory_options
@cursed_spriteset = KursedVictory::Spriteset.new
@curse_stage = 0
@curse_index = 0
@cursed_options = true
while @cursed_options
Graphics.update
Input.update
update_cursed_victory
end
end
def update_cursed_victory
case @curse_stage
when 0
update_cursed_victory_options
when 1
update_cursed_victory_decision
end
end
def update_cursed_victory_options
if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
Sound.play_cursor
@curse_index = (@curse_index + 1) % 2
@cursed_spriteset.move_cursor(@curse_index)
return
elsif Input.trigger?(Input::C)
Sound.play_decision
name = @round2_data[:name]
if name
text = KursedVictory::OUTCOME[@curse_index]
text = sprintf(text, name)
end
@cursed_spriteset.dispose
if @curse_index == 1
RPG::BGS.stop
@cursed_message.dispose
@curse_lifted = true
end
if name
ow = 460
$game_message.texts << text
@curse_stage = 1
else
@cursed_options = @curse_stage = nil
end
end
end
def update_cursed_victory_decision
@message_window.update
if Input.trigger?(Input::C)
Sound.play_decision
@cursed_options = @curse_stage = nil
end
end
def process_cursed_victory_execution
@info_viewport.visible = true
@party_command_window.contents.clear
@party_command_window.index = -1
@message_window.visible = false
@status_window.index = 0
@status_window.active = true
@cursed_victory = true
while @cursed_victory
Graphics.update
Input.update
update_cursed_victory_execution
end
KursedVictory::WAIT_FRAMES.times { Graphics.update }
@cursed_message.dispose
@info_viewport.visible = false
@cursed_victory = true
end
def update_cursed_victory_execution
@status_window.update
if Input.trigger?(Input::C)
Sound.play_decision
n = @status_window.index
$game_party.members[n].add_state(1)
@status_window.refresh
@status_window.active = false
@cursed_victory = nil
end
end
end
VX ACE Script
Code: # * KursedVictory ACE * #
# Scripter : Kyonides
# v1.2.0 - 2025-09-09
# Sometimes the heroes cannot simply obtain a flawless victory. Thus, they need
# some final punishment to make sure they learn their lesson!
# - Method #1
# Just add enemy ID's to the ENEMY_IDS constant to make this happen!
# - Method #2
# Leave a note tag in the enemy's notebox: curse_victory
# Warning: If you refuse to comply, you might have to fight another troop...
module KursedVictory
BGS = "Darkness"
CURSOR = "sword0132"
CURSOR_OY = 4
OPTION_BACKDROP = "box240"
MESSAGE = ["Flawless Victory!", "Now choose a curse victim!"]
OPTIONS = ["Comply", "Refuse"]
OUTCOME = ["You complied with the %s's demand.",
"You refused to listen to %s."]
CURSE_CHANCE = 100
WAIT_FRAMES = 40
ENEMY_NOTE_TAG = /curse_victory/i
ENEMY_IDS = []
ROUND2_ENEMY_IDS = {}
ROUND2_ENEMY_IDS[1] = { :name => "Basilisk", :troop_id => 2 }
end
class Game_Enemy
def cursed_victory_note
@cursed_victory ||= enemy.note[KursedVictory::ENEMY_NOTE_TAG]
end
def curse_victory?
return true if KursedVictory::ENEMY_IDS.include?(@enemy_id)
cursed_victory_note != nil
end
end
class Game_Party
def dead_members
members.select {|member| member.dead? }
end
def all_dead_now?
dead_members.size == @actors.size
end
end
class Game_Troop
def curse_flawless_victory?
enemy = @enemies.find {|enemy| enemy.curse_victory? }
enemy != nil
end
attr_reader :troop_id
end
class CursedMessageWindow < Window_Base
def initialize(wx, wy)
super(wx, wy, 280, 76)
refresh
end
def refresh
line1, line2 = KursedVictory::MESSAGE
font = self.contents.font
font.bold = true
font.color.set(220, 80, 0)
self.contents.draw_text(0, 0, width - 32, 24, line1, 1)
font.bold = false
font.color.set(255, 255, 255)
self.contents.draw_text(0, 26, width - 32, 24, line2, 1)
end
end
module KursedVictory
class Message < Window_Base
def set_text(text)
contents.clear
contents.draw_text(0, 0, contents.width, 24, text)
self.visible = true
self.pause = true
end
end
class TextBox
def initialize(pos, total, vp=nil)
@index = pos
@max = total
@row_max = 2
@col_max = 1
@viewport = vp
@backdrop = Sprite.new(vp)
@label = Sprite.new(vp)
@label.z = 50
end
def set_image(filename)
@filename = filename
set_bitmap
set_text_bitmap
reset_alignment
end
def set_bitmap
bitmap = Cache.picture(@filename)
@width = bitmap.width
@height = bitmap.height
@rect = bitmap.rect
@col_width = Graphics.width
@center_x = (@col_width - @width) / 2
@backdrop.bitmap = bitmap
end
def set_text_bitmap
@align_x = 1
@label.bitmap = Bitmap.new(@width, @height)
end
def set_align_xy
h = @height + 24
@backdrop.x = @center_x
@backdrop.y = 140 + @index * h
end
def reset_alignment
set_align_xy
@label.x = @backdrop.x
@label.y = @backdrop.y
end
def x
@backdrop.x
end
def y
@backdrop.y
end
def set_text(text)
@text = text
bit = @label.bitmap
bit.clear
bit.draw_text(@rect, text, @align_x)
end
def dispose
@label.bitmap.dispose
@label.dispose
@backdrop.bitmap.dispose
@backdrop.dispose
end
attr_reader :text
end
class Spriteset
def initialize
@curse_viewport = Viewport.new
@curse_viewport.z = 500
@curse_boxes = []
@curse_x = []
@curse_y = []
filename = KursedVictory::OPTION_BACKDROP
options = KursedVictory::OPTIONS
options.each_with_index do |choice, n|
box = KursedVictory::TextBox.new(n, options.size, @curse_viewport)
box.set_image(filename)
box.set_text(choice)
@curse_x << box.x
@curse_y << box.y + KursedVictory::CURSOR_OY
@curse_boxes << box
end
@cursed_cursor = Sprite.new(@curse_viewport)
@cursed_cursor.x = @curse_x[0]
@cursed_cursor.y = @curse_y[0]
@cursed_cursor.z = 100
@cursed_cursor.bitmap = Cache.picture(KursedVictory::CURSOR)
end
def move_cursor(index)
@cursed_cursor.y = @curse_y[index]
end
def dispose
@curse_boxes.each {|box| box.dispose }
@cursed_cursor.bitmap.dispose
@cursed_cursor.dispose
@curse_viewport.dispose
end
end
end
class << BattleManager
alias :kyon_kurvic_btlman_proc_victor :process_victory
def process_victory
process_cursed_victory
if @cursed_victory and $game_party.all_dead_now?
process_defeat
return true
end
kyon_kurvic_btlman_proc_victor
start_anti_curse_battle if @curse_lifted
@curse_lifted = nil
true
end
def process_cursed_victory
return if KursedVictory::CURSE_CHANCE < rand(100)
return unless $game_troop.curse_flawless_victory?
return if $game_party.dead_members.size > 0
RPG::BGM.stop
@bgs = RPG::BGS.new(KursedVictory::BGS)
@bgs.play
@scene = SceneManager.scene
@scene.create_cursed_message
@scene.start_cursed_victory
end
def start_anti_curse_battle
RPG::BGM.stop
RPG::BGS.stop
$game_party.clear_actions
$game_troop.clear
$game_troop.setup(@next_troop_id)
@next_troop_id = nil
Sound.play_battle_start
BattleManager.play_battle_bgm
SceneManager.call(Scene_Battle)
end
attr_writer :cursed_victory, :next_troop_id
attr_accessor :curse_lifted
end
class Scene_Battle
def create_cursed_message
wx = (Graphics.width - 280) / 2
@cursed_message = CursedMessageWindow.new(wx, 40)
@info_viewport.visible = true
@party_command_window.contents.clear
@party_command_window.index = -1
@message_window.visible = false
@status_window.index = 0
@status_window.active = true
@outcome_window = KursedVictory::Message.new(0, 288, 544, 128)
@outcome_window.visible = false
end
def start_cursed_victory
troop_id = $game_troop.troop_id
@round2_data = KursedVictory::ROUND2_ENEMY_IDS[troop_id]
if @round2_data
process_cursed_victory_options
return if BattleManager.curse_lifted
end
process_cursed_victory_execution
end
def process_cursed_victory_options
@cursed_spriteset = KursedVictory::Spriteset.new
@curse_stage = 0
@curse_index = 0
while @curse_stage
Graphics.update
Input.update
update_cursed_victory
end
end
def update_cursed_victory
case @curse_stage
when 0
update_cursed_victory_options
when 1
update_cursed_victory_decision
end
end
def update_cursed_victory_options
if Input.trigger?(:UP) or Input.trigger?(:DOWN)
Sound.play_cursor
@curse_index = (@curse_index + 1) % 2
@cursed_spriteset.move_cursor(@curse_index)
return
elsif Input.trigger?(:C)
Sound.play_ok
name = @round2_data[:name]
if name
text = KursedVictory::OUTCOME[@curse_index]
text = sprintf(text, name)
end
@cursed_spriteset.dispose
if @curse_index == 1
RPG::BGS.stop
BattleManager.curse_lifted = true
BattleManager.next_troop_id = @round2_data[:troop_id]
@cursed_message.dispose
@cursed_message = nil
end
if name
@outcome_window.set_text(text)
@status_window.visible = false
@curse_stage = 1
else
@curse_stage = nil
end
end
end
def update_cursed_victory_decision
@outcome_window.update
if Input.trigger?(:C)
Sound.play_ok
state = @curse_index == 0
BattleManager.cursed_victory = state
@status_window.visible = state
@message_window.visible = !state
@outcome_window.dispose
@outcome_window = @curse_stage = nil
end
end
def process_cursed_victory_execution
while @curse_index
Graphics.update
Input.update
update_cursed_victory_execution
end
KursedVictory::WAIT_FRAMES.times { Graphics.update }
@message_window.visible = true
@cursed_message.dispose
@cursed_message = nil
end
def update_cursed_victory_execution
@status_window.update
if Input.trigger?(:C)
Sound.play_ok
n = @status_window.index
$game_party.members[n].add_state(1)
BattleManager.cursed_victory = nil
@status_window.refresh
@status_window.active = false
@curse_index = nil
end
end
end
Terms & Conditions
Free as in beer for non commercial games. 
Include my nickname in your game credits.
That's it!
RE: KursedVictory VX + ACE - kyonides - 09-07-2025
The Script Has Been Ported to VX ACE!
The VX ACE port features the same mechanism that might cause your team to lose a team member after obtaining a flawless victory. 
That does not exclude the possibility that you might still lose the battle if the last hero standing meets his demise then. 
Life is hard indeed. 
Just take a look at the screenshots if you don't believe me!
RE: KursedVictory VX + ACE - kyonides - 09-10-2025
The Script Has Been Improved!
Version 1.2.0 now offers you the possibility of complying or refusing to obey the evil lord's commands after obtaining a flawless victory. 
I guess you already know what that means: a second battle will ensure if you're stubborn enough to pick the second option! 
Just create a Hash entry like the following:
Code: ROUND2_ENEMY_IDS[1] = { :troop_id => 3 }
The first number is the original troop ID while the second one belongs to the next troop ID.
Please make sure the next troop ID has NEVER been included in the ENEMY_IDS array.
And yes, the battle will take place soon enough if the party ever dare to defy the dark lord!
If you ever want to show a brief reaction no matter which choice you pick, you can modify that entry this way:
VX Setup
Code: ROUND2_ENEMY_IDS[1] = { :name => "Basilisk", :troop_id => 2 }
VX ACE Setup
Code: ROUND2_ENEMY_IDS[1] = { name: "Basilisk", troop_id: 2 }
For Both Engines
Add this Array to the script or modify the existing one:
Code: OUTCOME = ["You complied with the %s's demand.",
"You refused to listen to %s."]
|