Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ############################################
- # #
- # UTILITY SCALING SCRIPT #
- # #
- # v1.0 for RPG Maker VX Ace #
- # #
- # Created by Jason "Wavelength" Commander #
- # #
- ############################################
- # "I don't think limits."
- # ~ Usain Bolt
- ############################################
- # #
- # ABOUT THIS SCRIPT #
- # #
- ############################################
- # This script allows you to scale the Utility and Duration
- # of Status Effects based on the stats of the battler
- # that inflicted the status.
- # You can also set up these scaling effects based on the stats
- # of the battler that received the status, on a variable,
- # or, in theory, on almost anything else you'd like to.
- # As examples, you could create:
- #
- # * A poison state that inflicts higher degeneration rates
- # as the user's Magic stat grows stronger
- #
- # * A confusion state which will last for different lengths
- # of time depending on whether a weak monster or a powerful
- # boss was the one that used it on you
- #
- # * A vulnerability state that causes an enemy to take 1%
- # more Fire damage for each point of Luck you have
- #
- # * A fury state that gives an ally an extra attack for
- # every five "Rage Gems" the player owns
- #
- # * A regen state that will heal an ally each turn based on that
- # ally’s Strength stat instead of their Max HP
- # This script will likely *not* be compatible with other scripts that
- # alias or overwrite methods dealing with adding states to
- # battlers. I will look into using more alias methods in order
- # to improve compatibility in future versions of this script.
- ############################################
- # #
- # TERMS OF USE #
- # #
- ############################################
- # Free to use for non-commercial projects - just credit me
- # A license is required to use this script in commercial or
- # semi-commercial projects. Please visit my website
- # wavescripts.wordpress.com for more info about obtaining
- # a license for my scripts.
- # You may freely share or modify this script, but you cannot
- # sell it (even if modified) without my written permission
- # Please preserve the header (with version #) and terms of use;
- # besides that, feel free to remove any commenting you please
- ############################################
- # #
- # ADDITIONAL THANKS #
- # #
- ############################################
- # Thanks to Tsukihime and Galv for their help learning Notetags.
- # This was the first time I've used them as a scripter and
- # their guides and help were invaluable.
- # Thanks to Riot Games for popularizing the idea of Utility
- # Scaling. I loved this concept the moment I saw it in
- # League of Legends and I hope that people can use my
- # script to implement this kind of thoughtful design.
- ############################################
- # #
- # HOW TO USE THIS SCRIPT #
- # #
- ############################################
- # This script should be placed in the "Materials" section
- # of the script editor. If you are using other shop
- # scripts, it's generally better to place this script
- # below those other scripts.
- # To add scaling to States in your database, tag them in the
- # "Note" field using the appropriate format.
- # You can add UTILITY SCALING to any State that contains Features
- # which include a numerical value. Use the following format:
- #
- # <scaling>
- # 1: (formula)
- # 2: (formula)
- # ...
- # (feature #): (formula)
- # <scaling end>
- # You can add DURATION SCALING to any State, even those without
- # Features. Use the following format:
- #
- # <duration (add/set/mult): (formula)>
- ############################################
- # #
- # EXAMPLES AND NOTES ON USAGE #
- # #
- ############################################
- # UTILITY SCALING:
- # For example, let's say you want to create a state that gives
- # X additional attacks to an ally, gives them the Substitute
- # property, and heals them by X percent each turn, where X is
- # the Magic Attack of the user who applies the state. Set up
- # a State with the Atk Times +, Substitute, and HRG features,
- # then add the following tags into the Note box on the State:
- #
- # <scaling>
- # 1: a.mat
- # 3: a.mat * 0.01
- # <end scaling>
- # Note that we didn't enter a formula for the second effect (Substitute)
- # because this feature does not include a numerical value.
- # The actual values you set for features in the Features box will only be
- # used if the formula encounters an error when trying to evaluate.
- # For example, if the above state was added by an event (and therefore
- # there is no user to provide a MAT stat), the formula will make no
- # sense, so the value for the feature will revert back to what was
- # entered in the Features box.
- # DURATION SCALING:
- # You can ADD the result of your formula to the State's duration, MULTIPLY
- # the State's duration by the result of your formula, or SET the
- # duration to the result of your formula.
- # For example, if you want to add X turns to the State's normal
- # duration, where X is the level of the user, add the following
- # tag into the Note box on the State:
- #
- # <duration add: a.level>
- # You can use "shortcut" keywords for certain things in your formulas:
- #
- # * a is the user of the skill/item that applied the state.
- #
- # * b is the target that the state was applied to.
- #
- # * ^gp is a shortcut for "$game_party".
- #
- # * v#(number)# is a shortcut for the value of Variable (number).
- # Example: v#21# will pull the value of Variable 21.
- # For values expressed in percentages (such as Element Rates or Health
- # Regeneration), a value of 1 represents 100%. BE CAREFUL. If you
- # want to set the "Thunder" Element Rate to 100% + (user's Magic)%,
- # use the formula 1.00 + (a.mat * 0.01). If you use 1 + (a.mat / 100)
- # instead, it will have no effect until the user has 100 Magic power
- # because Ruby will round the second calculation down to zero!
- ############################################
- # #
- # ICKY CODE! #
- # #
- ############################################
- # Everything from here on represents the inner workings of the script.
- # Please don't alter anything from here on unless you are an
- # advanced scripter yourself (in which case, have at it!)
- module RPG
- class State < RPG::BaseItem
- #--------------------------------------------------------------------------
- # * Add extra Parameters to RPG::State items
- #--------------------------------------------------------------------------
- def init_scaling
- @scaling = false # Whether Utility Scaling is used on this State
- @scaling_info = [] # Array: [Feature # from List, Formula]
- # (Formula for Utility Scaling, as a string)
- @dur_scale_type = 0 # Type of Duration Scaling.
- # 0 = None; 1 = Add; 2 = Multiply; 3 = Set
- @dur_scale_form = "0" # Formula for Duration Scaling, as a string.
- # Set the Scaling values from the item's notetag
- get_scaling(@note)
- end
- #--------------------------------------------------------------------------
- # * Public Instance Variables
- #--------------------------------------------------------------------------
- attr_accessor :scaling
- attr_accessor :scaling_info
- attr_accessor :dur_scale_type
- attr_accessor :dur_scale_form
- #--------------------------------------------------------------------------
- # * Set the Scaling values from the item's notetag
- #--------------------------------------------------------------------------
- def get_scaling(note)
- newnote = @note.downcase
- newnote.gsub!($/, "@LINE@")
- if newnote =~ /<scaling>(.*)<scaling end>/
- splitter = $1.split("@LINE@")
- else
- splitter = []
- end
- # If the splitter isn't empty, set the Scale Type and Scale Formula
- scaling_array = []
- if splitter == []
- @scaling = false
- else
- @scaling = true
- for item in splitter
- if item.include?(":")
- details = item.split(":")
- details[0].slice!(" ")
- details[0].slice!(" ")
- if details[1].start_with?(" ")
- details[1].slice(" ")
- end
- if details[1].start_with?(" ")
- details[1].slice(" ")
- end
- scaling_array.push([details[0].to_i, details[1]])
- end
- end
- end
- @scaling_info = scaling_array
- # Retrieve the duration scaling notetag and split it into segments
- if @note =~ /<duration (.*)>/
- splitter = $1.split(":")
- splitter[0].slice!(" ")
- splitter[0].slice!(" ")
- if splitter[1].start_with?(" ")
- splitter[1].slice(" ")
- end
- if splitter[1].start_with?(" ")
- splitter[1].slice(" ")
- end
- else
- splitter = []
- end
- # If the splitter isn't empty, set the Scale Type and Scale Formula
- unless splitter == []
- if splitter[0].start_with?("add")
- @dur_scale_type = 1
- end
- if splitter[0].start_with?("mult")
- @dur_scale_type = 2
- end
- if splitter[0].start_with?("set", "equal")
- @dur_scale_type = 3
- end
- @dur_scale_form = splitter[1]
- end
- end
- end
- end
- module DataManager
- class << self
- #--------------------------------------------------------------------------
- # * Load Normal Database
- #--------------------------------------------------------------------------
- alias :load_normals_with_scaling :load_normal_database
- def load_normal_database
- load_normals_with_scaling
- for state in $data_states
- state.init_scaling if state != nil
- end
- end
- #--------------------------------------------------------------------------
- # * Load Battle Test Database
- #--------------------------------------------------------------------------
- alias :load_btest_with_scaling :load_battle_test_database
- def load_battle_test_database
- load_btest_with_scaling
- for state in $data_states
- state.init_scaling if state != nil
- end
- end
- end
- end
- class Game_BattlerBase
- #--------------------------------------------------------------------------
- # * Clear State Information
- #--------------------------------------------------------------------------
- alias :clear_states_with_utility :clear_states
- def clear_states
- clear_states_with_utility
- @state_utility = []
- end
- #--------------------------------------------------------------------------
- # * Get Array of All Objects Retaining Features
- # Overwrite Method! Instead of simply returning the States array, this
- # method copies each state on the battler and reconciles it with the
- # appropriate Utility Scaling value, then returns the Copied States.
- #--------------------------------------------------------------------------
- def feature_objects
- copies = states
- for copy in copies
- unless copy.features == []
- for i in 0..(copy.features.size - 1)
- feature = copy.features[i]
- # Find the place in the utility scaling array that holds scaling data
- # for this state. If none (-1), then skip this processing.
- place = find_utility_values(copy.id)
- unless place == -1
- for util_info in (@state_utility[place][1])
- if util_info[0] == i + 1
- this_val = util_info[1]
- unless this_val == "errored"
- feature.value = this_val
- end
- end
- end
- end
- end
- end
- end
- return copies
- end
- #--------------------------------------------------------------------------
- # * Iterate through the @utility_values array to find the position that holds
- # the values for a given state
- #--------------------------------------------------------------------------
- def find_utility_values(state_id)
- for i in 0..(@state_utility.size - 1)
- if @state_utility[i][0] == state_id
- return i
- end
- end
- return -1
- end
- end
- class Game_Battler < Game_BattlerBase
- #--------------------------------------------------------------------------
- # * [Add State] Effect: Normal
- # Overwrite Method! Adds additional parameters to "add_state" call.
- #--------------------------------------------------------------------------
- def item_effect_add_state_normal(user, item, effect)
- chance = effect.value1
- chance *= state_rate(effect.data_id) if opposite?(user)
- chance *= luk_effect_rate(user) if opposite?(user)
- if rand < chance
- add_state(effect.data_id, user, self)
- @result.success = true
- end
- end
- #--------------------------------------------------------------------------
- # * [Add State] Effect: Normal Attack
- # Overwrite Method! Adds additional parameters to "add_state" call.
- #--------------------------------------------------------------------------
- def item_effect_add_state_attack(user, item, effect)
- user.atk_states.each do |state_id|
- chance = effect.value1
- chance *= state_rate(state_id)
- chance *= user.atk_states_rate(state_id)
- chance *= luk_effect_rate(user)
- if rand < chance
- add_state(state_id, user, self)
- @result.success = true
- end
- end
- end
- #--------------------------------------------------------------------------
- # * Add State
- # Overwrite Method! Adds additional parameters to "reset_sta..." call.
- # Also calls the new method "set_state_scaling".
- #--------------------------------------------------------------------------
- def add_state(state_id, user = nil, target = nil)
- if state_addable?(state_id)
- add_new_state(state_id) unless state?(state_id)
- reset_state_counts(state_id, user, target)
- set_state_scaling(state_id, user, target)
- @result.added_states.push(state_id).uniq!
- end
- end
- #--------------------------------------------------------------------------
- # * Evaluate the new Scaling Value for the state and add it, as well as the
- # Scaling Type, to the Scaling Hash
- #--------------------------------------------------------------------------
- def set_state_scaling(state_id, user = nil, target = nil)
- state = $data_states[state_id]
- # If Scaling Utility is not used for this State, then add a dummy entry
- # into the State Utility hash
- if state.scaling == true
- # Otherwise, evaluate the Scaling Formula, then add the result and the
- # Scaling Type into the hash
- scaling_values_array = refine_scaling_value(state, user, target)
- # Find the existing data for this state in the utility_values array and
- # delete it if it exists
- place = find_utility_values(state_id)
- unless place == -1
- @state_utility.delete_at(place)
- end
- @state_utility.push([state_id, scaling_values_array])
- end
- end
- #~
- #--------------------------------------------------------------------------
- # * Reset State Counts (Turns and Steps)
- # Overwrite Method! Performs original state-count set, then new stuff.
- #--------------------------------------------------------------------------
- def reset_state_counts(state_id, user, target)
- # Old Code is here!
- state = $data_states[state_id]
- variance = 1 + [state.max_turns - state.min_turns, 0].max
- @state_turns[state_id] = state.min_turns + rand(variance)
- @state_steps[state_id] = state.steps_to_remove
- # New Code starts here!
- if state.dur_scale_type > 0
- if state.auto_removal_timing > 0
- if @state_turns != nil
- case state.dur_scale_type
- when 1
- @state_turns[state_id] += refine_scaling_dur_value(state, user, target)
- when 2
- @state_turns[state_id] *= refine_scaling_dur_value(state, user, target)
- when 3
- this_val = refine_scaling_dur_value(state, user, target)
- unless this_val == "errored"
- @state_turns[state_id] = this_val
- end
- end
- if @state_turns[state_id] < 0
- @state_turns[state_id] = 0
- end
- end
- end
- if state.remove_by_walking
- if @state_turns != nil
- case state.dur_scale_type
- when 1
- @state_steps[state_id] += refine_scaling_dur_value(state, user, target)
- when 2
- @state_steps[state_id] *= refine_scaling_dur_value(state, user, target)
- when 3
- this_val = refine_scaling_dur_value(state, user, target)
- unless this_val == "errored"
- @state_steps[state_id] = this_val
- end
- end
- if @state_steps[state_id] < 0
- @state_steps[state_id] = 0
- end
- end
- end
- end
- end
- #--------------------------------------------------------------------------
- # * Get the Scaling Value
- #--------------------------------------------------------------------------
- def refine_scaling_value(state, user, target)
- set_of_scalers = []
- for i in 0..(state.scaling_info.size - 1)
- value = state.scaling_info[i][1]
- # Substitute formula shortcuts for values that can be evaluated here
- value.gsub!(/a\./, 'user.')
- value.gsub!(/b\./, 'target.')
- value.gsub!(/self\./, 'target.')
- value.gsub!(/#gp/, '$game_party')
- value.gsub!(/v#/, '$game_variables[')
- value.gsub!(/#/, ']')
- # Evaluate the game designer's custom expression
- expression = ((Kernel.eval(value)) rescue rescue_scaling_form(state, 1))
- set_of_scalers.push([state.scaling_info[i][0], expression])
- end
- return set_of_scalers
- end
- #--------------------------------------------------------------------------
- # * Get the Scaling Duration Value
- #--------------------------------------------------------------------------
- def refine_scaling_dur_value(state, user, target)
- value = state.dur_scale_form
- # Substitute formula shortcuts for values that can be evaluated here
- value.gsub!(/a\./, 'user.')
- value.gsub!(/b\./, 'target.')
- value.gsub!(/self\./, 'target.')
- value.gsub!(/v#/, '$game_variables[')
- value.gsub!(/#/, ']')
- # Evaluate the game designer's custom expression
- expression = (Kernel.eval(value) rescue rescue_scaling_form(state, 2))
- return expression
- end
- #--------------------------------------------------------------------------
- # * Rescue the Scaling (or Scaling Duration) Value. This will be used not
- # only in case of an input error, but also for when States are applied
- # by an event but the formula calls for a "User" that inflicted it.
- #--------------------------------------------------------------------------
- def rescue_scaling_form(state, source)
- # Based on the source, we need to look at either Scaling or Duration Scaling
- case source
- # Utility Scaling - we want to return "errored"
- when 1
- type = 0
- # Duration Scaling - if it's Add or Multiply, we need to return a number
- when 2
- type = state.dur_scale_type
- else
- type = 0
- end
- # Based on the scaling type, we need to return a different modifier in case
- # of error to allow the state to maintain its standard function
- case type
- when 1 # Duration Scaling - Add
- return 0
- when 2 # Duration Scaling - Multiply
- return 1
- else
- return "errored"
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment