Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

[Resolved]Unique Resistance Tables for Each Skill and State

It doesn't make sense that every skill draws upon the same resistance table. As RMXP stands, the skill "Punch" is as likely as the skill "Stab" to cause the state "Bleeding," assuming that both having "Bleeding" checked as a State Change. By default, the table reads [100,80,60,40,20,0], which works fine for "Stab," though "Punch" would work better as [6,5,4,3,2,0], as knuckles are less likely (though still capable) of causing their target to bleed. Is there a way to assign a unique resistance table to each skill for each state?

Currently, I'm using a modified version of Trickster's Elem_State_Rate. I've altered it so that state rates actually change based on the armor equipped, as well as for compatibility with Atoa's Equipment Multi Slots. Currently, it works fine, though it only alters the table per state, as opposed to per skill per state.

The script as-is:
Code:
module Elem_State_Rate

 #--------------

 # * Elemental Rates

 #   - syntax: Element_Id => [A, B, C, D, E, F]

 #--------------

 Elemental = {

 1 => [100, 70, 50, 30, 10, 5],

 2 => [100, 70, 50, 30, 10, 5],

 3 => [100, 70, 50, 30, 10, 5],

 4 => [100, 70, 50, 30, 10, 5],

 5 => [100, 70, 50, 30, 10, 5],

 6 => [100, 70, 50, 30, 10, 5],

 7 => [100, 70, 50, 30, 10, 5],

 8 => [100, 70, 50, 30, 10, 5],

 9 => [100, 70, 50, 30, 10, 5],

 10 => [100, 70, 50, 30, 10, 5],

 11 => [100, 70, 50, 30, 10, 5],

 12 => [100, 70, 50, 30, 10, 5],

 13 => [100, 70, 50, 30, 10, 5],

 14 => [100, 70, 50, 30, 10, 5],

 15 => [100, 70, 50, 30, 10, 5],

 16 => [100, 70, 50, 30, 10, 5],

 17 => [100, 70, 50, 30, 10, 5],

 18 => [100, 70, 50, 30, 10, 5],

 19 => [100, 70, 50, 30, 10, 5],

 20 => [100, 70, 50, 30, 10, 5]

 

 }

 #--------------

 # * Default Elemental Rate

 #   - syntax: [A, B, C, D, E, F]

 #--------------

 Elemental.default = [200,150,100,50,0,-100]

 #--------------

 # * State Rates

 #   - syntax: Element_Id => [A, B, C, D, E, F]

 #--------------

 States = {

 

 60 => [90, 75, 60, 45, 30, 10],

 61 => [65, 50, 35, 20, 10, 2],

 62 => [30, 23, 17, 11, 6, 1],

 63 => [100, 100, 85, 50, 20, 5],

 64 => [100, 100, 50, 30, 15, 3],

 65 => [100, 100, 15, 10, 5, 1],

 68 => [100, 100, 85, 40, 5, 0],

 69 => [100, 100, 50, 20, 3, 0],

 70 => [100, 100, 15, 6, 1, 0],

 73 => [100, 100, 85, 5, 0, 0],

 74 => [100, 100, 50, 3, 0, 0],

 75 => [100, 100, 15, 1, 0, 0],

 

 124 => [30, 23, 17, 11, 6, 3],

 125 => [95, 85, 75, 50, 25, 10],

 126 => [50, 40, 30, 20, 10, 3],

 

 129 => [40, 32, 24, 16, 8, 4],

 130 => [20, 16, 12, 8, 4, 2],

 131 => [10, 8, 6, 4, 2, 1]

 }

 #--------------

 # * Default State Rate

 #   - syntax: [A, B, C, D, E, F]

 #--------------

 States.default = [100,80,60,40,20,0]

end  

 

class Game_Battler

 #--------------

 # * State Change (+) Application

 #     plus_state_set  : State Change (+)

 #--------------

 def states_plus(plus_state_set)

   # Clear effective flag

   effective = false

   # Loop (added state)

   for i in plus_state_set

       # Set effective flag if this state is not full

       effective |= self.state_full?(i) == false

       # If states offer [no resistance]

       if $data_states[i].nonresistance

         # Set state change flag

         @state_changed = true

         # Add a state

         add_state(i)

       # If this state is not full

       elsif self.state_full?(i) == false

         # Get Table

         table = Elem_State_Rate::States[i]

         # Random Chance

         if rand(100) < table[self.state_rate(i)]

           # Set state change flag

           @state_changed = true

           # Add a state

           add_state(i)

       end

     end

   end

   # End Method

   return effective

 end

end

 

class Game_Actor < Game_Battler

 

 def armor_ids

    result = []

    for i in 0...@equip_kind.size

      id = @equip_kind[i]

      if id > 0 and not ($atoa_script['Atoa Two Hands'] and id == 1 and two_swords_style)

        result << eval("@armor#{id}_id = @equip_id[i].nil? ? 0 : @equip_id[i]")

      end

    end

    return result

  end

 

 #--------------

 # * Get State Revision Value

 #     state_id : state ID

 #--------------

 def state_rate(status_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::States[status_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_classes[@class_id].state_ranks[status_id] - 1

   # Run Through each armor

   self.armor_ids.each do |armor_id|

     # Get Armor

     armor = $data_armors[armor_id]

     # Skip if state is nil or doesn't guard

     next if armor == nil or !armor.guard_state_set.include?(status_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return value

 end

 

#--------------

 # * Get Element Revision Value

 #     element_id : element ID

 #--------------

 def element_rate(element_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::Elemental[element_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_classes[@class_id].element_ranks[element_id] - 1

   # Run Through each armor

   self.armor_ids.each do |armor_id|

     # Get Armor

     armor = $data_armors[armor_id]

     # Skip if state is nil or doesn't guard

     next if armor == nil or !armor.guard_element_set.include?(element_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Run Through each state

   @states.each do |state_id|

     # Get State

     state = $data_states[state_id]

     # Skip if state is nil or doesn't guard against element

     next if state == nil or !state.guard_element_set.include?(element_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return table[value]

 end 

end

 

class Game_Enemy < Game_Battler

 

 #--------------

 # * Get State Revision Value

 #     state_id : state ID

 #--------------

 def state_rate(status_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::States[status_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_enemies[@enemy_id].state_ranks[status_id] - 1

   # Run Through each state

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return value

 end

  

 #--------------

 # * Get Element Revision Value

 #     element_id : Element ID

 #--------------

 def element_rate(element_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::Elemental[element_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_enemies[@enemy_id].element_ranks[element_id] - 1

   # Run Through each state

   @states.each do |state_id|

     # Get State

     state = $data_states[state_id]

     # Skip if state is nil or doesn't guard against element

     next if state == nil or !state.guard_element_set.include?(element_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return table[value]

 end

end

It seems that the best way to proceed is to create a hash for each skill, which itself contains a hash of resistance tables for each state. Then, when the skill is used in battle, it will cycle through its resistance tables, compare them to the target's resistance, and then assign states as appropriate.

I think with a little more time I can figure out how to make the hashes by examining Trickster's code, since he uses hashes himself. I'm not sure how I'll call this script from battle, though. In other words, how can I tell Ruby to check this script when a battler uses a skill?

Thanks for your help. I'm a novice at Ruby, but I'm also committed to figuring it out. Any guidance will go a long way.

-tuatha
 
Instead of using a Hash with Hashes in it you should do it with different keys:
Ruby:
Elements = {1 => { # skill 1

 1 => [100, 70, 50, 30, 10, 5] # Skill 1, Element 1

# ...

# not good

 

Elements = {[1, 1] => [100, 70, 50, 30, 10, 5], # skill 1, Element 1

[1, 2] => [100, 70, 50, 30, 10, 5] # skill 2, Element 2

#...

# better

 

Elements = {1 + 1*1000] => [100, 70 #...

# Best way to solve it since it is faster than Elements[1, 1]

# just multiplay the state/element id with (maximum number of skills + 1)

# so every combination of a state and a skill has its unique number


To check, if a Battler uses a skill at the moment you should check out the class Game_BattleAction. An instance of it is stored in Game_Battler#current_action so it should be something like:
Ruby:
class Game_Battler

 def is_casting_skill?

  return (current_action.kind == 1 and current_action.skill_id > 0)

 end

end
 
Well, in Ruby at least we should even use things like...

get_something(value) or set_something(value) or even is_casting_skill?

...but just...

something(value) or something=(value) or casting_skill?

...and so on. The only exception to that kind of rule would be is_a? and stop counting! (That's just because a? wouldn't make sense as any longer word would...)

Just a little correction...

Elements = {[1 + 1*1000] => [100, 70, as, many, values, as, you, like]
 
Progress! Thanks for your advice, it's put me on the right path. I even found a simple way to call the script. The method states_plus now receives both state and skill information, so that both skill and state ids can be used when searching for the proper table. Since this method is already called when a skill is used, I don't need to create a new method to initiate my changes.

I'm using Neo-Bahamut's key suggestion, calculating the keys in the script with the formula "tablenum = skill.id + i*1000." When I have the script print the formula results, it works fine. For instance, using skill 3 and state 60 will get the result 60003.

There are no game-crashing errors, but there is a subtle one. When I have the script print the table, it always uses the default [100,80,60,40,20,0]. Even when I manually set a table number, it prints out the default, instead. For instance, when I use the code:

Code:
         table = Elem_State_Rate::States[60003]

         p table

I still get [100,80,60,40,20,0] instead of [90, 75, 60, 45, 30, 10]. This error didn't occur before my most recent changes.

For reference, the altered sections of the script now look like this:

Code:
module Elem_State_Rate

 #--------------

 # * State Rates

 #   - syntax: Element_Id => [A, B, C, D, E, F]

 #--------------

 States = {

 

 [3 + 60*1000] => [90, 75, 60, 45, 30, 10],

 [4 + 60*1000] => [90, 75, 60, 45, 30, 10],

 [23 + 60*1000] => [90, 75, 60, 45, 30, 10],

 [24 + 60*1000] => [90, 75, 60, 45, 30, 10],

 [33 + 60*1000] => [10, 75, 60, 45, 30, 10],

 [34 + 60*1000] => [90, 75, 60, 45, 30, 10]

 }

 #--------------

 # * Default State Rate

 #   - syntax: [A, B, C, D, E, F]

 #--------------

 States.default = [100,80,60,40,20,0]

end  

 

class Game_Battler

 #--------------

 # * State Change (+) Application

 #     plus_state_set  : State Change (+)

 #--------------

 def states_plus(plus_state_set, skill = 0)

   # Clear effective flag

   effective = false

   # Loop (added state)

   for i in plus_state_set

       # Set effective flag if this state is not full

       effective |= self.state_full?(i) == false

       # If states offer [no resistance]

       if $data_states[i].nonresistance

         # Set state change flag

         @state_changed = true

         # Add a state

         add_state(i)

       # If this state is not full

       elsif self.state_full?(i) == false

         tablenum = skill.id + i*1000

         p tablenum

         # Get Table

         table = Elem_State_Rate::States[tablenum]

         p table

         # Random Chance

         if rand(100) < table[self.state_rate(i)]

           # Set state change flag

           @state_changed = true

           # Add a state

           add_state(i)

       end

     end

   end

   # End Method

   return effective

 end

end
 
You made a mistake with the keys; you define them as Arrays while they should be Integers:
Code:
States = {

 (3 + 60*1000) =>  [90, 75, 60, 45, 30, 10],

 (4 + 60*1000) => [#...

Oh and btw, since Hashes require some more memory than Arrays you possibly should use only one Array for all those States which are the same:
Code:
a = [90, 75, 60, 45, 30, 10]

States = {

 (3 + 60*1000) => a,

 (4 + 60*1000) => a,

 (23 + 60*1000) => a, #...
 
That does the trick! Thanks, Neo-Bahamut!

For anyone interested in using this script, here it is:

Code:
module Elem_State_Rate

 #--------------

 # * Elemental Rates

 #   - syntax: Element_Id => [A, B, C, D, E, F]

 #--------------

 Elemental = {

 1 => [100, 70, 50, 30, 10, 5],

 2 => [100, 70, 50, 30, 10, 5]

 

 }

 #--------------

 # * Default Elemental Rate

 #   - syntax: [A, B, C, D, E, F]

 #--------------

 Elemental.default = [200,150,100,50,0,-100]

 #--------------

 # * State Rates

 #   - syntax: Element_Id => [A, B, C, D, E, F]

 #--------------

 States = {

 

 (3+ 60*1000) => [30, 75, 60, 45, 30, 10]

 }

 #--------------

 # * Default State Rate

 #   - syntax: [A, B, C, D, E, F]

 #--------------

 States.default = [100,80,60,40,20,0]

end  

 

class Game_Battler

 #--------------

 # * State Change (+) Application

 #     plus_state_set  : State Change (+)

 #--------------

 def states_plus(plus_state_set, skill = 0)

   # Clear effective flag

   effective = false

   # Loop (added state)

   for i in plus_state_set

       # Set effective flag if this state is not full

       effective |= self.state_full?(i) == false

       # If states offer [no resistance]

       if $data_states[i].nonresistance

         # Set state change flag

         @state_changed = true

         # Add a state

         add_state(i)

       # If this state is not full

       elsif self.state_full?(i) == false

         tablenum = skill.id + i*1000

         # Get Table

         table = Elem_State_Rate::States[tablenum]

         # Random Chance

         if rand(100) < table[self.state_rate(i)]

           # Set state change flag

           @state_changed = true

           # Add a state

           add_state(i)

       end

     end

   end

   # End Method

   return effective

 end

end

 

class Game_Actor < Game_Battler

 #-------------

 # * Name:      Armor Ids

 #   Info:      Gets ALL Armor IDs

 #   Author:    Trickster

 #   Call Info: No Arguments

 #   Returns:   An Array of Armor Ids

 #   Comments:  Detects @armor(n)_id

 #-------------

 

 def armor_ids

    result = []

    for i in 0...@equip_kind.size

      id = @equip_kind[i]

      if id > 0 and not ($atoa_script['Atoa Two Hands'] and id == 1 and two_swords_style)

        result << eval("@armor#{id}_id = @equip_id[i].nil? ? 0 : @equip_id[i]")

      end

    end

    return result

  end

 

 #--------------

 # * Get State Revision Value

 #     state_id : state ID

 #--------------

 def state_rate(status_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::States[status_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_classes[@class_id].state_ranks[status_id] - 1

   # Run Through each armor

   self.armor_ids.each do |armor_id|

     # Get Armor

     armor = $data_armors[armor_id]

     # Skip if state is nil or doesn't guard

     next if armor == nil or !armor.guard_state_set.include?(status_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return value

 end

 

#--------------

 # * Get Element Revision Value

 #     element_id : element ID

 #--------------

 def element_rate(element_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::Elemental[element_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_classes[@class_id].element_ranks[element_id] - 1

   # Run Through each armor

   self.armor_ids.each do |armor_id|

     # Get Armor

     armor = $data_armors[armor_id]

     # Skip if state is nil or doesn't guard

     next if armor == nil or !armor.guard_element_set.include?(element_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Run Through each state

   @states.each do |state_id|

     # Get State

     state = $data_states[state_id]

     # Skip if state is nil or doesn't guard against element

     next if state == nil or !state.guard_element_set.include?(element_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return table[value]

 end 

end

 

class Game_Enemy < Game_Battler

 

 #--------------

 # * Get State Revision Value

 #     state_id : state ID

 #--------------

 def state_rate(status_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::States[status_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_enemies[@enemy_id].state_ranks[status_id] - 1

   # Run Through each state

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return value

 end

  

 #--------------

 # * Get Element Revision Value

 #     element_id : Element ID

 #--------------

 def element_rate(element_id)

   # Get values corresponding to element effectiveness

   table = Elem_State_Rate::Elemental[element_id]

   # Get Value Minus 1 (0 in front was removed)

   value = $data_enemies[@enemy_id].element_ranks[element_id] - 1

   # Run Through each state

   @states.each do |state_id|

     # Get State

     state = $data_states[state_id]

     # Skip if state is nil or doesn't guard against element

     next if state == nil or !state.guard_element_set.include?(element_id)

     # Add 1 (Bump up)

     value += 1

   end

   # Restrict to[0,5]

   value = [[value, 0].max, 5].min

   # End Method

   return table[value]

 end

end

PS. I like the idea of creating variables with common arrays. Not only will it save memory, but also a lot of tedious cutting and pasting. Thanks!
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top