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.

% Damage Calculator for Skills [resolved]

Status
Not open for further replies.
What i want is to have different kind of skills in my game, like in Phantasy Star 4.
1- Magic: just like the default

2- Skills: These ones can be used a certain # of times depending on the level and the most important thing is that the damage they do is a % of the damage done by normal attacks

lets say in the database I add "%120" to the name, this information is not shown in the game but that skill does 120% of the damage dealt with normal attacks. or i add "%100" to the name and make it deal damage in all enemies meaning it would do the same damage as in normal attacks but damaging everyone. The damage would depend on the equipment so if with a beginner sword 100% is 200 damage with an advanced sword 100% damage would be 1000

these skills dont use MP they have a number of times of usage until you go to an inn and every 4 levels another time is added to the skill. But just having the damage calculator is fine
 
[rgss]class Game_Battler
 
  def skill_hit?(user, skill)
    if ( [3,4].include?(skill.scope) and self.hp == 0) or
      ( [5,6].include?(skill.scope) and self.hp >= 1)
      return false
    end
    # else
    return true
  end
 
  def attack_hit?(attacker)
    hit_result = (rand(100) < attacker.hit)
    return hit_result
  end
 
  def damage_correct(attacker, damage)
    # critical
    if rand(100) < 4 * attacker.dex / self.agi
      damage *= 2
      self.critical = true
    end
    # Guard
    damage /= 2 if self.guarding?
    return damage
  end
 
 
  def attack_self_damage(attacker)
    self.critical = false
    # basic damage
    atk = [attacker.atk - self.pdef / 2, 0].max
    damage = atk * (20 + attacker.str) / 20
    # Element correction
    damage *= elements_correct(attacker.element_set)
    damage /= 100
    if (damage > 0)
      damage = damage_correct(attacker, damage)
    end
    # Dispersion
    if damage.abs > 0
      amp = [damage.abs * 15 / 100, 1].max
      damage += rand(amp+1) + rand(amp+1) - amp
    end
    return damage
  end
 
  def skill_effect(user, skill)
    data = skill.name.split(/%/)
    skill_rate = data[1].nil? ? 100 : data[1].to_i
    hit_result = attack_hit?(user)
    # If hit occurs
    if hit_result == true
      damage = attack_self_damage(user)
      self.damage = damage * skill_rate / 100
      # State Removed by Shock
      remove_states_shock
      # Substract damage from HP
      self.hp -= self.damage
      # State change
      @state_changed = false
      states_plus(user.plus_state_set)
      states_minus(user.minus_state_set)
    # When missing
    else
      # Set damage to "Miss"
      self.damage = "Miss"
      # Clear critical flag
      self.critical = false
    end
   
  end
 
end
 
 
class Game_Actor < Game_Battler
  attr_accessor  :left_skills
 
  alias actor_init initialize
  def initialize(actor_id)
    actor_init(actor_id)
    @left_skills = Hash.new
    n = max_skill_uses
    @skills.each { |id| @left_skills[id] = n }
  end
 
  def max_skill_uses
    return [@level/4, 1].max
  end
 
  #--------------------------------------------------------------------------
  # * Recover All
  #--------------------------------------------------------------------------
  def recover_all
    @hp = maxhp
    @sp = maxsp
    for i in @states.clone
      remove_state(i)
    end
    @skills.each { |id| @left_skills[id] = max_skill_uses }
  end
 
  def skill_can_use?(skill_id)
    if @left_skills[skill_id] <= 0
      return false
    end
    # Unusable if incapacitated
    if dead?
      return false
    end
    # If silent, only physical skills can be used
    if $data_skills[skill_id].atk_f == 0 and self.restriction == 1
      return false
    end
    # Get usable time
    occasion = $data_skills[skill_id].occasion
    # If in battle
    if $game_temp.in_battle
      # Usable with [Normal] and [Only Battle]
      return (occasion == 0 or occasion == 1)
    # If not in battle
    else
      # Usable with [Normal] and [Only Menu]
      return (occasion == 0 or occasion == 2)
    end
  end
 
end
 
class Window_Skill < Window_Selectable
  #--------------------------------------------------------------------------
  # * Draw Item
  #     index : item number
  #--------------------------------------------------------------------------
  def draw_item(index)
    skill = @data[index]
    if @actor.skill_can_use?(skill.id)
      self.contents.font.color = normal_color
    else
      self.contents.font.color = disabled_color
    end
    x = 4 + index % 2 * (288 + 32)
    y = index / 2 * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(skill.icon_name)
    opacity = self.contents.font.color == normal_color ? 255 : 128
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    # remove the % from the name:
    nameParts = skill.name.split(/%/)
    self.contents.draw_text(x + 28, y, 204, 32, nameParts[0], 0)
    #self.contents.draw_text(x + 232, y, 48, 32, skill.sp_cost.to_s, 2)
    max = @actor.max_skill_uses
    left = @actor.left_skills[skill.id]
    self.contents.draw_text(x + 232, y, 48, 32, "#{left}/#{max}", 2)
  end
 
end
 
 
class Scene_Battle
  #--------------------------------------------------------------------------
  # * Make Skill Action Results
  #--------------------------------------------------------------------------
  def make_skill_action_result
    # Get skill
    @skill = $data_skills[@active_battler.current_action.skill_id]
    # If not a forcing action
    unless @active_battler.current_action.forcing
      # If unable to use due to SP running out
      unless @active_battler.skill_can_use?(@skill.id)
        # Clear battler being forced into action
        $game_temp.forcing_battler = nil
        # Shift to step 1
        @phase4_step = 1
        return
      end
    end
    # ------------------------------------------- #
    # Use up SP -- disabled
    #@active_battler.sp -= @skill.sp_cost
    # Use up 'skill times' instead
    if @active_battler.is_a?(Game_Actor)
      @active_battler.left_skills[@skill.id] -= 1
    end
    # ------------------------------------------- #
    # Refresh status window
    @status_window.refresh
    # Show skill name on help window
    @help_window.set_text(@skill.name, 1)
    # Set animation ID
    @animation1_id = @skill.animation1_id
    @animation2_id = @skill.animation2_id
    # Set command event ID
    @common_event_id = @skill.common_event_id
    # Set target battlers
    set_target_battlers(@skill.scope)
    # Apply skill effect
    for target in @target_battlers
      target.skill_effect(@active_battler, @skill)
    end
  end
 
  def make_skill_action_result
    # Get skill
    @skill = $data_skills[@active_battler.current_action.skill_id]
    # If not a forcing action
    unless @active_battler.current_action.forcing
      # If unable to use due to SP running out
      unless @active_battler.skill_can_use?(@skill.id)
        # Clear battler being forced into action
        $game_temp.forcing_battler = nil
        # Shift to step 1
        @phase4_step = 1
        return
      end
    end
    # Use up SP
    @active_battler.sp -= @skill.sp_cost
    # Refresh status window
    @status_window.refresh
    # -------------------------------------- #
    name_parts = @skill.name.split(/%/)
    # Show skill name on help window
    @help_window.set_text(name_parts[0], 1)
    # -------------------------------------- #
    # Set animation ID
    @animation1_id = @skill.animation1_id
    @animation2_id = @skill.animation2_id
    # Set command event ID
    @common_event_id = @skill.common_event_id
    # Set target battlers
    set_target_battlers(@skill.scope)
    # Apply skill effect
    for target in @target_battlers
      target.skill_effect(@active_battler, @skill)
    end
  end
 
end
[/rgss]

You didn't give much detail, hopefully this is what you meant.

- if you forget to add %x to the skill name, it does 100% damage.
- all skills have the same # of uses: level/4.
- each skill has a separate number. a level 4 actor with x skills can use each skill once, rather than any skill 4x times.
- skill menu shows the number of skills you have left (1/3 etc).
- Recover All will heal the # of skill uses too.
Weapons already effect the damage dealt by skills, so I didn't have to change that.
 
The thing is that when there is a change of weapon the skill ends up doing less damage so what i want is that those skills marked in a way are directly calculated by normal attacks if a normal attack does 500dmg the skill with 100% does 500dmg and with 120% does 600dmg because theyre supposed to be skills and not magic.

so basically what im saying is that there are 2 kind of skills

Magic: Done with MP and infinite if there is mp to cast them
Skills: Damage based on the normal attacks and limited by #

the 2 of them are available so i want to mark the skills by atribute "skill"

if marked with attribute "skill": it is limited and 1 is added every 4 lvls

If not its a normal Spell and it uses mp like regular spells


now about the number of uses of the "Skills" i want the count to start on the level learnt so if the skill is leant in level 10 it has only 1 use until lvl 14

And thank you very much for helping me :grin:
 
I don't get what you mean with the weapons.
In rmxp, Attack does damage based on ATK. Equipping a weapon changes actor's states, including ATK. So weapons effect both Attack damage and Skill damage, (or non- if your weapon doesn't raise ATK). You shouldn't have a problem, as long as your non-magical skills are physical (100% Atk-f) .
[rgss] 
class RPG::Skill
 
  Non_Magic_Skill = 17        # element ID (of the 'skill' element)
 
  def non_magic_skill?
    return @element_set.include?(Non_Magic_Skill)
  end
 
  def fixed_name
    nameParts = @name.split(/%/)
    return nameParts[0]
  end
 
  def get_rate_from_name
    data = @name.split(/%/)
    skill_rate = data[1].nil? ? 100 : data[1].to_i
    return skill_rate
  end
 
end
 
 
class Game_Battler
 
  def skill_hit?(user, skill)
    if ( [3,4].include?(skill.scope) and self.hp == 0) or
      ( [5,6].include?(skill.scope) and self.hp >= 1)
      return false
    end
    # else
    return true
  end
 
  def damage_correct(attacker, damage)
    # critical
    if rand(100) < 4 * attacker.dex / self.agi
      damage *= 2
      self.critical = true
    end
    # Guard
    damage /= 2 if self.guarding?
    return damage
  end
 
 
  def attack_self_damage(attacker)
    self.critical = false
    # basic damage
    atk = [attacker.atk - self.pdef / 2, 0].max
    damage = atk * (20 + attacker.str) / 20
    # Element correction
    damage *= elements_correct(attacker.element_set)
    damage /= 100
    if (damage > 0)
      damage = damage_correct(attacker, damage)
    end
    # Dispersion
    if damage.abs > 0
      amp = [damage.abs * 15 / 100, 1].max
      damage += rand(amp+1) + rand(amp+1) - amp
    end
    return damage
  end
 
  def non_magic_skill_effect(user, skill)
    # Clear critical flag
    self.critical = false
    return false unless skill_hit?(user, skill)
    # Clear effective flag
    effective = false
    # Set effective flag if common ID is effective
    effective |= skill.common_event_id > 0
    skill_rate = skill.get_rate_from_name
    #hit_result = attack_hit?(user)
    # First hit detection
    hit = skill.hit
    if skill.atk_f > 0
      hit *= user.hit / 100
    end
    hit_result = (rand(100) < hit)
    # Set effective flag if skill is uncertain
    effective |= hit < 100
    # If hit occurs
    if hit_result == true
      damage = attack_self_damage(user)
      self.damage = damage * skill_rate / 100
      # Element correction
      self.damage *= elements_correct(skill.element_set)
      self.damage /= 100
      # State Removed by Shock
      remove_states_shock
      # Substract damage from HP
      self.hp -= self.damage
      # State change
      @state_changed = false
      effective |= states_plus(skill.plus_state_set)
      effective |= states_minus(skill.minus_state_set)
    # When missing
    else
      # Set damage to "Miss"
      self.damage = "Miss"
    end
    # If not in battle
    unless $game_temp.in_battle
      # Set damage to nil
      self.damage = nil
    end
    # End Method
    return effective
  end
 
  # new
  alias default_skill_effect skill_effect
 
  def skill_effect(user, skill)
    if skill.non_magic_skill?
      non_magic_skill_effect(user, skill)
    else
      default_skill_effect(user, skill)
    end
  end
 
end
 
 
class Game_Actor < Game_Battler
  attr_accessor  :left_skills
 
  alias actor_init initialize
  def initialize(actor_id)
    #actor_init(actor_id)
    @left_skills = Hash.new
    @skill_level_learnt = Hash.new
    actor_init(actor_id)
    # fix level_learnt
    for i in 1..@level
      for j in $data_classes[@class_id].learnings
        if j.level == i
          #learn_skill(j.skill_id)
          @skill_level_learnt[j.skill_id] = i
        end
      end
    end
    update_left_skills
  end
 
  def max_skill_uses(id)
    lev_learnt = @skill_level_learnt[id]
    max = (@level-lev_learnt)/4
    max += 1
    return max
  end
 
  def learn_skill(skill_id)
    if skill_id > 0 and not skill_learn?(skill_id)
      @skills.push(skill_id)
      @skills.sort!
    end
    @left_skills[skill_id] = 1
    @skill_level_learnt[skill_id] = @level
  end
 
  def update_left_skills
    # update the number of skill uses. will return uses to max.
    for id in @skills
      lev_learnt = @skill_level_learnt[id]
      @left_skills[id] = 1+((@level-lev_learnt)/4)
    end  
 
  end
 
  #--------------------------------------------------------------------------
  # * Change Level
  #     level : new level
  #--------------------------------------------------------------------------
  def level=(level)
    # Check up and down limits
    level = [[level, $data_actors[@actor_id].final_level].min, 1].max
    # Change EXP
    self.exp = @exp_list[level]
    # edit: update skill uses to fit the new level.
    update_left_skills
  end
 
  # new
  #--------------------------------------------------------------------------
  # * Change EXP
  #     exp : new EXP
  #--------------------------------------------------------------------------
  def exp=(exp)
    @exp = [[exp, 9999999].min, 0].max
    # Level up
    while @exp >= @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
      update_left_skills          # edit
    end
    # Level down
    while @exp < @exp_list[@level]
      @level -= 1
      update_left_skills          # edit
    end
    # Correction if exceeding current max HP and max SP
    @hp = [@hp, self.maxhp].min
    @sp = [@sp, self.maxsp].min
   
  end
 
  #--------------------------------------------------------------------------
  # * Recover All
  #--------------------------------------------------------------------------
  def recover_all
    @hp = maxhp
    @sp = maxsp
    for i in @states.clone
      remove_state(i)
    end
    @skills.each { |id| @left_skills[id] = max_skill_uses(id) }
  end
 
  def skill_can_use?(skill_id)
    # --------------- edit -------------- #
    not_magical = $data_skills[skill_id].non_magic_skill?
    if not_magical
      # If there's not enough 'uses', the skill cannot be used.
      if @left_skills[skill_id] <= 0
        return false
      end
    else # skills use SP
      # If there's not enough SP, the skill cannot be used.
      if $data_skills[skill_id].sp_cost > self.sp
        return false
      end
    end
    # ----------------------------------- #
    if not skill_learn?(skill_id)
      return false
    end
    # Unusable if incapacitated
    if dead?
      return false
    end
    # If silent, only physical skills can be used
    if $data_skills[skill_id].atk_f == 0 and self.restriction == 1
      return false
    end
    # Get usable time
    occasion = $data_skills[skill_id].occasion
    # If in battle
    if $game_temp.in_battle
      # Usable with [Normal] and [Only Battle]
      return (occasion == 0 or occasion == 1)
    # If not in battle
    else
      # Usable with [Normal] and [Only Menu]
      return (occasion == 0 or occasion == 2)
    end
  end
 
end
 
class Window_Skill < Window_Selectable
  #--------------------------------------------------------------------------
  # * Draw Item
  #     index : item number
  #--------------------------------------------------------------------------
  def draw_item(index)
    skill = @data[index]
    if @actor.skill_can_use?(skill.id)
      self.contents.font.color = normal_color
    else
      self.contents.font.color = disabled_color
    end
    x = 4 + index % 2 * (288 + 32)
    y = index / 2 * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(skill.icon_name)
    opacity = self.contents.font.color == normal_color ? 255 : 128
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    # edit:
    if skill.non_magic_skill?
      # use skill.fixed_name, so the %x isn't shown on screen.
      # replace the sp cost with: left/max uses
      self.contents.draw_text(x + 28, y, 204, 32, skill.fixed_name, 0)
      max = @actor.max_skill_uses(skill.id)
      left = @actor.left_skills[skill.id]
      self.contents.draw_text(x + 232, y, 48, 32, "#{left}/#{max}", 2)
    else
      self.contents.draw_text(x + 28, y, 204, 32, skill.name, 0)
      self.contents.draw_text(x + 232, y, 48, 32, skill.sp_cost.to_s, 2)  
    end
   
  end
 
end
 
 
class Scene_Battle
  #--------------------------------------------------------------------------
  # * Make Skill Action Results
  #--------------------------------------------------------------------------
  def make_skill_action_result
    # Get skill
    @skill = $data_skills[@active_battler.current_action.skill_id]
    # If not a forcing action
    unless @active_battler.current_action.forcing
      # If unable to use due to SP running out
      unless @active_battler.skill_can_use?(@skill.id)
        # Clear battler being forced into action
        $game_temp.forcing_battler = nil
        # Shift to step 1
        @phase4_step = 1
        return
      end
    end
    # ----------------- edit ------------------- #
    unless @skill.non_magic_skill?
      # Use up SP
      @active_battler.sp -= @skill.sp_cost
    end
    # Use up 'skill times' instead
    if @active_battler.is_a?(Game_Actor) and @skill.non_magic_skill?
      @active_battler.left_skills[@skill.id] -= 1
    end
    # ------------------------------------------- #
    # Refresh status window
    @status_window.refresh
    # Show skill name on help window
    # edit: use skill.fixed_name
    @help_window.set_text(@skill.fixed_name, 1)
    # Set animation ID
    @animation1_id = @skill.animation1_id
    @animation2_id = @skill.animation2_id
    # Set command event ID
    @common_event_id = @skill.common_event_id
    # Set target battlers
    set_target_battlers(@skill.scope)
    # Apply skill effect
    for target in @target_battlers
      target.skill_effect(@active_battler, @skill)
    end
  end
 
end
[/rgss]
 
Oh !!! perfect i feel like a noob!! lol sorry its been awhile since the last time i actually used the maker lately i just sprite lol too much spriting work! and excelent job i feel really happy about this script.

now... can u make it work for Atoa custom battle system?

viewtopic.php?f=11&t=62914

or any sideview animated battle system

It doesnt cause any error it just doesnt work, all the skills are magic no matter what i do
 
I tried my script with this battle system and it works fine ?
You know you should set the number of the 'skill' element inside the script, right? it's on line 4: Non_Magic_Skill = 17
change the 17 to whatever is the number of your skill element, and make sure your non-magic-skills have this element in the database.
 
yup, thats what i did. I tested in a new project and worked and then in this demo and didnt work. Can u post upload a project with the demo and ur script working?
Im really thankful for ur help. My game will only have mogs scripts, that battle system and ur script. Ur script is the one giving the fun to my game.

I will test it this weekend. Im posting this from my cellphone. I only have computer on weeknds :p
 
I didn't do anything special to make it work..
maybe you placed my script in the wrong position.
It should be in a new page above Main and below anything else. Atoa's script has many pages below main, if you put scripts there they'll be ignored and won't do a thing.
 
Ok Silver Wind your script works perfectly. I just tested it thanx for everything. credits go for u and u should deffinitely post this script. all the phantasy star 4 fans would love this script :grin: i will lock this post after your reply.
 
Status
Not open for further replies.

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