This script allows you to give actors the ability to increase their skill with a specified assortment of armor components. It does so by giving an actor's defined armor collection a level with experience to gain when in use. And as their level increases, so to does their base physical defense used during combat.
The system does not affect magical defense.
Features
Define armor style sets, so a collection of heavy armor pieces (by ID) could be one set and you gain proficiency with all of a given set
Sets have levels, so proficiency is those sets gaining their own experience
The player's own Experience Points or Level curve is used. So proficiency with armor types can be different per actor.
You can gauge how much or little bonus to the base physical defense score per level
Screenshots
That's a negatory, fellah.
Demo
Nuh uh.
Script
The Script
Code:
#==============================================================================
# ** Adeyemi's Armor Proficiency
#------------------------------------------------------------------------------
# by DerVVulfman
# version 1.0
# 04-25-2025 (mm/dd/yyyy)
# RGSS / RPGMaker XP
#==============================================================================
#
# INTRODUCTION:
#
# This script allows you to give actors the ability to increase their skill
# with a specified assortment of armor components. It does so by giving an
# actor's defined armor collection a level with experience to gain when in
# use. And as their level increases, so to does their base physical defense
# used during combat.
#
# Bonus features include:
#
# * The in-game removal of class armor limits. You may be forced to set a
# specific armor to an actor at game start. But as the game goes on, any
# actor can use any piece of armor defined in the Armor database.
#
# I wrote the instructions into the coonfiguration section. Enjoy.
#
#
#------------------------------------------------------------------------------
#
# NOTES:
#
# The base_pdef value (whether from Game_Actor or Game_Enemy) is used by
# the Game_Battler class to calculate the 'physical defense' value used
# for any/all attack, skill and item based attacks. Its effect is visible
# within the status and equipment screend.
#
# The system does not affect magical defense.
#
# When I created the 'weapon_prof_chance' method within Game_Battler on
# line 434, I did so with the expectation of making add-ons that can in-
# fluence the actor's chance of success when gaining experience points.
#
# When you craft an armor style with the ARMOR_STYLE hash array, you give
# each style a name. Couple that with the leveling system, prospective
# scripters could create updates to the Equip, Status any similar menu to
# show their armor proficiency levels by name.
#
#
#------------------------------------------------------------------------------
#
# VERSION HISTORY:
#
# 1.0 - 2025-04-19: Original release
# 1.1 - 2025-04-20: Altered exp storage to track all styles (if style changes)
# 1.2 - 2025-04-24: Three alterations to the script
# * Altered: Changed value and method names in RPG script
# * Fixed: Value identifying which experience points to test
# * Fixed: Method to find highest leveled weapon proficiency
#
#
#------------------------------------------------------------------------------
#
# COMPATIBILITY:
#
# Fairly compatible for RPGMaker XP systems as there are no rewrites to any
# classes, all content using aliased methods.
#
#
#==============================================================================
#
# TERMS OF USE:
#
# Free for use, even in commercial games. Only due credit is required.
#
#
#==============================================================================
module Yemi
#--------------------------------------------------------------------------
# DO NOT TOUCH
#--------------------------------------------------------------------------
ARMOR_STYLE, ARMOR_CLASS, ARMOR_ACTOR, ARMOR_BONUS = {},{},{},{}
ARMOR_C_LOSS, ARMOR_A_LOSS = {},{}
#--------------------------------------------------------------------------
# ARMOR STYLES
# =============
# A list of individual style sets: A style set consists of the name of the
# style along with other options related to that style:
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# * Name: Name of the styleset
# * Ch: Chance of gaining exp per successful hit
# * Armor IDs: List of all armor pieces, each in their own arrays
# * Exp: Exp gained per armor piece worn if actively struck
# * The Armor IDs are in four specific arrays
# * Note that the "Unarmored" style has a '0' included
# in the Body armor section. Armor #0 or 'no' armor.
#--------------------------------------------------------------------------
#
# ID Name Ch. Shield, Helmet, Body, Acc Exp
# == ========== === ========== ========== ========== ========== ===
ARMOR_STYLE[1] = [ 'Tank', 70, [ [1,2,3,4], [5,6,7,8], [17,18,19,20], [] ], 0.1 ]
ARMOR_STYLE[2] = [ 'Heavy', 100, [ [1,2,3,4], [5,6,7,8], [13,14,15,16], [] ], 0.1 ]
ARMOR_STYLE[3] = [ 'Medium', 70, [ [], [5,6,7,8], [13,14,15,16], [] ], 0.1 ]
ARMOR_STYLE[4] = [ 'Light', 70, [ [], [], [21,22,23,24], [] ], 0.1 ]
ARMOR_STYLE[5] = [ 'Unarmored', 70, [ [], [], [0,21,22], [] ], 0.1 ]
# ASSIGNED ARMOR STYLES
# ======================
# This section applies armor styles to character classes and actors alike.
# Do know that duplicates are removed.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# * Class/Actor ID: ID of the actor or class depending on the hash array
# * Armor Styles: The ID(s) of the armor styles defined above within
# ARMOR STYLES section.
# * If a single actor is defined an Armor Style within
# the ARMOR_CLASS array and the same style within the
# ARMOR_ACTOR array, the system will recognize this
# duplication and will remove the duplicate instance.
#--------------------------------------------------------------------------
#
# Class ID Weaspon Style(s)
# ======== ================
ARMOR_CLASS[1] = [2,3] # (1)Fighters are trained in Heavy and Medium
ARMOR_CLASS[2] = [2] # (2)Warriors are trained in Heavy armor only
ARMOR_CLASS[4] = [3] # (4)Thieves are trained with medium armor
ARMOR_CLASS[7] = [4] # (7)Clerics use light armor, not meant to fight
# Actor ID Weaspon Style(s)
# ======== ================
ARMOR_ACTOR[2] = [1] # (2)Basil was trained with TANK armor also
ARMOR_ACTOR[8] = [5] # (8)Hilda works best unarmored
# ASSIGNED ARMOR PENALTIES
# =========================
# This section will apply percentage based penalties to the actor's base pdef
# score if any armor pieces defined in use. There are two hash arrays in
# which to accomplish this, and the effects CAN be cumulative.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# * Class/Actor ID: ID of the actor or class depending on the hash array
# * Per: Percentage of Base Pdef loss (ie 20 is -20% loss).
# * Armor IDs: List of all armor pieces that deliver the penalty
# * NOTE: The effects are cumulative. In the below
# example, Hilda (as a mage) would lose 10% of her
# base_pdf score from the CLASS penalty if she used
# any shield or plate or heavy armor. However, the
# helmets are fine. And Gloria is set up to hate the
# use of helmets, losing 25% of her base_pdef. IF
# Gloria was a mage, she'd be stuck not using any!
#--------------------------------------------------------------------------
#
# Class ID Per Armor IDs
# ======== === ================
ARMOR_C_LOSS[8] = [ 10, [1,2,3,4,13,14,15,16,17,18,19,20]] #(8)Mage
#
# Actor ID Per Armor IDs
# ======== === ================
ARMOR_A_LOSS[7] = [ 25, [5,6,7,8]] #(7)Gloria hates helmets
# LEVEL GAIN ADJUSTMENT
# =====================
# The armor sets for any actor is based upon the same experience curve as
# the actor's own experience point leveling curve. This means the armor
# style levels can reach level 100 if so defined. However, this section may
# assist you in slowing down the rate of style set leveling and limit how
# many levels that the armor style sets can attain.
#
# These levels are important for the LEVEL ATTACK BONUS ADJUSTMENT below.
#--------------------------------------------------------------------------
#
ARMOR_DIVIDE = 3 # Set to 3. The higher the rate, the slower the gain.
# If set to 1, it is normal. Nothing lower than 1.
ARMOR_MAX = 5 # Set to 5, the sets cannot go beyond level 5.
# If set to 1, sets won't grow. Nothing lower than 1.
# LEVEL ATTACK BONUS ADJUSTMENT
# =============================
# This final area defines what bonus the actors have when using armor which
# they are skilled and trained (based on their applied armor sets). Each of
# the armor bonus level entries is an array divided into four parameters,
# each parameter for a type of armor: shield, helmet, body armor, accessory.
# Each is given a small floating point value. However, these values are cu-
# mulative. In that, if an actor is wearing three pieces of armor, their
# bonus will be for those three values combined. It IS assumed that these
# values would be positive as negative values would be a penalty.
#
# The below example only has five WEAP_BONUS entries as I set the MAX_LEVEL
# value (above) to 5. I could set MAX_LEVEL to 10 and make five more entries,
# but opted not. Just so ya know, it is flexible.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# * Level ID: The level for any weapon set to give the defined bonus
# * Multiplier: Four multiplier bonuses for the Base PDef value
# * The multipliers are for Shield, Helmet, Body Armor and
# Accessory in that order.
#--------------------------------------------------------------------------
#
# Level ID Multipliers
# ======== ==== ==== ==== ====
ARMOR_BONUS[1] = [ 0.1, 0.1, 0.1, 0.1 ]
ARMOR_BONUS[2] = [ 0.2, 0.2, 0.2, 0.1 ]
ARMOR_BONUS[3] = [ 0.3, 0.3, 0.3, 0.1 ]
ARMOR_BONUS[4] = [ 0.4, 0.4, 0.5, 0.1 ]
ARMOR_BONUS[5] = [ 0.5, 0.5, 0.7, 0.1 ]
end
#==============================================================================
# ** RPG
#------------------------------------------------------------------------------
# A module containing RPGXP's data structures and more.
#==============================================================================
module RPG
#--------------------------------------------------------------------------
# * Clear all class armor limitations
#--------------------------------------------------------------------------
def RPG.yemi_class_clear_a
#
return if @initialized_yemi_class_clear_a # Exit if executed
class_clear_armor # Clear armor
@initialized_yemi_class_clear_a = true # Flag executed
#
end
#--------------------------------------------------------------------------
# * Clear all class armor limitations
#--------------------------------------------------------------------------
def RPG.class_clear_armor
#
for classes in $data_classes # Cycle thru classes
next if classes.nil? # Skip invalid class
classes.armor_set = [] # Clear armor set
for armor in $data_armors # Cycle thru armor
next if armor.nil? # Skip invalid armor
classes.armor_set.push(armor.id) # Push all armor IDs
end
end
#
end
#--------------------------------------------------------------------------
# * RPG Initialized Class Clearing
# bool : boolean value (true/false)
#--------------------------------------------------------------------------
def RPG.initialized_yemi_class_clear_a=(bool)
#
@initialized_yemi_class_clear_a = bool # Set/reset flag
#
end
end
#==============================================================================
# ** Game_Battler
#------------------------------------------------------------------------------
# This class deals with battlers. It's used as a superclass for the Game_Actor
# and Game_Enemy classes.
#==============================================================================
class Game_Battler
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
alias yemi2_battler_attack_effect attack_effect
alias yemi2_battler_skill_effect skill_effect
alias yemi2_battler_item_effect item_effect
#--------------------------------------------------------------------------
# * Applying Normal Attack Effects
# attacker : battler
#--------------------------------------------------------------------------
def attack_effect(attacker)
#
hp_test = self.hp # Get hp test value
effective = yemi2_battler_attack_effect(attacker) # Perform the method
hp_retest = self.hp # Get current HP
if hp_retest != hp_test # If HP changed
attack_effect_armor_prof # Run armor prof
end
return effective # Exit effective
#
end
#--------------------------------------------------------------------------
# * Apply Skill Effects
# user : the one using skills (battler)
# skill : skill
#--------------------------------------------------------------------------
def skill_effect(user, skill)
#
hp_test = self.hp # Get hp test value
effective = yemi2_battler_skill_effect(user, skill) # Perform the method
hp_retest = self.hp # Get current HP
if hp_retest != hp_test # If HP changed
attack_effect_armor_prof # Run armor prof
end
return effective # Exit effective
#
end
#--------------------------------------------------------------------------
# * Application of Item Effects
# item : item
#--------------------------------------------------------------------------
def item_effect(item)
#
hp_test = self.hp # Get hp test value
effective = yemi2_battler_skill_effect(user, skill) # Perform the method
hp_retest = self.hp # Get current HP
if hp_retest != hp_test # If HP changed
attack_effect_armor_prof # Run armor prof
end
return effective # Exit effective
#
end
#--------------------------------------------------------------------------
# * Get Armor Proficiency
#--------------------------------------------------------------------------
def attack_effect_armor_prof
#
return unless self.is_a?(Game_Actor) # Exit if not an actor
return if self.prof_armor == [] # Exit if no profs.
for prof_id in self.prof_armor # Cycle through styles
armor_prof_exp(prof_id) # Process experience
end
#
end
#--------------------------------------------------------------------------
# * Set Armor Proficiency Experience
# prof_id : ID of proficiency skill for aggressor
#--------------------------------------------------------------------------
def armor_prof_exp(prof_id)
#
prof_style = Yemi::ARMOR_STYLE[prof_id] # Get style array
for id in 0..3 # Cycle through armors
armor_prof_components(prof_style, prof_id, id) # Process each armor
end
#
end
#--------------------------------------------------------------------------
# * Set Individual Armor Experience Value
# prof_id : ID of proficiency skill for aggressor
#--------------------------------------------------------------------------
def armor_prof_components(prof_style, prof_id, id)
#
chance = prof_style[1] # Get chance
prof_list = prof_style[2] # Get full armor list
prof_exp = prof_style[3] # Get experience
list = prof_list[id] # Get list
armor_txt = "self.armor" + (id+1).to_s + "_id" # Get armor string
armor_idx = eval(armor_txt) # Get evaluation
return unless armor_prof_chance(chance) # Exit if chance fails
return unless list.include?(armor_idx) # Exit if no armor
keys = Yemi::ARMOR_STYLE.keys # Get keys to styles
keys.sort! # Ensure key order
idx = keys.index(prof_id) # Get index position
self.prof_armor_exp[idx] += prof_exp # Increase style exp
#
end
#--------------------------------------------------------------------------
# * Set Armor Proficiency Experience
# chance : chance of success for that weapon set
#--------------------------------------------------------------------------
def armor_prof_chance(chance)
#
effective = (rand(100) < chance) # Get chance success
return effective # Exit with outcome
#
end
end
#==============================================================================
# ** Game_Actor
#------------------------------------------------------------------------------
# This class handles the actor. It's used within the Game_Actors class
# ($game_actors) and refers to the Game_Party class ($game_party).
#==============================================================================
class Game_Actor < Game_Battler
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :prof_armor # Armor proficiency list
attr_accessor :prof_armor_exp # Armor proficiency experience
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias yemi2_actor_setup setup
alias yemi_actor_base_pdef base_pdef
#--------------------------------------------------------------------------
# * Setup
# actor_id : actor ID
#--------------------------------------------------------------------------
def setup(actor_id)
yemi2_actor_setup(actor_id) # Perform the method
setup_proficiencies_armor # Setup weapon profs
end
#--------------------------------------------------------------------------
# * Get Basic Attack Power
#--------------------------------------------------------------------------
def base_pdef
#
score = yemi_actor_base_pdef # Perform the method
score = armor_penalty_change(score) # Adj for penalty
score = armor_proficiency_change(score) # Adj for proficiency
return score.to_i # Exit with score
#
end
#--------------------------------------------------------------------------
# * Setup Proficiencies in Armor
#--------------------------------------------------------------------------
def setup_proficiencies_armor
#
@prof_armor = [] # Clear proficiencies
if Yemi::ARMOR_CLASS.has_key?(@class_id) # If class proficiency
for id in Yemi::ARMOR_CLASS[@class_id] # Cycle through styles
@prof_armor.push(id) # Push styles
end
end
if Yemi::ARMOR_ACTOR.has_key?(@actor_id) # If actor proficiency
for id in Yemi::ARMOR_ACTOR[@actor_id] # Cycle through styles
@prof_armor.push(id) # Push styles
end
end
@prof_armor.uniq! # Remove duplicates
keys = Yemi::ARMOR_STYLE.keys # Get keys to styles
size = keys.size # Get total num styles
@prof_armor_exp = Array.new(size, 0.0) # Make style exp array
#
end
#--------------------------------------------------------------------------
# * Get Weapon Proficiency Penalty
# score : base_atk score
#--------------------------------------------------------------------------
def armor_penalty_change(score)
#
return score if score == 0 # Exit if '0' score
test = false # Assume failure
test = true if Yemi::ARMOR_C_LOSS.has_key?(@class_id) # True if class loss
test = true if Yemi::ARMOR_A_LOSS.has_key?(@actor_id) # True if actor loss
return score unless test # Exit unless true
loss_test = Yemi::ARMOR_C_LOSS[@class_id] # Get class loss
score = armor_penalty_calc(score, loss_test) # Execute class loss
loss_test = Yemi::ARMOR_A_LOSS[@actor_id] # Get actor loss
score = armor_penalty_calc(score, loss_test) # Execute actor loss
return score.to_i # Exit with score
#
end
#--------------------------------------------------------------------------
# * Get Weapon Proficiency Bonus
# score : base_atk score
# loss_array : penalty array
#--------------------------------------------------------------------------
def armor_penalty_calc(score, loss_array)
#
return score if loss_array.nil? # Exit if no penalty
armor = loss_array[1] # Get penalty weapons
penalty = 0 # Assume no penalty
for id in 0..3 # Cycle through armors
armor_txt = "@armor" + (id+1).to_s + "_id" # Get armor string
armor_idx = eval(armor_txt) # Get evaluation
next unless armor.include?(armor_idx) # Skip if not armor
penalty += loss_array[0].to_f # Add penalty percent
end
return score if penalty == 0 # Exit if no penalty
score *= ((100-penalty)/100) # Reduce by percent
return score.to_i # Exit with score
#
end
#--------------------------------------------------------------------------
# * Get Armor Proficiency Bonus
# score : base_atk score
#--------------------------------------------------------------------------
def armor_proficiency_change(score)
#
return score if @prof_armor == [] # Exit if no profs.
retval = armor_proficiency_level # Get returned value
level = retval[0] # Get proficiency lvl
idx = retval[2] # Get Style Index
return score if level.nil? # Exit if no level
return score if level == 0 # Exit if 0 level
level = Yemi::ARMOR_MAX if level > Yemi::ARMOR_MAX # Cannot exceed max
keys = Yemi::ARMOR_STYLE.keys # Get keys to styles
keys.sort! # Ensure sorted order
prof_id = keys[idx] # Get Style ID
prof_style = Yemi::ARMOR_STYLE[prof_id] # Get style
prof_list = prof_style[2] # Get armor lists
bonus = 1.0 # Reset bonus to 1
for id in 0..3 # Cycle through armors
armor_txt = "@armor" + (id+1).to_s + "_id" # Get armor string
armor_idx = eval(armor_txt) # Get evaluation
the_list = prof_list[id] # Get armor sub list
next unless the_list.include?(armor_idx) # Skip unless armor
value = Yemi::ARMOR_BONUS[level] # Level bonus per type
bonus += value[id] # Level bonus per type
end
score *= bonus # Increase by bonuses
return score.to_i # Exit with score
#
end
#--------------------------------------------------------------------------
# * Get Armor Proficiency Level
#--------------------------------------------------------------------------
def armor_proficiency_level
#
exp, idx = 0, 0 # Reset exp and idx
make_list = [] # Create new exp list
for exp_score in @prof_armor_exp # Cycle through exp
make_list.push([exp_score,idx]) # push exp and idx
idx += 1 # increase idx
end
make_list.sort! # Sort exp low-to-high
make_list.reverse! # Reverse to high/low
for item in make_list # Sort exp list
exp = item[0] # Get Exp score
idx = item[1] # Get index position
result = armor_proficiency_found?(idx) # Get armor result
qty = result[0] # Get qty of armors
break if result[1] # Exit loop if found
end
exp = 0 if exp.nil?
exp = [[exp, 9999999].min, 0].max # Keep exp in range
level = 1 # Assume lvl 1 start
while exp >= @exp_list[level+1] # Exp is above level?
level += 1 # Increase level by 1
end
l_divide = Yemi::ARMOR_DIVIDE # Get divide amount
l_divide = 1 if l_divide < 1 # Its no lower than 1
level = (level/l_divide).to_i # Divide level
l_max = Yemi::ARMOR_MAX # Get max level
l_max = 1 if l_max < 1 # Its no lower than 1
level = [[level, l_max].min, 0].max # Keep within range
return [level, qty, idx] # Exit: level,qty,idx
#
end
#--------------------------------------------------------------------------
# * Get Armor Proficiency found
# idx : index in actor's weapon style list
#--------------------------------------------------------------------------
def armor_proficiency_found?(idx)
#
keys = Yemi::ARMOR_STYLE.keys # Get keys to styles
keys.sort! # Ensure sorted order
for prof_id in @prof_armor # Cycle through styles
next unless idx == keys.index(prof_id) # Skip until match
prof_style = Yemi::ARMOR_STYLE[prof_id] # Get style
prof_list = prof_style[2] # Get armor list
effective = false # Set armor unfound
qty = 0 # Clear armor count
for id in 0..3 # Cycle through armors
armor_txt = "@armor" + (id+1).to_s + "_id" # Get armor string
armor_idx = eval(armor_txt) # Get evaluation
the_list = prof_list[id] # Get armor sub list
effective = true if the_list.include?(armor_idx) # flag armor found
qty += 1 if the_list.include?(armor_idx) # Increase armor count
end
next unless effective # Skip until armor
return [qty, true] # Exit with quantity
break # Break from loop
end
return [0, false] # Exit no armor found
#
end
end
Instructions
Plenty, and all in the script.
Compatibility
Fairly compatible for RPGMaker XP systems as there are no rewrites to any classes, all content using aliased methods.
Author's Notes
Modeled after my recent Weapon Proficiency script from last week, but more extensive as to deal with the multiple armor slots.
Terms and Conditions
Free for use, even in commercial games. Only due credit is required.