[XP] Phoenix Engine ~ Game_Battler_3 Re-write

Started by PhoenixFire, March 15, 2014, 11:10:59 pm

Previous topic - Next topic

PhoenixFire

March 15, 2014, 11:10:59 pm Last Edit: June 14, 2014, 03:51:53 pm by PhoenixFire
Phoenix Engine ~ Alternate Attack Calculations
Authors: PhoenixFire/DigitalSoul and Xelias
Version: 1.0
Type: Custom Battle System / Default Script Edit
Key Term: Custom Battle System



Introduction

So part 1 of many.. I went ahead and re-wrote Game_Battler_3 with an included re-write of the Alternate Attack Algorithms originally made by Xelias. Note: You ABSOLUTELY MUST configure the script if you use it. The configuration bit is located at the top of the re-written script, along with an explanation of what each alternate algorithm does. This SHOULD be compatible with EVERYTHING, since it doesn't overwrite anything, but rather completely replaces the atk values that would be overwritten by other scripts..


Features


  • Re-write of the Game_Battler_3 standard script, changing the attack calculations.

  • Provides several alternate attack algorithms, which can be assigned to several weapons.

  • Fully configurable script re-write (you can always use the regular attack methods as well)




Screenshots

N/A ~ Not sure how you would screenshot something like that anyways..


Demo

N/A ~ Demo not needed.


Script


Spoiler: ShowHide

#==============================================================================
# ** Game_Battler (part 3)
#------------------------------------------------------------------------------
#  This class deals with battlers. It's used as a superclass for the Game_Actor
#  and Game_Enemy classes.
#==============================================================================

class Game_Battler

##:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
#    ALTERNATE ATTACK ALGORITHMS CONFIGURATION
#
##:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# How to use this script :
#
# This allows your weapons to follow different damage algorithms. If your weapon
# uses a normal attack algorithm, you MUST place its ID in the
# NORMAL_WEAPONS_IDS, or else it wouldn't be good for your game. Also place all
# weapons ID except SP damaging and absorbing ones, into the
# "ALL_WEAPONS_IDS", because if you don't, a nasty bug will prevent you from
# dealing damage with normal attack.
#
# ATMA_WEAPON_IDS = [X,X...] : A weapon with an ID equal to X will inflict
# more damage depending on the user's HP. If HP are full, attack power is doubled.
# If HP are at minimum, attack power is normal. If HP are equal to half, attack
# power is equal to 1.5 of the normal Attack power, and so on...
#
# VALIANT_IDS = [X, X...] : The opposite effect of Atma Weapon.
# If HP are at minimum, attack power is doubled, and so on...
#
# WHITE_MOON_IDS = [X, X...] : Follows the same formula than Atma Weapon
# but works with SP
#
# CONFORMER_IDS = [X, X...] : Deals damage based on user's Level.
#
# INTEL_WEAPON_IDS = [X, X...] : Inflicts damage based on user's Intelligence
# instead of Strength
#
# NINJA_IDS = [X, X...] : Inflicts damage based on user's Agility
# instead of Strength
#
# MIND_BLASTER_IDS = [X, X...] : Damage is inflicted to SP. Damage
# relies also on the opponent's Magic Defense and your Intelligence
#
# BLOOD_SWORD_IDS = [X, X...] & PERCENT_DRAINED = X : 
# some damage is absorbed from the attack. How many? PERCENT_DRAINED %
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= 

  OTHER_WEAPONS_IDS = [0]
  ALL_WEAPONS_IDS = []

  ATMA_WEAPON_IDS = []
  VALIANT_IDS = []
  WHITE_MOON_IDS = []
  CONFORMER_IDS = []
  INTEL_WEAPON_IDS = []
  NINJA_IDS = []
  MIND_BLASTER_IDS = []
  BLOOD_SWORD_IDS = []
  PERCENT_DRAINED = 50

  #--------------------------------------------------------------------------
  # * Determine Usable Skills
  #     skill_id : skill ID
  #--------------------------------------------------------------------------
  def skill_can_use?(skill_id)
    # If there's not enough SP, the skill cannot be used.
    if $data_skills[skill_id].sp_cost > self.sp
      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
#--------------------------------------------------------------------------
# * Applying Normal Attack Effects
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# Alternative Attack Algorithms
# Authors: Xelias and PhoenixFire
# Version: 1.00
# Type: Battle Add-ON
# Date v1.00:   7.11.2009
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

#  This work is protected by the following license:
# #----------------------------------------------------------------------------
# # 
# #  Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
# #  ( http://creativecommons.org/licenses/by-nc-sa/3.0/ )
# # 
# #  You are free:
# # 
# #  to Share - to copy, distribute and transmit the work
# #  to Remix - to adapt the work
# # 
# #  Under the following conditions:
# # 
# #  Attribution. You must attribute the work in the manner specified by the
# #  author or licensor (but not in any way that suggests that they endorse you
# #  or your use of the work).
# # 
# #  Noncommercial. You may not use this work for commercial purposes.
# # 
# #  Share alike. If you alter, transform, or build upon this work, you may
# #  distribute the resulting work only under the same or similar license to
# #  this one.
# # 
# #  - For any reuse or distribution, you must make clear to others the license
# #    terms of this work. The best way to do this is with a link to this web
# #    page.
# # 
# #  - Any of the above conditions can be waived if you get permission from the
# #    copyright holder.
# # 
# #  - Nothing in this license impairs or restricts the author's moral rights.
# # 
# #----------------------------------------------------------------------------
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

def attack_effect(attacker)
    # Clear critical flag
    self.critical = false
    # First hit detection
    hit_result = (rand(100) < attacker.hit)
    # If hit occurs
    if hit_result == true
      # Calculate basic damage
          if attacker.is_a?(Game_Actor)
    if OTHER_WEAPONS_IDS.include?(attacker.weapon_id)
    atk = [attacker.atk - self.pdef / 2, 0].max
     self.damage = atk * (20 + attacker.str) / 20
   end
   if ATMA_WEAPON_IDS.include?(attacker.weapon_id)
     atk = [attacker.atk - self.pdef / 2,0].max
     atk2 = atk * (20 + attacker.str) / 20
    self.damage = atk2 + ((atk2*((attacker.hp*100)/attacker.maxhp))/100)
    end
       if VALIANT_IDS.include?(attacker.weapon_id)
     atk = [attacker.atk - self.pdef / 2,0].max
     atk2 = atk * (20 + attacker.str) / 20
     minushp = attacker.maxhp - attacker.hp
    self.damage = atk2 + ((atk2*((minushp*100)/attacker.maxhp))/100)
    end
     if WHITE_MOON_IDS.include?(attacker.weapon_id)
     atk = [attacker.atk - self.pdef / 2,0].max
     atk2 = atk * (20 + attacker.str) / 20
    self.damage = atk2 + ((atk2*((attacker.sp*100)/attacker.maxsp))/100)
  end
       if CONFORMER_IDS.include?(attacker.weapon_id)
     atk = [attacker.atk - self.pdef / 2,0].max
     atk2 = atk * (20 + attacker.str) / 20
    self.damage = atk2 + (atk2*(((attacker.level*100) / 99)/100))
  end
      if INTEL_WEAPON_IDS.include?(attacker.weapon_id)
    atk = [attacker.atk - self.pdef / 2, 0].max
     self.damage = atk * (20 + attacker.int) / 20
   end
      if NINJA_IDS.include?(attacker.weapon_id)
    atk = [attacker.atk - self.pdef / 2, 0].max
     self.damage = atk * (20 + attacker.agi) / 20
   end
      if BLOOD_SWORD_IDS.include?(attacker.weapon_id)
    atk = [attacker.atk - self.pdef / 2, 0].max
     self.damage = atk * (20 + attacker.str) / 20
   end
   end
   if attacker.is_a?(Game_Enemy)
      atk = [attacker.atk - self.pdef / 2, 0].max
     self.damage = atk * (20 + attacker.str) / 20
   end
      # Element correction
    self.damage *= elements_correct(attacker.element_set)
      self.damage /= 100
      # If damage value is strictly positive
      if self.damage > 0
        # Critical correction
        if attacker.is_a?(Game_Actor)
    if GENJI_WEAPON_IDS.include?(attacker.weapon_id)
        if rand(100) < 8 * attacker.dex / self.agi
          self.damage *= 2
          self.critical = true
        end
        end
      if KIKU_ICHIMONJI_IDS.include?(attacker.weapon_id)
        if rand(100) < 4 * attacker.dex / self.agi
          self.damage *= 4
          self.critical = true
        end
      end
    elsif rand(100) < 4 * attacker.dex / self.agi
          self.damage *= 2
          self.critical = true
        end
        # Guard correction
        if self.guarding?
        if GUARD_BREAKER_IDS.include?(attacker.weapon_id)
       self.damage /=1
          end
     else
       self.damage /=2
     end
      # Dispersion
   if self.damage.abs > 0
        amp = [self.damage.abs * 15 / 100, 1].max
        self.damage += rand(amp+1) + rand(amp+1) - amp
      end
      # Second hit detection
      eva = 8 * self.agi / attacker.dex + self.eva
      hit = self.damage < 0 ? 100 : 100 - eva
      hit = self.cant_evade? ? 100 : hit
      hit_result = (rand(100) < hit)
    end
     # If hit occurs
    if hit_result == true
      # State Removed by Shock
      remove_states_shock
      # Substract damage from HP
       if attacker.is_a?(Game_Actor)
      if MIND_BLASTER_IDS.include?(attacker.weapon_id)
        self.sp -= self.damage
        self.damage = sprintf('%+d %s', -self.damage, $data_system.words.sp)
        end
      if BLOOD_SWORD_IDS.include?(attacker.weapon_id)
       healing = (self.damage*PERCENT_DRAINED)/100
        self.hp -= self.damage
        attacker.hp += healing
      end
      if ALL_WEAPONS_IDS.include?(attacker.weapon_id)
        self.hp -= self.damage
    end
    else self.hp -= self.damage
  end
  end
      # State change
      @state_changed = false
      states_plus(attacker.plus_state_set)
      states_minus(attacker.minus_state_set)
    # When missing
    else
      # Set damage to "Miss"
      self.damage = "Miss"
      # Clear critical flag
      self.critical = false
    end
    # End Method
    return true
  end
end
  #--------------------------------------------------------------------------
  # * Apply Skill Effects
  #     user  : the one using skills (battler)
  #     skill : skill
  #--------------------------------------------------------------------------
  def skill_effect(user, skill)
    # Clear critical flag
    self.critical = false
    # If skill scope is for ally with 1 or more HP, and your own HP = 0,
    # or skill scope is for ally with 0, and your own HP = 1 or more
    if ((skill.scope == 3 or skill.scope == 4) and self.hp == 0) or
       ((skill.scope == 5 or skill.scope == 6) and self.hp >= 1)
      # End Method
      return false
    end
    # Clear effective flag
    effective = false
    # Set effective flag if common ID is effective
    effective |= skill.common_event_id > 0
    # 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
      # Calculate power
      power = skill.power + user.atk * skill.atk_f / 100
      if power > 0
        power -= self.pdef * skill.pdef_f / 200
        power -= self.mdef * skill.mdef_f / 200
        power = [power, 0].max
      end
      # Calculate rate
      rate = 20
      rate += (user.str * skill.str_f / 100)
      rate += (user.dex * skill.dex_f / 100)
      rate += (user.agi * skill.agi_f / 100)
      rate += (user.int * skill.int_f / 100)
      # Calculate basic damage
      self.damage = power * rate / 20
      # Element correction
      self.damage *= elements_correct(skill.element_set)
      self.damage /= 100
      # If damage value is strictly positive
      if self.damage > 0
        # Guard correction
        if self.guarding?
          self.damage /= 2
        end
      end
      # Dispersion
      if skill.variance > 0 and self.damage.abs > 0
        amp = [self.damage.abs * skill.variance / 100, 1].max
        self.damage += rand(amp+1) + rand(amp+1) - amp
      end
      # Second hit detection
      eva = 8 * self.agi / user.dex + self.eva
      hit = self.damage < 0 ? 100 : 100 - eva * skill.eva_f / 100
      hit = self.cant_evade? ? 100 : hit
      hit_result = (rand(100) < hit)
      # Set effective flag if skill is uncertain
      effective |= hit < 100
    end
    # If hit occurs
    if hit_result == true
      # If physical attack has power other than 0
      if skill.power != 0 and skill.atk_f > 0
        # State Removed by Shock
        remove_states_shock
        # Set to effective flag
        effective = true
      end
      # Substract damage from HP
      last_hp = self.hp
      self.hp -= self.damage
      effective |= self.hp != last_hp
      # State change
      @state_changed = false
      effective |= states_plus(skill.plus_state_set)
      effective |= states_minus(skill.minus_state_set)
      # If power is 0
      if skill.power == 0
        # Set damage to an empty string
        self.damage = ""
        # If state is unchanged
        unless @state_changed
          # Set damage to "Miss"
          self.damage = "Miss"
        end
      end
    # If miss occurs
    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
  #--------------------------------------------------------------------------
  # * Application of Item Effects
  #     item : item
  #--------------------------------------------------------------------------
  def item_effect(item)
    # Clear critical flag
    self.critical = false
    # If item scope is for ally with 1 or more HP, and your own HP = 0,
    # or item scope is for ally with 0 HP, and your own HP = 1 or more
    if ((item.scope == 3 or item.scope == 4) and self.hp == 0) or
       ((item.scope == 5 or item.scope == 6) and self.hp >= 1)
      # End Method
      return false
    end
    # Clear effective flag
    effective = false
    # Set effective flag if common ID is effective
    effective |= item.common_event_id > 0
    # Determine hit
    hit_result = (rand(100) < item.hit)
    # Set effective flag is skill is uncertain
    effective |= item.hit < 100
    # If hit occurs
    if hit_result == true
      # Calculate amount of recovery
      recover_hp = maxhp * item.recover_hp_rate / 100 + item.recover_hp
      recover_sp = maxsp * item.recover_sp_rate / 100 + item.recover_sp
      if recover_hp < 0
        recover_hp += self.pdef * item.pdef_f / 20
        recover_hp += self.mdef * item.mdef_f / 20
        recover_hp = [recover_hp, 0].min
      end
      # Element correction
      recover_hp *= elements_correct(item.element_set)
      recover_hp /= 100
      recover_sp *= elements_correct(item.element_set)
      recover_sp /= 100
      # Dispersion
      if item.variance > 0 and recover_hp.abs > 0
        amp = [recover_hp.abs * item.variance / 100, 1].max
        recover_hp += rand(amp+1) + rand(amp+1) - amp
      end
      if item.variance > 0 and recover_sp.abs > 0
        amp = [recover_sp.abs * item.variance / 100, 1].max
        recover_sp += rand(amp+1) + rand(amp+1) - amp
      end
      # If recovery code is negative
      if recover_hp < 0
        # Guard correction
        if self.guarding?
          recover_hp /= 2
        end
      end
      # Set damage value and reverse HP recovery amount
      self.damage = -recover_hp
      # HP and SP recovery
      last_hp = self.hp
      last_sp = self.sp
      self.hp += recover_hp
      self.sp += recover_sp
      effective |= self.hp != last_hp
      effective |= self.sp != last_sp
      # State change
      @state_changed = false
      effective |= states_plus(item.plus_state_set)
      effective |= states_minus(item.minus_state_set)
      # If parameter value increase is effective
      if item.parameter_type > 0 and item.parameter_points != 0
        # Branch by parameter
        case item.parameter_type
        when 1  # Max HP
          @maxhp_plus += item.parameter_points
        when 2  # Max SP
          @maxsp_plus += item.parameter_points
        when 3  # Strength
          @str_plus += item.parameter_points
        when 4  # Dexterity
          @dex_plus += item.parameter_points
        when 5  # Agility
          @agi_plus += item.parameter_points
        when 6  # Intelligence
          @int_plus += item.parameter_points
        end
        # Set to effective flag
        effective = true
      end
      # If HP recovery rate and recovery amount are 0
      if item.recover_hp_rate == 0 and item.recover_hp == 0
        # Set damage to empty string
        self.damage = ""
        # If SP recovery rate / recovery amount are 0, and parameter increase
        # value is ineffective.
        if item.recover_sp_rate == 0 and item.recover_sp == 0 and
           (item.parameter_type == 0 or item.parameter_points == 0)
          # If state is unchanged
          unless @state_changed
            # Set damage to "Miss"
            self.damage = "Miss"
          end
        end
      end
    # If miss occurs
    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
  #--------------------------------------------------------------------------
  # * Application of Slip Damage Effects
  #--------------------------------------------------------------------------
  def slip_damage_effect
    # Set damage
    self.damage = self.maxhp / 10
    # Dispersion
    if self.damage.abs > 0
      amp = [self.damage.abs * 15 / 100, 1].max
      self.damage += rand(amp+1) + rand(amp+1) - amp
    end
    # Subtract damage from HP
    self.hp -= self.damage
    # End Method
    return true
  end
  #--------------------------------------------------------------------------
  # * Calculating Element Correction
  #     element_set : element
  #--------------------------------------------------------------------------
  def elements_correct(element_set)
    # If not an element
    if element_set == []
      # Return 100
      return 100
    end
    # Return the weakest object among the elements given
    # * "element_rate" method is defined by Game_Actor and Game_Enemy classes,
    #    which inherit from this class.
    weakest = -100
    for i in element_set
      weakest = [weakest, self.element_rate(i)].max
    end
    return weakest
  end
end



Instructions

To install, simply copy and paste over the default Game_Battler_3 script. IF YOU THINK YOU MAY WANT TO SWITCH BACK~ Always make a backup of scripts before major changes, but, even if you don't, you can "create a new project" and simply copy the default script from the new project, and paste it over the modified one. You absolutely MUST configure the script for it to work properly. Config instructions are within the script, above the configuration variables, at the top of the script.


Compatibility

Does not work with rpgmaker XP version 1.05 ~ Causes the following error:

NoMethodError
Undefined method "*" for nil:NilClass


Unfortunately, I have no idea how to fix this at the moment, but if I find a solution, I will certainly fix it.


Credits and Thanks


  • PhoenixFire/DigitalSoul ~ The re-write and editing.

  • Xelias ~ The original Alternate Algorithms script. Parts of it were used in this re-write.




Author's Notes

Enjoy the script! Really, I'm trying to better my scripting abilities, and this is just a simple start. I know that it's not much of an edit, but in time, I plan to re-write most, if not all, of the default scripts to have added functionality.

Restrictions: None - You may use this in your game, whether commercial or non-commercial, as long as proper credit is given.
Quote from: Subsonic_Noise on July 01, 2011, 02:42:19 amNext off, how to create a first person shooter using microsoft excel.

Quote from: Zeriab on September 09, 2011, 02:58:58 pm<Remember when computers had turbo buttons?

Blizzard

March 16, 2014, 04:36:06 am #1 Last Edit: March 16, 2014, 04:37:17 am by Blizzard
Quote from: DigitalSoul on March 15, 2014, 11:10:59 pm
This SHOULD be compatible with EVERYTHING, since it doesn't overwrite anything,


Actually no. The script literally does overwrite all the methods (attack_effect, skill_effect, etc.). It won't work with most customizations to battle algorithm and custom skill effects properly unless it is put above them. I didn't take a look at your implementation, but even then it might not work well.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

PhoenixFire

March 25, 2014, 09:56:00 pm #2 Last Edit: May 03, 2014, 11:40:50 am by PhoenixFire
Alright, updated the compatibility section to warn people of that. I guess I didn't think of that, since this is near the top of the script list, being an overwrite of a core script anyways....
Quote from: Subsonic_Noise on July 01, 2011, 02:42:19 amNext off, how to create a first person shooter using microsoft excel.

Quote from: Zeriab on September 09, 2011, 02:58:58 pm<Remember when computers had turbo buttons?