This system allows you to increase your stats using exp obtained. This gives the player greater customization over the character's growth during the game.
Features
*Increase stats using exp *Resetting (all) stats *Level up when you spend exp
Script
Script
CODE
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # Exp Distribution System by Tsukihime # Adapted from Blizzard's DP Distribution system # Version: 1.02 # Nov 8, 2011 #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # # Change log # # v1.00 Nov 2, 2011 - initial release # v1.01 Nov 6, 2011 - stat reset added, leveling removed # v1.02 Nov 8, 2011 - leveling re-added, fixed bugs related to exp and level # # Features: # # - distribute exp 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 # # Configuration (needs to be updated): # # Set up the configuration below. # # HP_EXP_COST - how much EXP does 1 HP cost # SP_EXP_COST - how much EXP does 1 SP cost # STR_EXP_COST - how much EXP does 1 STR cost # DEX_EXP_COST - how much EXP does 1 DEX cost # AGI_EXP_COST - how much EXP does 1 AGI cost # INT_EXP_COST - how much EXP does 1 INT cost # AUTO_CALL - set to true to have the scene called automatically after # battles if at least one character got leveled up # AUTO_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 # DISPLAY_ICON - displays an icon on the map if ANY character in the # party has any points to distribute # OWN_ICON - use an own icon for display, false for no or filename of # your own icon (the icon has to be in the Icons folder) # ICON_X - icon X coordinate # ICON_Y - icon Y coordinate # ICON_OPACITY - icon Y opacity # WINDOW_MODE - set to true to have the command windows at the bottom, set # to false to have them to at the top # # This system replaces the default leveling system. You will only level up # when you have allocated a certain amount of exp (based on the exp tables # that you define). # # You can call the Scene by using a "Call script" event command. Type into # the editor window this text: # # $scene = Scene_Points.new #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
def level=(level) # Check up and down limits level = [[level, $data_actors[@actor_id].final_level].min, 1].max # Don't change EXP ##self.exp = @exp_list[level] end
def exp_spent=(exp) @exp_spent = [[exp, 999999].min, 0].max while @exp_spent >= @exp_list[@level+1] and @exp_list[@level+1] > 0 @level += 1 # Learn skill for j in $data_classes[@class_id].learnings if j.level == @level learn_skill(j.skill_id) end end end # Level down while @exp_spent < @exp_list[@init_level] - @exp_list[@level] @level -= 1 end # Correction if exceeding current max HP and max SP @hp = [@hp, self.maxhp].min @sp = [@sp, self.maxsp].min end
#The following methods override stat increases when leveling #-------------------------------------------------------------------------- # * Get Basic Maximum HP #-------------------------------------------------------------------------- def base_maxhp return $data_actors[@actor_id].parameters[0, @init_level] end #-------------------------------------------------------------------------- # * Get Basic Maximum SP #-------------------------------------------------------------------------- def base_maxsp return $data_actors[@actor_id].parameters[1, @init_level] end #-------------------------------------------------------------------------- # * Get Basic Strength #-------------------------------------------------------------------------- def base_str n = $data_actors[@actor_id].parameters[2, @init_level] weapon = $data_weapons[@weapon_id] armor1 = $data_armors[@armor1_id] armor2 = $data_armors[@armor2_id] armor3 = $data_armors[@armor3_id] armor4 = $data_armors[@armor4_id] n += weapon != nil ? weapon.str_plus : 0 n += armor1 != nil ? armor1.str_plus : 0 n += armor2 != nil ? armor2.str_plus : 0 n += armor3 != nil ? armor3.str_plus : 0 n += armor4 != nil ? armor4.str_plus : 0 return [[n, 1].max, 999].min end #-------------------------------------------------------------------------- # * Get Basic Dexterity #-------------------------------------------------------------------------- def base_dex n = $data_actors[@actor_id].parameters[3, @init_level] weapon = $data_weapons[@weapon_id] armor1 = $data_armors[@armor1_id] armor2 = $data_armors[@armor2_id] armor3 = $data_armors[@armor3_id] armor4 = $data_armors[@armor4_id] n += weapon != nil ? weapon.dex_plus : 0 n += armor1 != nil ? armor1.dex_plus : 0 n += armor2 != nil ? armor2.dex_plus : 0 n += armor3 != nil ? armor3.dex_plus : 0 n += armor4 != nil ? armor4.dex_plus : 0 return [[n, 1].max, 999].min end #-------------------------------------------------------------------------- # * Get Basic Agility #-------------------------------------------------------------------------- def base_agi n = $data_actors[@actor_id].parameters[4, @init_level] weapon = $data_weapons[@weapon_id] armor1 = $data_armors[@armor1_id] armor2 = $data_armors[@armor2_id] armor3 = $data_armors[@armor3_id] armor4 = $data_armors[@armor4_id] n += weapon != nil ? weapon.agi_plus : 0 n += armor1 != nil ? armor1.agi_plus : 0 n += armor2 != nil ? armor2.agi_plus : 0 n += armor3 != nil ? armor3.agi_plus : 0 n += armor4 != nil ? armor4.agi_plus : 0 return [[n, 1].max, 999].min end #-------------------------------------------------------------------------- # * Get Basic Intelligence #-------------------------------------------------------------------------- def base_int n = $data_actors[@actor_id].parameters[5, @init_level] weapon = $data_weapons[@weapon_id] armor1 = $data_armors[@armor1_id] armor2 = $data_armors[@armor2_id] armor3 = $data_armors[@armor3_id] armor4 = $data_armors[@armor4_id] n += weapon != nil ? weapon.int_plus : 0 n += armor1 != nil ? armor1.int_plus : 0 n += armor2 != nil ? armor2.int_plus : 0 n += armor3 != nil ? armor3.int_plus : 0 n += armor4 != nil ? armor4.int_plus : 0 return [[n, 1].max, 999].min end end
def refresh self.contents.clear (0...@item_max).each {|i| draw_item(i)} end
def draw_item(i) y = i * 32 self.contents.fill_rect(0, y, self.contents.width, 32, Color.new(0, 0, 0, 0)) self.contents.font.color = system_color self.contents.draw_text(4, y, 80, 32, @words[i]) self.contents.draw_text(344, y, 40, 32, BlizzCFG::DPName) self.contents.draw_text(180, y, 12, 32, '/', 1) self.contents.draw_text(192, y, 64, 32, @current[i].to_s) self.contents.font.color = normal_color self.contents.draw_text(276, y, 64, 32, BlizzCFG::ExchangeRates[i].to_s, 2) font, self.contents.font.name = self.contents.font.name, 'Arial' size, self.contents.font.size = self.contents.font.size, 32 bold, self.contents.font.bold = self.contents.font.bold, true self.contents.draw_text(104, y - 2, 24, 32, '«') self.contents.draw_text(244, y - 2, 24, 32, '»', 2) self.contents.font.bold = bold self.contents.font.size = size self.contents.font.bold = bold self.contents.font.color = BlizzCFG::ColorIncreased if @spent[i] > 0 self.contents.draw_text(116, y, 64, 32, (@current[i] + @spent[i] / BlizzCFG::ExchangeRates[i]).to_s, 2) end
def add_points(value) value *= BlizzCFG::ExchangeRates[index] limit = @actor.exp - @spent.sum value = limit if value > limit value /= BlizzCFG::ExchangeRates[index] limit = BlizzCFG::AttrLimits[index] - (@current[index] + @spent[index]) value = limit if value > limit if value > 0 @spent[index] += value * BlizzCFG::ExchangeRates[index] return true end return false end
def remove_points(value) value *= BlizzCFG::ExchangeRates[index] limit = spent.sum value = limit if value > limit value = @spent[index] if value > @spent[index] value /= BlizzCFG::ExchangeRates[index] if value > 0 @spent[index] -= value * BlizzCFG::ExchangeRates[index] 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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 super end end
Edit the constants under the "START CONFIGURATION" section.
compatibility
The menu was modified based on the default menu. You will have to modify the appropriate sections if you want to use a custom menu system (just the status window)
May not be compatible with any scripts that change the game actor class, or the exp system, or the leveling system
Bugs
When resetting stats, HP/SP is set to the previous maximum. I know why it happens, but not sure how to fix it.
Installation
Copy script above main.
Credits
Blizzard, for writing the DP system that this script was adapted from. Night_Runner, for adding features like reset and updating the menu to make more sense
This post has been edited by Tsukihime: Nov 8 2011, 06:38 PM
Group: +Gold Member
Posts: 1,528
Type: Scripter
RM Skill: Undisclosed
Would you like me to move this over to script submissions?
And also, I've tweaked the code, I've removed levelling up, it caused bugs ( I received 200 exp, spent about 40 (going from 741 - 780) on increasing max HP, and when I close and return I would have levelled up, causing my MaxHP to jump to 880 or so ), which means you have to manually learn skills, which isn't such a big deal.
I've also removed the 'exp until next level' from the menu and status menu, although the status menu isn't as elegant and will probably not work well with any oterh scripts that change class Window_MenuStatus.
And I think the last thing I changed, you mentioned reverting to default stats, I've added an option for it
code
CODE
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # Exp Distribution System by Tsukihime # Adapted from Blizzard's DP Distribution system # Version: 1.00 # Nov 2, 2011 #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # # Features: # # - distribute exp 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 # # Configuration (needs to be updated): # # Set up the configuration below. # # HP_DP_COST - how many DP does 1 HP cost # SP_DP_COST - how many DP does 1 SP cost # STR_DP_COST - how many DP does 1 STR cost # DEX_DP_COST - how many DP does 1 DEX cost # AGI_DP_COST - how many DP does 1 AGI cost # INT_DP_COST - how many DP does 1 INT cost # AUTO_CALL - set to true to have the scene called automatically after # battles if at least one character got leveled up # AUTO_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 # DISPLAY_ICON - displays an icon on the map if ANY character in the # party has any points to distribute # OWN_ICON - use an own icon for display, false for no or filename of # your own icon (the icon has to be in the Icons folder) # ICON_X - icon X coordinate # ICON_Y - icon Y coordinate # ICON_OPACITY - icon Y opacity # WINDOW_MODE - set to true to have the command windows at the bottom, set # to false to have them to at the top # # This system replaces the default leveling system. You will only level up # when you have allocated a certain amount of exp (based on the exp tables # that you define). # # You can call the Scene by using a "Call script" event command. Type into # the editor window this text: # # $scene = Scene_Points.new #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
alias setup_sds_later setup def setup(actor_id) @exp_spent = 0 setup_sds_later(actor_id) end
def exp=(exp) @exp = [[exp, 9999999].min, 0].max
end
def exp_spent=(exp) @exp_spent = [[exp, 999999].min, 0].max # Correction if exceeding current max HP and max SP @hp = [@hp, self.maxhp].min @sp = [@sp, self.maxsp].min end end
def refresh self.contents.clear (0...@item_max).each {|i| draw_item(i)} end
def draw_item(i) y = i * 32 self.contents.fill_rect(0, y, self.contents.width, 32, Color.new(0, 0, 0, 0)) self.contents.font.color = system_color self.contents.draw_text(4, y, 80, 32, @words[i]) self.contents.draw_text(344, y, 40, 32, BlizzCFG::DPName) self.contents.draw_text(180, y, 12, 32, '/', 1) self.contents.draw_text(192, y, 64, 32, @current[i].to_s) self.contents.font.color = normal_color self.contents.draw_text(276, y, 64, 32, BlizzCFG::ExchangeRates[i].to_s, 2) font, self.contents.font.name = self.contents.font.name, 'Arial' size, self.contents.font.size = self.contents.font.size, 32 bold, self.contents.font.bold = self.contents.font.bold, true self.contents.draw_text(104, y - 2, 24, 32, '«') self.contents.draw_text(244, y - 2, 24, 32, '»', 2) self.contents.font.bold = bold self.contents.font.size = size self.contents.font.bold = bold self.contents.font.color = BlizzCFG::ColorIncreased if @spent[i] > 0 self.contents.draw_text(116, y, 64, 32, (@current[i] + @spent[i] / BlizzCFG::ExchangeRates[i]).to_s, 2) end
def add_points(value) value *= BlizzCFG::ExchangeRates[index] limit = @actor.exp - @spent.sum value = limit if value > limit value /= BlizzCFG::ExchangeRates[index] limit = BlizzCFG::AttrLimits[index] - (@current[index] + @spent[index]) value = limit if value > limit if value > 0 @spent[index] += value * BlizzCFG::ExchangeRates[index] return true end return false end
def remove_points(value) value *= BlizzCFG::ExchangeRates[index] limit = spent.sum value = limit if value > limit value = @spent[index] if value > @spent[index] value /= BlizzCFG::ExchangeRates[index] if value > 0 @spent[index] -= value * BlizzCFG::ExchangeRates[index] 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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) draw_item(self.index) 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 super end end
alias main_sds_later main def main main_sds_later if BlizzCFG::AUTO_CALL && $game_party.actors.any? {|actor| actor.exp > 0} $scene = Scene_Points.new end end
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 BlizzCFG::AUTO_MAP_CALL && $game_party.actors.any? {|actor| actor.exp > 0} $scene = Scene_Points.new end end
I'll change the opening post at some point to make it more formal. I'll have to update the script as well since I've left in things that won't be needed.
I'll PM when that is done.
This post has been edited by Tsukihime: Nov 7 2011, 10:30 AM
Leveling up has been re-added and the issue with stat increases has been addressed somewhat. I over-rid the methods in Game_Actor that returned the "basic" stat like base HP and base str so that they return the initial level rather than the character's current level
What if a character is supposed to start at a fixed level? He'll have a bunch of exp available to distribute based on the exp table, but his stats are all level 1 stats.
This doesn't really work if you're in a game where you have NPC characters join you temporarily, which is pretty common.
There was a bug where if the player's initial level > 1, you're given a bunch of exp, but if you decided to spend only some of it, it'll lower your level just because the amount of exp you spent is lower than what you're "supposed" to have.
I've added a new attribute called "init_level" which stores the actor's initial level. The lower-bound for exp has simply been changed from your current level to your initial level.
So if you started at lv 50 and didn't spend any exp, you're not going to level down just because you didn't spend any exp.
Storing the initial level also allows me to initialize a character at level 50 with the specified level 50 stats. Of course, this means you won't be able to customize 50 levels worth of exp, but I decided to compromise between full customizability and a headache when trying to deal with initializing level 50 NPC characters that join you temporarily in the middle of the battle.
I have changed the exp so that the character is initialized with 0 exp rather than the amount of exp required at each level. So a level 50 character will have no exp to distribute.
This may cause problems because if you make it so that it does not cost a lot to increase your stats, the character that you started with might be many times stronger than a level 50 character that you recruited in the middle of the game.
I am not sure how to balance this. Perhaps the character should be initialized with "initial level" stats and also be given all of the exp for that level?
Code in initial post has been changed to reflect updates.
Night_Runner - Moved as per request
This post has been edited by Night_Runner: Nov 9 2011, 01:11 AM