Wavescripts

Wave's Utility Scaling

Jul 7th, 2015
429
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 20.95 KB | None | 0 0
  1. ############################################
  2. #                                          #
  3. #        UTILITY SCALING SCRIPT            #
  4. #                                          #
  5. #       v1.0 for RPG Maker VX Ace          #
  6. #                                          #
  7. # Created by Jason "Wavelength" Commander  #
  8. #                                          #
  9. ############################################
  10.  
  11. # "I don't think limits."
  12. #                                     ~ Usain Bolt
  13.  
  14.  
  15. ############################################
  16. #                                          #
  17. #           ABOUT THIS SCRIPT              #
  18. #                                          #
  19. ############################################
  20.  
  21. # This script allows you to scale the Utility and Duration
  22. #      of Status Effects based on the stats of the battler
  23. #      that inflicted the status.
  24.  
  25. # You can also set up these scaling effects based on the stats
  26. #      of the battler that received the status, on a variable,
  27. #      or, in theory, on almost anything else you'd like to.
  28.  
  29. # As examples, you could create:
  30. #
  31. #      * A poison state that inflicts higher degeneration rates
  32. #        as the user's Magic stat grows stronger
  33. #
  34. #      * A confusion state which will last for different lengths
  35. #        of time depending on whether a weak monster or a powerful
  36. #        boss was the one that used it on you
  37. #
  38. #      * A vulnerability state that causes an enemy to take 1%
  39. #        more Fire damage for each point of Luck you have
  40. #
  41. #      * A fury state that gives an ally an extra attack for
  42. #        every five "Rage Gems" the player owns
  43. #
  44. #      * A regen state that will heal an ally each turn based on that
  45. #        ally’s Strength stat instead of their Max HP
  46.  
  47. # This script will likely *not* be compatible with other scripts that
  48. #      alias or overwrite methods dealing with adding states to
  49. #      battlers.  I will look into using more alias methods in order
  50. #      to improve compatibility in future versions of this script.
  51.  
  52.  
  53. ############################################
  54. #                                          #
  55. #              TERMS OF USE                #
  56. #                                          #
  57. ############################################
  58.  
  59. #  Free to use for non-commercial projects - just credit me
  60.  
  61. #  A license is required to use this script in commercial or
  62. #       semi-commercial projects.  Please visit my website
  63. #       wavescripts.wordpress.com for more info about obtaining
  64. #       a license for my scripts.
  65.  
  66. #  You may freely share or modify this script, but you cannot
  67. #       sell it (even if modified) without my written permission
  68.  
  69. #  Please preserve the header (with version #) and terms of use;
  70. #       besides that, feel free to remove any commenting you please
  71.  
  72.  
  73. ############################################
  74. #                                          #
  75. #            ADDITIONAL THANKS             #
  76. #                                          #
  77. ############################################
  78.  
  79. # Thanks to Tsukihime and Galv for their help learning Notetags.
  80. #      This was the first time I've used them as a scripter and
  81. #      their guides and help were invaluable.
  82.  
  83. # Thanks to Riot Games for popularizing the idea of Utility
  84. #      Scaling.  I loved this concept the moment I saw it in
  85. #      League of Legends and I hope that people can use my
  86. #      script to implement this kind of thoughtful design.
  87.  
  88.  
  89. ############################################
  90. #                                          #
  91. #         HOW TO USE THIS SCRIPT           #
  92. #                                          #
  93. ############################################
  94.  
  95. # This script should be placed in the "Materials" section
  96. #      of the script editor.  If you are using other shop
  97. #      scripts, it's generally better to place this script
  98. #      below those other scripts.
  99.  
  100. # To add scaling to States in your database, tag them in the
  101. #     "Note" field using the appropriate format.
  102.  
  103. # You can add UTILITY SCALING to any State that contains Features
  104. #     which include a numerical value.  Use the following format:
  105. #
  106. #             <scaling>
  107. #             1: (formula)
  108. #             2: (formula)
  109. #             ...
  110. #             (feature #): (formula)
  111. #             <scaling end>
  112.  
  113. # You can add DURATION SCALING to any State, even those without
  114. #       Features.  Use the following format:
  115. #
  116. #             <duration (add/set/mult): (formula)>
  117.  
  118. ############################################
  119. #                                          #
  120. #      EXAMPLES AND NOTES ON USAGE         #
  121. #                                          #
  122. ############################################
  123.  
  124. # UTILITY SCALING:
  125.  
  126. # For example, let's say you want to create a state that gives
  127. #       X additional attacks to an ally, gives them the Substitute
  128. #       property, and heals them by X percent each turn, where X is
  129. #       the Magic Attack of the user who applies the state.  Set up
  130. #       a State with the Atk Times +, Substitute, and HRG features,
  131. #       then add the following tags into the Note box on the State:
  132. #
  133. #             <scaling>
  134. #             1: a.mat
  135. #             3: a.mat * 0.01
  136. #             <end scaling>
  137.  
  138. # Note that we didn't enter a formula for the second effect (Substitute)
  139. #       because this feature does not include a numerical value.
  140.  
  141. # The actual values you set for features in the Features box will only be
  142. #       used if the formula encounters an error when trying to evaluate.
  143. #       For example, if the above state was added by an event (and therefore
  144. #       there is no user to provide a MAT stat), the formula will make no
  145. #       sense, so the value for the feature will revert back to what was
  146. #       entered in the Features box.
  147.  
  148. # DURATION SCALING:
  149.  
  150. # You can ADD the result of your formula to the State's duration, MULTIPLY
  151. #       the State's duration by the result of your formula, or SET the
  152. #       duration to the result of your formula.
  153.  
  154. # For example, if you want to add X turns to the State's normal
  155. #       duration, where X is the level of the user, add the following
  156. #       tag into the Note box on the State:
  157. #
  158. #             <duration add: a.level>
  159.  
  160. # You can use "shortcut" keywords for certain things in your formulas:
  161. #
  162. #     * a is the user of the skill/item that applied the state.
  163. #
  164. #     * b is the target that the state was applied to.
  165. #
  166. #     * ^gp is a shortcut for "$game_party".
  167. #
  168. #     * v#(number)# is a shortcut for the value of Variable (number).
  169. #            Example: v#21# will pull the value of Variable 21.
  170.  
  171. # For values expressed in percentages (such as Element Rates or Health
  172. #       Regeneration), a value of 1 represents 100%.  BE CAREFUL.  If you
  173. #       want to set the "Thunder" Element Rate to 100% + (user's Magic)%,
  174. #       use the formula 1.00 + (a.mat * 0.01).  If you use 1 + (a.mat / 100)
  175. #       instead, it will have no effect until the user has 100 Magic power
  176. #       because Ruby will round the second calculation down to zero!
  177.  
  178.  
  179.  
  180. ############################################
  181. #                                          #
  182. #               ICKY CODE!                 #
  183. #                                          #
  184. ############################################
  185.  
  186. # Everything from here on represents the inner workings of the script.
  187. #       Please don't alter anything from here on unless you are an
  188. #       advanced scripter yourself (in which case, have at it!)  
  189.  
  190. module RPG
  191.  
  192.   class State < RPG::BaseItem
  193.  
  194.     #--------------------------------------------------------------------------
  195.     # * Add extra Parameters to RPG::State items
  196.     #--------------------------------------------------------------------------
  197.     def init_scaling
  198.      
  199.       @scaling = false          # Whether Utility Scaling is used on this State
  200.       @scaling_info = []        # Array: [Feature # from List, Formula]
  201.                                 #      (Formula for Utility Scaling, as a string)
  202.      
  203.       @dur_scale_type = 0       # Type of Duration Scaling.
  204.                                 #      0 = None; 1 = Add; 2 = Multiply; 3 = Set
  205.       @dur_scale_form = "0"     # Formula for Duration Scaling, as a string.
  206.      
  207.      
  208.       # Set the Scaling values from the item's notetag
  209.       get_scaling(@note)
  210.      
  211.     end
  212.    
  213.     #--------------------------------------------------------------------------
  214.     # * Public Instance Variables
  215.     #--------------------------------------------------------------------------
  216.     attr_accessor :scaling
  217.     attr_accessor :scaling_info
  218.     attr_accessor :dur_scale_type
  219.     attr_accessor :dur_scale_form
  220.    
  221.     #--------------------------------------------------------------------------
  222.     # * Set the Scaling values from the item's notetag
  223.     #--------------------------------------------------------------------------
  224.     def get_scaling(note)
  225.      
  226.       newnote = @note.downcase
  227.       newnote.gsub!($/, "@LINE@")
  228.       if newnote =~ /<scaling>(.*)<scaling end>/
  229.         splitter = $1.split("@LINE@")
  230.       else
  231.         splitter = []
  232.       end
  233.      
  234.       # If the splitter isn't empty, set the Scale Type and Scale Formula
  235.       scaling_array = []
  236.       if splitter == []
  237.         @scaling = false
  238.       else
  239.         @scaling = true
  240.         for item in splitter
  241.           if item.include?(":")
  242.             details = item.split(":")
  243.             details[0].slice!(" ")
  244.             details[0].slice!(" ")
  245.             if details[1].start_with?(" ")
  246.               details[1].slice(" ")
  247.             end
  248.             if details[1].start_with?(" ")
  249.               details[1].slice(" ")
  250.             end
  251.             scaling_array.push([details[0].to_i, details[1]])
  252.           end
  253.         end
  254.       end
  255.       @scaling_info = scaling_array
  256.      
  257.       # Retrieve the duration scaling notetag and split it into segments
  258.       if @note =~ /<duration (.*)>/
  259.         splitter = $1.split(":")
  260.         splitter[0].slice!(" ")
  261.         splitter[0].slice!(" ")
  262.         if splitter[1].start_with?(" ")
  263.           splitter[1].slice(" ")
  264.         end
  265.         if splitter[1].start_with?(" ")
  266.           splitter[1].slice(" ")
  267.         end
  268.       else
  269.         splitter = []
  270.       end
  271.      
  272.       # If the splitter isn't empty, set the Scale Type and Scale Formula
  273.       unless splitter == []
  274.         if splitter[0].start_with?("add")
  275.           @dur_scale_type = 1
  276.         end
  277.         if splitter[0].start_with?("mult")
  278.           @dur_scale_type = 2
  279.         end
  280.         if splitter[0].start_with?("set", "equal")
  281.           @dur_scale_type = 3
  282.         end
  283.         @dur_scale_form = splitter[1]
  284.       end  
  285.      
  286.     end
  287.    
  288.   end
  289.  
  290. end
  291.  
  292.  
  293. module DataManager
  294.  
  295.   class << self
  296.  
  297.     #--------------------------------------------------------------------------
  298.     # * Load Normal Database
  299.     #--------------------------------------------------------------------------
  300.     alias :load_normals_with_scaling :load_normal_database
  301.     def load_normal_database
  302.       load_normals_with_scaling
  303.       for state in $data_states
  304.         state.init_scaling if state != nil
  305.       end
  306.     end
  307.     #--------------------------------------------------------------------------
  308.     # * Load Battle Test Database
  309.     #--------------------------------------------------------------------------
  310.     alias :load_btest_with_scaling :load_battle_test_database
  311.     def load_battle_test_database
  312.       load_btest_with_scaling
  313.       for state in $data_states
  314.         state.init_scaling if state != nil
  315.       end
  316.     end
  317.  
  318.   end
  319.  
  320. end
  321.  
  322.  
  323. class Game_BattlerBase
  324.  
  325.   #--------------------------------------------------------------------------
  326.   # * Clear State Information
  327.   #--------------------------------------------------------------------------
  328.   alias :clear_states_with_utility :clear_states
  329.   def clear_states
  330.     clear_states_with_utility
  331.     @state_utility = []
  332.   end
  333.  
  334.   #--------------------------------------------------------------------------
  335.   # * Get Array of All Objects Retaining Features
  336.   #       Overwrite Method!  Instead of simply returning the States array, this
  337.   #       method copies each state on the battler and reconciles it with the
  338.   #       appropriate Utility Scaling value, then returns the Copied States.
  339.   #--------------------------------------------------------------------------
  340.   def feature_objects
  341.     copies = states
  342.     for copy in copies
  343.       unless copy.features == []
  344.         for i in 0..(copy.features.size - 1)
  345.           feature = copy.features[i]
  346.           # Find the place in the utility scaling array that holds scaling data
  347.           #   for this state.  If none (-1), then skip this processing.
  348.           place = find_utility_values(copy.id)
  349.           unless place == -1
  350.             for util_info in (@state_utility[place][1])
  351.               if util_info[0] == i + 1
  352.                 this_val = util_info[1]
  353.                 unless this_val == "errored"
  354.                   feature.value = this_val
  355.                 end
  356.               end
  357.             end
  358.           end
  359.         end
  360.       end
  361.     end
  362.     return copies
  363.   end
  364.  
  365.   #--------------------------------------------------------------------------
  366.   # * Iterate through the @utility_values array to find the position that holds
  367.   #        the values for a given state
  368.   #--------------------------------------------------------------------------  
  369.   def find_utility_values(state_id)
  370.     for i in 0..(@state_utility.size - 1)
  371.       if @state_utility[i][0] == state_id
  372.         return i
  373.       end
  374.     end
  375.     return -1
  376.   end
  377.  
  378. end
  379.  
  380. class Game_Battler < Game_BattlerBase
  381.  
  382.   #--------------------------------------------------------------------------
  383.   # * [Add State] Effect: Normal
  384.   #      Overwrite Method!  Adds additional parameters to "add_state" call.
  385.   #--------------------------------------------------------------------------
  386.   def item_effect_add_state_normal(user, item, effect)
  387.     chance = effect.value1
  388.     chance *= state_rate(effect.data_id) if opposite?(user)
  389.     chance *= luk_effect_rate(user)      if opposite?(user)
  390.     if rand < chance
  391.       add_state(effect.data_id, user, self)
  392.       @result.success = true
  393.     end
  394.   end
  395.  
  396.   #--------------------------------------------------------------------------
  397.   # * [Add State] Effect: Normal Attack
  398.   #      Overwrite Method!  Adds additional parameters to "add_state" call.
  399.   #--------------------------------------------------------------------------
  400.   def item_effect_add_state_attack(user, item, effect)
  401.     user.atk_states.each do |state_id|
  402.       chance = effect.value1
  403.       chance *= state_rate(state_id)
  404.       chance *= user.atk_states_rate(state_id)
  405.       chance *= luk_effect_rate(user)
  406.       if rand < chance
  407.         add_state(state_id, user, self)
  408.         @result.success = true
  409.       end
  410.     end
  411.   end
  412.  
  413.   #--------------------------------------------------------------------------
  414.   # * Add State
  415.   #      Overwrite Method!  Adds additional parameters to "reset_sta..." call.
  416.   #      Also calls the new method "set_state_scaling".
  417.   #--------------------------------------------------------------------------
  418.   def add_state(state_id, user = nil, target = nil)
  419.     if state_addable?(state_id)
  420.       add_new_state(state_id) unless state?(state_id)
  421.       reset_state_counts(state_id, user, target)
  422.       set_state_scaling(state_id, user, target)
  423.       @result.added_states.push(state_id).uniq!
  424.     end
  425.   end
  426.  
  427.   #--------------------------------------------------------------------------
  428.   # * Evaluate the new Scaling Value for the state and add it, as well as the
  429.   #       Scaling Type, to the Scaling Hash
  430.   #--------------------------------------------------------------------------
  431.   def set_state_scaling(state_id, user = nil, target = nil)
  432.     state = $data_states[state_id]
  433.     # If Scaling Utility is not used for this State, then add a dummy entry
  434.     #   into the State Utility hash
  435.     if state.scaling == true
  436.     # Otherwise, evaluate the Scaling Formula, then add the result and the
  437.     #   Scaling Type into the hash
  438.       scaling_values_array = refine_scaling_value(state, user, target)
  439.       # Find the existing data for this state in the utility_values array and
  440.       #   delete it if it exists
  441.       place = find_utility_values(state_id)
  442.       unless place == -1
  443.         @state_utility.delete_at(place)
  444.       end
  445.       @state_utility.push([state_id, scaling_values_array])
  446.     end
  447.   end
  448. #~  
  449.   #--------------------------------------------------------------------------
  450.   # * Reset State Counts (Turns and Steps)
  451.   #      Overwrite Method!  Performs original state-count set, then new stuff.
  452.   #--------------------------------------------------------------------------
  453.   def reset_state_counts(state_id, user, target)
  454.     # Old Code is here!
  455.     state = $data_states[state_id]
  456.     variance = 1 + [state.max_turns - state.min_turns, 0].max
  457.     @state_turns[state_id] = state.min_turns + rand(variance)
  458.     @state_steps[state_id] = state.steps_to_remove
  459.     # New Code starts here!
  460.     if state.dur_scale_type > 0
  461.       if state.auto_removal_timing > 0
  462.         if @state_turns != nil
  463.           case state.dur_scale_type
  464.           when 1
  465.             @state_turns[state_id] += refine_scaling_dur_value(state, user, target)
  466.           when 2
  467.             @state_turns[state_id] *= refine_scaling_dur_value(state, user, target)
  468.           when 3
  469.             this_val = refine_scaling_dur_value(state, user, target)
  470.             unless this_val == "errored"
  471.               @state_turns[state_id] = this_val
  472.             end
  473.           end
  474.           if @state_turns[state_id] < 0
  475.             @state_turns[state_id] = 0
  476.           end
  477.         end
  478.       end
  479.       if state.remove_by_walking
  480.         if @state_turns != nil
  481.           case state.dur_scale_type
  482.           when 1
  483.             @state_steps[state_id] += refine_scaling_dur_value(state, user, target)
  484.           when 2
  485.             @state_steps[state_id] *= refine_scaling_dur_value(state, user, target)
  486.           when 3
  487.             this_val = refine_scaling_dur_value(state, user, target)
  488.             unless this_val == "errored"
  489.               @state_steps[state_id] = this_val
  490.             end
  491.           end
  492.           if @state_steps[state_id] < 0
  493.             @state_steps[state_id] = 0
  494.           end
  495.         end
  496.       end
  497.     end
  498.   end
  499.  
  500.   #--------------------------------------------------------------------------
  501.   # * Get the Scaling Value
  502.   #--------------------------------------------------------------------------
  503.   def refine_scaling_value(state, user, target)
  504.     set_of_scalers = []
  505.     for i in 0..(state.scaling_info.size - 1)
  506.       value = state.scaling_info[i][1]
  507.       # Substitute formula shortcuts for values that can be evaluated here
  508.       value.gsub!(/a\./, 'user.')
  509.       value.gsub!(/b\./, 'target.')
  510.       value.gsub!(/self\./, 'target.')
  511.       value.gsub!(/#gp/, '$game_party')
  512.       value.gsub!(/v#/, '$game_variables[')
  513.       value.gsub!(/#/, ']')
  514.       # Evaluate the game designer's custom expression
  515.       expression = ((Kernel.eval(value)) rescue rescue_scaling_form(state, 1))
  516.       set_of_scalers.push([state.scaling_info[i][0], expression])
  517.     end
  518.     return set_of_scalers
  519.   end
  520.  
  521.   #--------------------------------------------------------------------------
  522.   # * Get the Scaling Duration Value
  523.   #--------------------------------------------------------------------------
  524.   def refine_scaling_dur_value(state, user, target)
  525.     value = state.dur_scale_form
  526.     # Substitute formula shortcuts for values that can be evaluated here
  527.     value.gsub!(/a\./, 'user.')
  528.     value.gsub!(/b\./, 'target.')
  529.     value.gsub!(/self\./, 'target.')
  530.     value.gsub!(/v#/, '$game_variables[')
  531.     value.gsub!(/#/, ']')
  532.     # Evaluate the game designer's custom expression
  533.     expression = (Kernel.eval(value) rescue rescue_scaling_form(state, 2))
  534.     return expression
  535.   end
  536.  
  537.   #--------------------------------------------------------------------------
  538.   # * Rescue the Scaling (or Scaling Duration) Value.  This will be used not
  539.   #       only in case of an input error, but also for when States are applied
  540.   #       by an event but the formula calls for a "User" that inflicted it.
  541.   #--------------------------------------------------------------------------
  542.   def rescue_scaling_form(state, source)
  543.     # Based on the source, we need to look at either Scaling or Duration Scaling
  544.     case source
  545.     # Utility Scaling - we want to return "errored"
  546.     when 1
  547.       type = 0
  548.     # Duration Scaling - if it's Add or Multiply, we need to return a number
  549.     when 2
  550.       type = state.dur_scale_type
  551.     else
  552.       type = 0
  553.     end
  554.     # Based on the scaling type, we need to return a different modifier in case
  555.     #   of error to allow the state to maintain its standard function
  556.     case type
  557.     when 1 # Duration Scaling - Add
  558.       return 0
  559.     when 2 # Duration Scaling - Multiply
  560.       return 1
  561.     else
  562.       return "errored"
  563.     end
  564.   end
  565.  
  566. end
Advertisement
Add Comment
Please, Sign In to add comment