I've added the Stat Distribution System by Blizzard, and the problem I'm running into is that it doesn't work with old saved game files. When I try to load an old saved game, it gives me the error "undefined method > for Nil:NilClass"
The reason (as far as I can tell) is that any new game is created with an additional module/class which includes a variable "points" for each actor. Does anyone know if it's possible to add this module into an existing saved game, either in the Load Game menu or otherwise?
Here's the full script. The section "class Game_Actor < Game_Battler" is where the variable "points" is added, and I'm wondering if there's a way to "inject" that into an existing saved game.
The reason (as far as I can tell) is that any new game is created with an additional module/class which includes a variable "points" for each actor. Does anyone know if it's possible to add this module into an existing saved game, either in the Load Game menu or otherwise?
Here's the full script. The section "class Game_Actor < Game_Battler" is where the variable "points" is added, and I'm wondering if there's a way to "inject" that into an existing saved game.
Code:
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# Stat Distribution System by Blizzard
# Version: 1.33b
# Type: Actor Attribute Modifier
# Date: 25.3.2007
# Date v1.1b: 6.4.2007
# Date v1.2b: 22.8.2007
# Date v1.3b: 12.9.2007
# Date v1.33b: 5.11.2007
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
# This work is protected by the following license:
# #----------------------------------------------------------------------------
# #
# # Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
# # ( http://creativecommons.org/licenses/by-nc-sa/3.0/ )
# #
# # You are free:
# #
# # to Share - to copy, distribute and transmit the work
# # to Remix - to adapt the work
# #
# # Under the following conditions:
# #
# # Attribution. You must attribute the work in the manner specified by the
# # author or licensor (but not in any way that suggests that they endorse you
# # or your use of the work).
# #
# # Noncommercial. You may not use this work for commercial purposes.
# #
# # Share alike. If you alter, transform, or build upon this work, you may
# # distribute the resulting work only under the same or similar license to
# # this one.
# #
# # - For any reuse or distribution, you must make clear to others the license
# # terms of this work. The best way to do this is with a link to this web
# # page.
# #
# # - Any of the above conditions can be waived if you get permission from the
# # copyright holder.
# #
# # - Nothing in this license impairs or restricts the author's moral rights.
# #
# #----------------------------------------------------------------------------
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
# Compatibility:
#
# 99% compatible with SDK v1.x. 80% compatible with SDK 2.x. WILL corrupt
# your old savegames. Might cause problems with custom leveling up systems.
# 99% compatibility with everything else.
#
#
# Features:
#
# - distribute points between different stats
# - extra scene for point distribution with confirmation window at the end
# - calls the "caller scene" automatically when finished
# - add points by easily pressing RIGHT/LEFT
# - hold Q to add 10 points at once
# - hold W to add 100 points at once
# - a Stat Distribution System that actually works like it should...
#
# new in v1.1b:
# - added option to call the Points Scene after a fight with level ups
# - customizable icon position and opacity
#
# new in v1.2b:
# - improved coding and made code shorter
# - rewritten conditions using classic syntax to avoid RGSS conditioning bug
#
# new in v1.3b:
# - improved coding
# - fixed bug with AUTOMATIC_CALL after battle
# - new AUTOMATIC_MAP_CALL works on the map as well (that means it's fully
# compatible with Blizz-ABS)
#
# new in v1.33b:
# - improved coding
# - improved compatibility
# - fixed a little glitch
#
#
# Configuration:
#
# Set up the configuration below.
#
# STARTING_POINTS - how many points should the actor have initially at
# level 1
# POINTS_PER_LEVEL - how many points should the actor gain per level
# DISPLAY_ICON - displays an icon on the map if ANY character in the
# party has any points to distribute
# ICON_DATA - some custom options for your icon: [X, Y, OPACITY]
# the default values are [612, 452, 192]
# OWN_ICON - use an own icon for display (the icon has to be in the
# Icons folder and must be named "point_notify")
# EVASION - the name that should be displayed for "Evasion"
# STR_LIMIT - max possible STR
# DEX_LIMIT - max possible DEX
# AGI_LIMIT - max possible AGI
# INT_LIMIT - max possible INT
# WINDOW_MODE - set to true to have the windows at the left, set to
# false to have them to at the right
# AUTOMATIC_CALL - set to true to have the scene called automatically
# after battles if at least one character got leveled up
# AUTOMATIC_MAP_CALL - set to true to have the scene called automatically on
# the map if at least one character got leveled up
# (this works for Blizz-ABS as well), also note that
# this will cause the scene to called over and over as
# long as not all points were distributed
#
#
# You can always add stat points yourself by using following syntax:
#
# $game_party.actors[X].add_stat_points(Z)
# $game_actors[Y].add_stat_points(Z)
#
# Or you can remove them (how much sense it does is up to you...):
#
# $game_party.actors[X].remove_stat_points(Z)
# $game_actors[Y].remove_stat_points(Z)
#
# X - position of actor in the party (STARTS FROM ZERO!)
# Y - ID of actor in the database
# Z - value
#
# You can call the Scene by using a "Call script" event command. Type into
# the editor window this text:
#
# $scene = Scene_Points.new
#
#
# Side Note:
#
# Decreasing the level of an actor won't remove his gained stat points. You
# MUST do it manually.
#
#
# If you find any bugs, please report them here:
# http://forum.chaos-project.com
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
module BlizzCFG
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# START Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
STARTING_POINTS = 0
POINTS_PER_LEVEL = 5
DISPLAY_ICON = true
ICON_DATA = [612, 452, 192]
OWN_ICON = false
EVASION = 'EVA'
STR_LIMIT = 999
DEX_LIMIT = 999
AGI_LIMIT = 999
INT_LIMIT = 999
WINDOW_MODE = true
AUTOMATIC_CALL = true
AUTOMATIC_MAP_CALL = false
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# END Configuration
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ATTR_LIMITS = [STR_LIMIT, DEX_LIMIT, AGI_LIMIT, INT_LIMIT]
# ensures compatibility
$stat_system = 1.33
end
#==============================================================================
# Array
#==============================================================================
class Array
def sum
result = 0
self.each {|i| result += i if i.is_a?(Numeric)}
return result
end
end
#==============================================================================
# Game_Actor
#==============================================================================
class Game_Actor < Game_Battler
attr_reader :points
alias setup_sds_later setup
def setup(actor_id)
@points = BlizzCFG::STARTING_POINTS
setup_sds_later(actor_id)
end
alias exp_sds_later exp=
def exp=(exp)
old_level = @level
exp_sds_later(exp)
add_stat_points((@level - old_level) * BlizzCFG::POINTS_PER_LEVEL)
end
def add_stat_points(val)
@points += val if val > 0
end
def remove_stat_points(val)
@points = [@points-val, 0].max
end
end
#==============================================================================
# Window_Base
#==============================================================================
class Window_Base < Window
def draw_actor_battler(actor, x, y)
bitmap = RPG::Cache.battler(actor.battler_name, actor.battler_hue)
cw, ch = bitmap.width, bitmap.height
src_rect = Rect.new(0, 0, cw, ch)
self.contents.blt(x - cw/2, y - ch/2, bitmap, src_rect)
end
alias draw_actor_parameter_sds_later draw_actor_parameter
def draw_actor_parameter(actor, x, y, type)
if type == 7
self.contents.font.color = system_color
self.contents.draw_text(x, y, 120, 32, BlizzCFG::EVASION)
self.contents.font.color = normal_color
self.contents.draw_text(x + 120, y, 36, 32, actor.eva.to_s, 2)
else
draw_actor_parameter_sds_later(actor, x, y, type)
end
end
end
#==============================================================================
# Window_Distribution_Status
#==============================================================================
class Window_Distribution_Status < Window_Base
attr_accessor :actor
def initialize(actor)
super(BlizzCFG::WINDOW_MODE ? 160 : 0, 0, 480, 480)
@actor = actor
self.contents = Bitmap.new(width - 32, height - 32)
if $fontface != nil
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
elsif $defaultfonttype != nil
self.contents.font.name = $defaultfonttype
self.contents.font.size = $defaultfontsize
end
refresh
end
def refresh
self.contents.clear
unless @actor == nil
draw_actor_battler(@actor, 280, 120)
draw_actor_name(@actor, 4, 0)
draw_actor_class(@actor, 4, 32)
draw_actor_level(@actor, 4, 64)
draw_actor_state(@actor, 4, 96)
self.contents.font.color = system_color
self.contents.draw_text(4, 128, 80, 32, 'EXP')
self.contents.draw_text(4, 160, 80, 32, 'next')
self.contents.font.color = normal_color
self.contents.draw_text(4, 128, 156, 32, @actor.exp_s, 2)
self.contents.draw_text(4, 160, 156, 32, @actor.next_rest_exp_s, 2)
draw_actor_hp(@actor, 4, 224, 172)
draw_actor_sp(@actor, 4, 256, 172)
draw_actor_parameter(@actor, 4, 320, 0)
draw_actor_parameter(@actor, 4, 352, 1)
draw_actor_parameter(@actor, 4, 384, 2)
draw_actor_parameter(@actor, 4, 416, 7)
self.contents.font.color = system_color
self.contents.draw_text(240, 240, 96, 32, 'Equipment')
draw_item_name($data_weapons[@actor.weapon_id], 240, 288)
draw_item_name($data_armors[@actor.armor1_id], 240, 320)
draw_item_name($data_armors[@actor.armor2_id], 240, 352)
draw_item_name($data_armors[@actor.armor3_id], 240, 384)
draw_item_name($data_armors[@actor.armor4_id], 240, 416)
end
end
end
#==============================================================================
# Window_Distribution
#==============================================================================
class Window_Distribution < Window_Selectable
attr_accessor :actor
attr_reader :points
def initialize(actor)
super(BlizzCFG::WINDOW_MODE ? 0 : 480, 160, 160, 320)
self.contents = Bitmap.new(width - 32, height - 32)
if $fontface != nil
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
elsif $defaultfonttype != nil
self.contents.font.name = $defaultfonttype
self.contents.font.size = $defaultfontsize
end
self.active, self.index, = false, 0
@item_max, @actor, @att, @points = 4, actor, [0, 0, 0, 0], 0
refresh
end
def set_new_attributes
@actor.str += @att[0]
@actor.dex += @att[1]
@actor.agi += @att[2]
@actor.int += @att[3]
@actor.remove_stat_points(@points)
end
def actor=(actor)
@actor = actor
@att[0] = @att[1] = @att[2] = @att[3] = @points = 0
end
def refresh
self.contents.clear
unless @actor == nil
self.contents.font.color = system_color
self.contents.draw_text(52, 0, 72, 32, 'DP left', 2)
self.contents.draw_text(4, 32, 120, 32, $data_system.words.str)
self.contents.draw_text(4, 96, 120, 32, $data_system.words.dex)
self.contents.draw_text(4, 160, 120, 32, $data_system.words.agi)
self.contents.draw_text(4, 224, 120, 32, $data_system.words.int)
self.contents.font.color = normal_color
self.contents.draw_text(4, 0, 48, 32, "#{actor.points-@points}", 2)
self.contents.draw_text(36, 64, 56, 32, "#{@actor.str+@att[0]}", 2)
self.contents.draw_text(36, 128, 56, 32, "#{@actor.dex+@att[1]}", 2)
self.contents.draw_text(36, 192, 56, 32, "#{@actor.agi+@att[2]}", 2)
self.contents.draw_text(36, 256, 56, 32, "#{@actor.int+@att[3]}", 2)
self.contents.font.size += 8
self.contents.font.bold = true
(0...4).each {|i|
self.contents.draw_text(0, (i + 1) * 64 - 8, 32, 42, '«', 2)
self.contents.draw_text(96, (i + 1) * 64 - 8, 32, 42, '»')}
self.contents.font.bold = false
self.contents.font.size -= 8
end
end
def add_points(num)
attr = [@actor.str, @actor.dex, @actor.agi, @actor.int]
if @points < @actor.points &&
attr[index]+@att[index] < BlizzCFG::ATTR_LIMITS[index]
@points = [@points + num, @actor.points].min
@att[index] = [@att[index]+num, @points+@att[index]-@att.sum].min
return true
end
return false
end
def remove_points(num)
if @points > 0 && @att[index] > 0
@points = [@points - num, 0].max
@att[index] = [@att[index] - num, 0].max
return true
end
return false
end
def update
super
return unless self.active
if Input.press?(Input::R)
if Input.repeat?(Input::RIGHT)
if add_points(100)
$game_system.se_play($data_system.cursor_se)
refresh
else
$game_system.se_play($data_system.buzzer_se)
end
elsif Input.repeat?(Input::LEFT)
if remove_points(100)
$game_system.se_play($data_system.cursor_se)
refresh
else
$game_system.se_play($data_system.buzzer_se)
end
end
elsif Input.press?(Input::L)
if Input.repeat?(Input::RIGHT)
if add_points(10)
$game_system.se_play($data_system.cursor_se)
refresh
else
$game_system.se_play($data_system.buzzer_se)
end
elsif Input.repeat?(Input::LEFT)
if remove_points(10)
$game_system.se_play($data_system.cursor_se)
refresh
else
$game_system.se_play($data_system.buzzer_se)
end
end
elsif Input.repeat?(Input::RIGHT)
if add_points(1)
$game_system.se_play($data_system.cursor_se)
refresh
else
$game_system.se_play($data_system.buzzer_se)
end
elsif Input.repeat?(Input::LEFT)
if remove_points(1)
$game_system.se_play($data_system.cursor_se)
refresh
else
$game_system.se_play($data_system.buzzer_se)
end
end
end
def update_cursor_rect
if @index < 0 || !self.active
self.cursor_rect.empty
else
self.cursor_rect.set(32, (@index+1)*64, 64, 32)
end
end
end
#==============================================================================
# Window_Sure
#==============================================================================
class Window_Sure < Window_Command
attr_accessor :actor
def initialize(width, commands)
commands.push('')
super
@item_max, self.index = commands.size - 1, 0
self.x, self.y, self.z = 320-self.width/2, 240-self.height/2, 10000
refresh
end
def refresh
super
self.contents.font.color = system_color
self.contents.draw_text(4, 0, self.contents.width - 8, 32, 'Are you sure?', 1)
end
def draw_item(index, color)
self.contents.font.color = color
rect = Rect.new(4, 32 * (index+1), self.contents.width - 8, 32)
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
self.contents.draw_text(rect, @commands[index], 1)
end
def update_cursor_rect
if @index < 0
self.cursor_rect.empty
else
self.cursor_rect.set(32, (@index+1)*32, self.contents.width - 64, 32)
end
end
end
#==============================================================================
# Scene_Points
#==============================================================================
class Scene_Points
def initialize
@actor, @scene = $game_party.actors[0], $scene.class
end
def main
commands = ['Distribute', 'Next', 'Previous', 'Finish']
@command_window = Window_Command.new(160, commands)
@command_window.x = (BlizzCFG::WINDOW_MODE ? 0 : 480)
@status_window = Window_Distribution_Status.new(@actor)
@distro_window = Window_Distribution.new(@actor)
Graphics.transition
loop do
Graphics.update
Input.update
update
break if $scene != self
end
Graphics.freeze
[@command_window, @status_window, @distro_window].each {|win| win.dispose}
end
def make_sure_window
commands = ['Cancel', 'Accept changes', 'Discard changes']
@sure_window = Window_Sure.new(256, commands)
end
def update
if @command_window.active
@command_window.update
update_main_command
elsif @sure_window != nil
@sure_window.update
update_sure
elsif @distro_window.active
@distro_window.update
if Input.trigger?(Input::B)
$game_system.se_play($data_system.cancel_se)
@command_window.active, @distro_window.active = true, false
end
end
end
def update_main_command
if Input.trigger?(Input::B)
$game_system.se_play($data_system.cancel_se)
if @distro_window.points != 0
@command_window.index, @command_window.active = 3, false
make_sure_window
else
$scene = @scene.new
end
elsif Input.trigger?(Input::C)
$game_system.se_play($data_system.decision_se)
case @command_window.index
when 0 then @command_window.active, @distro_window.active = false, true
when 1
if @distro_window.points != 0
@command_window.active = false
make_sure_window
else
i = (@actor.index+1) % $game_party.actors.size
@actor = @status_window.actor = @distro_window.actor = $game_party.actors[i]
[@status_window, @distro_window].each {|win| win.refresh}
@distro_window.index = 0
end
when 2
if @distro_window.points != 0
@command_window.active = false
make_sure_window
else
i = (@actor.index+$game_party.actors.size-1) % $game_party.actors.size
@actor = @status_window.actor = @distro_window.actor = $game_party.actors[i]
[@status_window, @distro_window].each {|win| win.refresh}
@distro_window.index = 0
end
when 3
if @distro_window.points != 0
@command_window.active = false
make_sure_window
else
$scene = @scene.new
end
end
end
end
def update_sure
if Input.trigger?(Input::B)
$game_system.se_play($data_system.cancel_se)
@sure_window.dispose
@sure_window, @command_window.active = nil, true
elsif Input.trigger?(Input::C)
$game_system.se_play($data_system.decision_se)
case @command_window.index
when 1
if @sure_window.index > 0
@distro_window.set_new_attributes if @sure_window.index == 1
i = (@actor.index+1) % $game_party.actors.size
@actor = @status_window.actor = @distro_window.actor = $game_party.actors[i]
[@status_window, @distro_window].each {|win| win.refresh}
end
@sure_window.dispose
@sure_window, @command_window.active = nil, true
when 2
if @sure_window.index > 0
@distro_window.set_new_attributes if @sure_window.index == 1
i = (@actor.index+$game_party.actors.size-1) % $game_party.actors.size
@actor = @status_window.actor = @distro_window.actor = $game_party.actors[i]
[@status_window, @distro_window].each {|win| win.refresh}
end
@sure_window.dispose
@sure_window, @command_window.active = nil, true
when 3
if @sure_window.index > 0
@distro_window.set_new_attributes if @sure_window.index == 1
$scene = @scene.new
end
@sure_window.dispose
@sure_window, @command_window.active = nil, true
end
end
end
end
#==============================================================================
# Scene_Battle
#==============================================================================
class Scene_Battle
alias main_sds_later main
def main
main_sds_later
if BlizzCFG::AUTOMATIC_CALL &&
$game_party.actors.any? {|actor| actor.points > 0}
$game_switches[58] = 1
$scene = Scene_Points.new
end
end
end
#==============================================================================
# Scene_Map
#==============================================================================
class Scene_Map
alias main_sds_later main
def main
main_sds_later
@notify.dispose if @notify != nil
end
alias upd_sds_later update
def update
check_icon if BlizzCFG::DISPLAY_ICON
upd_sds_later
#if $game_party.actors.any? {|actor| actor.points > 0}
# $game_switches[58] = true
#end
end
def check_icon
if $game_party.actors.any? {|actor| actor.points > 0}
$game_switches[58] = true
if @notify == nil
@notify = RPG::Sprite.new
if BlizzCFG::OWN_ICON
@notify.bitmap = RPG::Cache.icon('point_notify')
else
@notify.bitmap = Bitmap.new(24, 24)
@notify.bitmap.fill_rect(0, 0, 24, 24, Color.new(255, 255, 255))
@notify.bitmap.fill_rect(22, 1, 2, 23, Color.new(0, 0, 0))
@notify.bitmap.fill_rect(1, 22, 23, 2, Color.new(0, 0, 0))
@notify.bitmap.set_pixel(23, 0, Color.new(0, 0, 0))
@notify.bitmap.set_pixel(0, 23, Color.new(0, 0, 0))
@notify.bitmap.fill_rect(2, 2, 20, 20, Color.new(0, 0, 224))
@notify.bitmap.fill_rect(4, 10, 16, 4, Color.new(255, 255, 255))
@notify.bitmap.fill_rect(10, 4, 4, 16, Color.new(255, 255, 255))
@notify.opacity = BlizzCFG::ICON_DATA[2]
end
@notify.x, @notify.y = BlizzCFG::ICON_DATA[0, 2]
@notify.z = 5000
@notify.blink_on
end
@notify.update
elsif @notify != nil
@notify.dispose
@notify = nil
end
end
end