Reducing Effectiveness With Weapons

● ARCHIVED · READ-ONLY
Started by LanceGardner 3 posts View original ↗
  1. Hey! I'd like to make my characters weapon specialists. That is to say, everyone can use any weapon, but unless you're using your weapon of choice you have a -20% effectiveness. Is there any simple way to accomplish this? Or, failing that, a not-so-simple way? Thanks a lot,

    Lance :)
  2. I have a script I call WeaponMastery which allows you to grant class-specific boosts to a weapon.   It doesn't let you "choose" which weapon your character masters, but is based solely on the actor's class (i.e. Swordsman might specialize in Swords, etc).  I've used this script in my game so that, say, Smiths get an ATK boost when using Hammers, but Knights get an ATK boost when using Swords --- but either can use either weapon.

    Would that meet your needs?  So each weapon could have their ATK lowered and use this script to boost only the ATK for the "correct" specialized weapon.

    The script is here:

    Spoiler
    #================================================

    #

    # Script: WeaponMastery

    # by: whitesphere (whitesphere@comcast.net)

    # September ?? 2014

    #================================================

    =begin

    ================================================================================

     

    Description: Allows each Class to grow in Weapon specific skill, increasing their Attack damage as they use the Weapon more.  Also allows weapons to be more or less effective for specific Classes (i.e. Knights are better with a Sword than, say a Rogue).

     

     

    --------------------------------------------------------------------------------

    History

     

    v0.5 (2014/09/??)

      Initial release

      

      

    --------------------------------------------------------------------------------

    Terms of Use

     

    - You are free to use this script for non-commercial or commercial projects.

    - Reported bug will be fixed, but no guarantee on requested features.

    - No guarantee either for compatibility fixes.

    - Give credit to whitesphere (me), and do not delete this header.

    --------------------------------------------------------------------------------

     

    In each Class, add one or more notetags in this format:

    <mastery type="1" ATK="5" DEF="10" count="100">

    <mastery type="1" ATK="5%" DEF="5%" count="100" skill="33,40">

    Valid attributes are:

    ATK, DEF, AGI, MAT, MDF, etc.

    Values can also be negative to decrease a stat.

     

    This means "For Weapons of Type 1, add 5 to ATK score and 20% to DEF score.  Advance to next Mastery level after 100 Attacks"

    The second entry also adds Skill 33 and 40 to the Actor only when wielding this appropriate weapon and when the Actor is this particular Class, when this Mastery level is reached.

     

     

    --------------------------------------------------------------------------------

    =end

     

     

    ####################################################################

    # Module which reads XML formatted note tags and returns them as

    # HashMaps

    module Tag_reader

     

    ###################################################################

    # Represents a single XML node

    class XML_node

     

    #####################################

    # Constructor

    def initialize(name)

    @name=name

     

    # Set of name=value pairs

    @attributes={}

     

    end

     

    ###################################

    # Adds an attribute

    def add_attribute(name, value)

    @attributes[name]=value

    end

     

    ###################################

    # Returns this as an XML string

    def to_s

    result="<"+@name

    @attributes.each {

    |key, value| result += " "+key+"=\""+value+"\""

    }

    result += " />\n"

    return result

    end

     

    attr_reader :)name)

    attr_reader :)attributes)

     

    end

     

    #######################################################

    # Reads a set of XML tags

    class XML_Reader

    def initialize()

    @nodes=[]

    end

     

    ##########################################################

    # Reads the XML tags in note_string.  Does nothing if the

    # note string is empty or nil.  Returns the set of nodes read

    # from the note_string.  This may be empty

    def read(note_string)

    @nodes.clear

    if (note_string == nil)

    return @nodes

    end

    note_s=note_string.to_s.strip

    # Ignore empty strings

    string_len=note_s.length

    if (string_len == 0)

    return

    end

    index=0

    worker=""

    right_index=0

    node_name=""

     

    # Parse the XML string

    while (index < string_len)

     

    # Search for < mark

    if (note_s[index] != '<')

    index += 1

    next

    end

     

    # Find the > mark after the < mark

    right_index=note_s.index("/>",index)

    if (right_index == nil)

    right_index=note_s.index('>',index)

    if (right_index == nil)

    break

    end

    end

     

    # This is a string from < to >

    worker=note_s.slice(index, right_index-index+1)

    worker=worker.strip

     

    # Find name="value" pairs

     

    # Skip the <name part of the XML

    attr_index=worker.index(' ')

    if (attr_index == nil)

    return

    end

    node_name=worker.slice(1,attr_index).strip

     

    new_node=XML_node.new(node_name)

    while (worker.length > attr_index)

    if (worker[attr_index] == ' ')

    attr_index += 1

    next

    end

    value_index=worker.index("=\"", attr_index)

    if (value_index == nil)

    break

    end

     

    # Backspace to find the previous space or < mark - start of the

    # attribute

    attr_start_index=value_index-1

    while (worker[attr_start_index] != '<' &&

    worker[attr_start_index] != ' ')

    attr_start_index -=1

    end

    # Get to the start of the attribute name

    attr_start_index += 1

     

    # Skip the =" marker after attribute name

    second_quote=worker.index("\"", value_index+3)

    if (second_quote == nil)

    break

    end

    attr=worker.slice(attr_start_index, value_index-attr_index)

    value=worker.slice(value_index+2, second_quote-value_index-2)

    new_node.add_attribute(attr, value)

    attr_index = second_quote+1

    end

    @nodes << new_node

    index=right_index+1

    end

    return @nodes

    end

    end

    end

     

     

    #

    module WeaponMastery

     

     

    ##########################################################################

    # CONSTANTS

     

    # Defines changes to a single Attribute

    class Attribute_entry

     

    attr_reader:)attr_name)

    attr_reader:)attr_change)

    attr_reader:)attr_index)

    attr_reader:)attr_type)

     

    def initialize(attr_name, attr_change)

    attr_name=attr_name.downcase

    @attr_name=nil

    @attr_index=0

    @attr_type=nil

    if (@@name_map[attr_name] != nil)

    @attr_name=@@name_map[attr_name][0]

    @attr_index=@@name_map[attr_name][1]

    @attr_type=@@name_map[attr_name][2]

    end

    attr_change=attr_change.downcase

    @attr_is_percent=false

    if (attr_change.end_with?("%"))

    @attr_is_percent=true

    end

    @attr_change=attr_change.to_f

    end

     

    def to_s

    result=@attr_name.to_s+": "

    if (@attr_is_percent)

    result += "* "+@attr_change.to_s+"%"

    else

    result += "+ "+@attr_change.to_s

    end

    result

    end

     

    # Return true if the attribute change is a percent delta, false

    # for an absolute value to add or subtract

    def percent?

    return @attr_is_percent

    end

     

    def self.initial()

    @@name_strings=["mhp", "mmp", "atk", "def", "mat", "mdf", 

    "luk", "hit", "eva", "cri", "cev", "mev",

    "mrf", "cnt", "hrg", "mrg", "trg", "tgr", "grd",

    "rec", "pha", "mcr", "tcr", "pdr", "mdr", "fdr",

    "exr"]

    @@name_map={}

    @@attr_list=[]

    @@attr_list << [:mhp, 0, :param]

    @@attr_list << [:mmp, 1, :param]

    @@attr_list << [:atk, 2, :param]

    @@attr_list << [:def, 3, :param]

    @@attr_list << [:mat, 4, :param]

    @@attr_list << [:mdf, 5, :param]

    @@attr_list << [:luk, 6, :param]

    @@attr_list << [:hit, 7, :param]

    @@attr_list << [:eva, 0, :xparam]

    @@attr_list << [:cri, 1, :xparam]

    @@attr_list << [:cev, 2, :xparam]

    @@attr_list << [:mev, 3, :xparam]

    @@attr_list << [:mrf, 4, :xparam]

    @@attr_list << [:cnt, 5, :xparam]

    @@attr_list << [:hrg, 6, :xparam]

    @@attr_list << [:mrg, 7, :xparam]

    @@attr_list << [:trg, 8, :xparam]

    @@attr_list << [:tgr, 0, :sparam]

    @@attr_list << [:grd, 1, :sparam]

    @@attr_list << [:rec, 2, :sparam]

    @@attr_list << [:pha, 3, :sparam]

    @@attr_list << [:mcr, 4, :sparam]

    @@attr_list << [:tcr, 5, :sparam]

    @@attr_list << [:pdr, 6, :sparam]

    @@attr_list << [:mdr, 7, :sparam]

    @@attr_list << [:fdr, 8, :sparam]

    @@attr_list << [:exr, 9, :sparam]

     

    index=0

    @@name_strings.each {

    |entry| @@name_map=@@attr_list[index]

    index += 1

    }

    end

    end

     

    # Setup the hashmap

    Attribute_entry::initial

     

     

    # Represents a single level of weapon/item mastery

    class Item_level

     

    attr_reader:)item_type)

    attr_reader:)item_index)

    attr_reader:)skill_list)

    attr_reader:)attrs)

     

    # The Constructor

    def initialize(item_type, item_index, count, attr_list, skill_list)

     

    # Set to something like "mastery" ro identify what type of item is

    # affected

    item_type=item_type.downcase

     

    # This is for future use --- perhaps allow Shields to upgrade...

    @item_type=:weapon

     

    # Set to 1 to affect Weapon Type #1 in the System tab, 2 for Type #2, # etc.

    @item_index=item_index.to_i

     

    @skill_list=[]

    if (skill_list != nil)

    skill_list.each {

    |entry| @skill_list << entry.to_i

    }

    end

    @attrs=attr_list

    @key=@item_type.to_s+":"+@item_index.to_s

    end

     

    def to_s

    result="Entry: "+@item_type.to_s+", index "+@item_index.to_s+", attrs:"

    @attrs.each { |entry| result += entry.to_s+"\n"

    }

    result += "Skills: ["

    @skill_list.each { |entry| result += "+entry.to_s

    }

    result +=]"

    result

    end

     

    def key

    return @key

    end

     

    end

     

    # Contains all of the mastery levels for a particular Class

    class Item_mastery

     

    attr_reader:)level_set)

    def initialize(level_set)

    @level_set=level_set

    end

    end

     

    # The current mastery level for a particular Class/Actor/Item Type combination

    class Current_mastery

     

    attr_reader:)class_id)

    attr_reader:)actor_id)

    attr_reader:)item_type)

    attr_reader:)item_index)

    attr_reader:)use_count)

     

    def initialize(class_id, actor_id, item_type, item_index)

    @class_id=class_id.to_i

    @actor_id=@actor_id.to_i

     

    # For future use

    @item_type=:weapon

     

    @mastery_index=0

    @item_index=item_index.to_i

    @use_count=0

    @key=Current_mastery::make_key(@item_type, @item_index)

    end

     

    def self.make_key(item_type, item_index)

    result=item_type.to_s+":"+item_index.to_s

    return result

    end

     

    def key()

    @key

    end

     

    def increment()

    @use_count += 1

    end

     

    # Use when we advance to a new level of mastery

    def advance_level()

    @use_count=0

    @mastery_index = @mastery_index+1

    end

     

    def to_s

    result="Current: actor="+@actor_id.to_s+", class="+@class_id.to_s

    result +=", item type="+@item_type.to_s+", index="+@item_index.to_s

    result += ", use count="+@use_count+", level="+@mastery_index.to_s

    return result

    end

     

    # Given an item type and item index, this examines the Class-specific mastery

    # information and returns the appropriate Item_level object.  This will return

    # nil if none is applicable

    def get_mastery_data()

    defs=$data_classes[@class_id].mastery_defs()

    if (defs == nil)

    return nil

    end

    current_level=@mastery_index

    last_match=nil

    defs.each { |current| 

    if (current.item_type != @item_type || current.item_index != @item_index)

    next

    end

    last_match=current

    if (current_level == 0)

    return last_match

    end

    current_level -= 1

    }

    return last_match

    end

    end

     

    # Class which represents all of the current mastery meta-data for a given

    # Actor and Class

    class Class_mastery

     

    attr_reader:)class_id)

    attr_reader:)actor_id)

     

    def initialize(class_id, actor_id)

    @class_id=class_id.to_i

    @actor_id=actor_id.to_i

    @current_mastery={}

    end

     

    # Returns a Current_mastery object for the item type and index

    # Creates one if not found

    def get(item_type, item_index)

    key=Current_mastery::make_key(item_type, item_index)

    result=@current_mastery[key]

    if (result != nil)

    return result

    end

    result=Current_mastery.new(@class_id, @actor_id, item_type, item_index)

    @current_mastery[key]=result

    return result

    end

     

    # Callers can use this after incrementing use times

    def update(current_mastery)

    key=current_mastery.key

    @current_mastery[key]=current_mastery

    end

    end

     

     

    # This class holds ALL of the current mastery levels in a large hashmap

    class Complete_class_cache

     

    def initialize()

    @mastery={}

    end

     

    def make_key(actor_id, class_id, item_type, item_id)

    result=actor_id.to_s+"-"+class_id.to_s+"-"+item_type.to_s+"-"+item_id.to_s

    return result

    end

     

    # Returns a Current_mastery appropriate for the passed in actor ID

    # class id, item type (such as :weapon) and item_id (such as 1 for Weapon #1) 

    # Creates one if needed

    def get(actor_id, class_id, item_type, item_id)

    key=make_key(actor_id, class_id, item_type, item_id)

    current_entry=@mastery[key]

    if (current_entry != nil)

    result=current_entry.get(item_type, item_id)

    return result

    end

    current_entry=Class_mastery.new(class_id, actor_id)

    @mastery[key]=current_entry

    result=current_entry.get(item_type, item_id)

    return result

    end

     

    end

     

    # Create the singleton

    def self.init()

    @@class_cache=Complete_class_cache.new()

    end

     

    # Returns the matching Current_mastery item

    def self.get(actor_id, class_id, item_type, item_id)

    return @@class_cache.get(actor_id, class_id, item_type, item_id)

    end

    end

     

     

    # Create the static member

    WeaponMastery::init()

     

    # We update the param methods to take into account any Class specifics

    class Game_Actor < Game_Battler

     

    alias actor_setup setup

    alias actor_param param

    alias actor_xparam xparam

    alias actor_sparam sparam

     

    def setup(actor_id)

    actor_setup(actor_id)

    end

     

     

     def param(param_id)

    value=actor_param(param_id)

    # Apply class modifiers for the current weapons (dual wield)

    weapons.each { |current| weapon_id=current.wtype_id

    current_mastery=WeaponMastery::get(@actor_id, @class_id, :weapon, weapon_id)

    mastery_data=current_mastery.get_mastery_data()

    if (mastery_data == nil)

    next

    end

    # Look for a matching attribute

    mastery_data.attrs.each { |attr|

    if (attr.attr_type != :param || attr.attr_index != param_id)

    next

    end

    # Adjust the value

    if (attr.percent?)

    value = (value * attr.attr_change) / 100

    else

    value += attr.attr_change

    end

    }

    }

    [[value, param_max(param_id)].min, param_min(param_id)].max.to_i

     end

     

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

     # * Get Ex-Parameter

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

     def xparam(xparam_id)

    value=actor_xparam(xparam_id)

    # Apply class modifiers for the current weapons (dual wield)

    weapons.each { |current| weapon_id=current.wtype_id

    current_mastery=WeaponMastery::get(@actor_id, @class_id, :weapon, weapon_id)

    mastery_data=current_mastery.get_mastery_data()

    if (mastery_data == nil)

    next

    end

    # Look for a matching attribute

    mastery_data.attrs.each { |attr|

    if (attr.attr_type != :xparam || attr.attr_index != param_id)

    next

    end

    # Adjust the value

    if (attr.percent?)

    value = (value * attr.attr_change) / 100

    else

    value += attr.attr_change

    end

    }

    }

    value

     end

     

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

     # * Get Sp-Parameter

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

     def sparam(sparam_id)

    value=actor_sparam(sparam_id)

    # Apply class modifiers for the current weapons (dual wield)

    weapons.each { |current| weapon_id=current.wtype_id

    current_mastery=WeaponMastery::get(@actor_id, @class_id, :weapon, weapon_id)

    mastery_data=current_mastery.get_mastery_data()

    if (mastery_data == nil)

    next

    end

    # Look for a matching attribute

    mastery_data.attrs.each { |attr|

    if (attr.attr_type != :sparam || attr.attr_index != param_id)

    next

    end

    # Adjust the value

    if (attr.percent?)

    value = (value * attr.attr_change) / 100

    else

    value += attr.attr_change

    end

    }

    }

    value

     end

    end

     

     

     

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

    # Read the mastery definitions

    class RPG::Class

     

    def read_note_tag_as_nodes

    if (@node_set == nil)

    reader=Tag_reader::XML_Reader.new

    @node_set=reader.read(@note)

    end

    return @node_set

    end

     

    # Returns the current set of mastery definitions 

    def mastery_defs

    if (@mastery_defs != nil)

    if (@mastery_defs.empty?)

    return nil

    end

    return @mastery_defs

    end

    @mastery_defs=[]

    nodes=read_note_tag_as_nodes

    if (nodes == nil)

    return nil

    end

     

    # This is to simplify the search

    @attr_types=["mhp", "mmp", "atk", "def", "mat", "mdf",

    "luk", "hit", "eva", "cri",

    "cev", "mev", "mrf", "cnt", "hrg", "mrg",

    "trg",  "tgr", "grd", "rec", "pha", "mcr",

    "tcr", "pdr", "mdr", "fdr", "exr"]

    nodes.each {

    |current| 

    if (current.name != "mastery")

    next

    end

    # A "type" tag is required

    weapon_type=current.attributes["type"]

    if (weapon_type == nil)

    next

    end

     

    # Look for "count" or "skills" tags.  Both are

    # optional

    current_skills=current.attributes["skills"]

    if (current_skills != nil)

    current_skills=current_skills.split(",")

    end

    current_count=current.attributes["count"]

     

    # Assemble a list of attribute modifications

    attr_mods=[]

    current.attributes.each {

    |key, value| key=key.downcase

    if (@attr_types.include?(key))

    new_mod=WeaponMastery::Attribute_entry.new(key, value)

    attr_mods << new_mod

    end

    }

     

    # If attr_mods is not empty, add it

    if (attr_mods.empty?)

    next

    end

    new_level=WeaponMastery::Item_level.new(":weapon", weapon_type, current_count, attr_mods, current_skills)

    @mastery_defs << new_level

    }

    return @mastery_defs

    end

     

    end

     
  3. Looks great, thanks.