RMRK RPG Maker Creation => VX Ace => VXA Scripts Database => Topic started by: modern algebra on December 26, 2012, 07:13:14 PM
Title: [VXA] Item Instances Base
Post by: modern algebra on December 26, 2012, 07:13:14 PM
Item Instances Base Version:1.0.0 Author:modern algebra Date:26 December 2012
Version History
<Version 1.0> 2012.12.26 - Original Release
Description
This script changes the item system in RMVX Ace to accomodate for items of the same ID to have different stats. It can thereby serve as a base for scripts that require such functionality, such as durability for weapons and armors, charges for items, weapons that level up, socketing, etc...
This script does none of that by default - it only sets up data structures to permit that, and its only independent use is that you can manually change the stats on an item added to the party through events.
Features
Allows for items of the same ID to be saved as instances.
A useful base for other scripts which require that functionality, such as durability scripts, socketing, enchanting items, levelling weapons, etc.
Instructions
Insert this script into its own slot in the Script Editor, above Main but below Materials. This script must also be above every script that requires it.
#============================================================================== # Instance Items Base [VXA] # Version: 1.0.0 # Author: modern algebra (rmrk.net) # Date: 26 December 2012 #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Description: # # This script changes the item system in RMVX Ace to accomodate for items # of the same ID to have different stats. It can thereby serve as a base for # scripts that require such functionality, such as durability for weapons and # armors, charges for items, weapons that level up, socketing, etc... # # This script does none of that by default - it only sets up data structures # to permit that, and its only independent use is that you can manually # change the stats on an item added to the party through events. #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Instructions: # # Insert this script into its own slot in the Script Editor, above Main but # below Materials. This script must also be above every script that requires # it. #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Instructions for Scripters: # # If you are a scripter and want to write a script that requires this script # in order to be used, you have my permission. I ask only that you link back # to this script at RMRK, as well as provide me with a link to your script so # that I can ensure compatibility. # # I have tried to comment the script where there might be some confusion, # so you should be able to read through it to gain an understanding as to # how it works. For the most part, it is designed to mimic as much as # possible the default arrangement. So, if you access the first 999 indices # of $data_items, $data_weapons, or $data_armors, you will receive the basic # classes for those. New instances begin at ID 1000, and each new instance # will have a unique ID, which is what is returned when you call the #id # method. Instances will also have a #database_id method which returns the # ID of its base item. Instance items are now of the Game_IItem, Game_IWeapon, # or Game_IArmor. Game_IItem inherits its methods from the module # Game_IUsableItem, and the others inherit from the module Game_IEquipItem. # Both Game_IEquipItem and Game_IUsableItem inherit from Game_IBaseItem. # # If you need to add a new notefield tag, it is recommended you also add it # to MA_INSTANCE_ITEMS_BASE[:regexp_array], as any regular expressions # included in that array will make the #instance_based? method in # RPG::BaseItem return true if the item has that in its note field. # # Beyond that, I recommend you read the entire script in order to gain an # understanding of how it works. #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Support: # # If you have any questions, feel free to ask them in the script's topic: # # http://rmrk.net/index.php/topic,47427.0.html # # I will try to answer as swiftly as possible. If you believe further # documentation is required, please let me know. #==============================================================================
MA_INSTANCE_ITEMS_BASE = { # This sets the first index used for instance items. It should be 1000 # unless you are using another script which makes extends the database # limitations beyond 999. :index_start => 1000, # This array tracks the note field codes which identify that an item should # be created as new instances. :regexp_array => [/\\INS/i], # This array holds methods which you would never want to distinguish between # instances :ignore_accessors => [], }
#============================================================================== # ** MAIIB_RPG_BaseItem #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # This mixes in to RPG::Item, RPG::Weapon, and RPG::Armor, adding the # following methods: # overwritten method - == # new methods - instance_based?; database_id #==============================================================================
module MAIIB_RPG_BaseItem #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Instance Based? # This is true if the item is identified as instance-based. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def instance_based? @ins_based = MA_INSTANCE_ITEMS_BASE[:regexp_array].any? { |regexp| !self.note[regexp].nil? } unless @ins_based @ins_based end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Data ID # Essentially just aliases #id, but in case any other script overwrites # or aliases #id, I made it so it just calls it #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def database_id(*args, &block) id(*args, &block) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Equality? # Also returns true if other is an instance item with same data. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def ==(other) super(other) || (other.is_a?(Game_BaseInstanceItem) && super(other.data)) end end
# MAIIB_RPG_UsableItem and MAIIB_RPG_EquipItem both inherit MAIIB_RPG_BaseItem module MAIIB_RPG_UsableItem; include MAIIB_RPG_BaseItem; end module MAIIB_RPG_EquipItem; include MAIIB_RPG_BaseItem; end
module RPG class Item; include MAIIB_RPG_UsableItem; end class Weapon; include MAIIB_RPG_EquipItem; end class Armor; include MAIIB_RPG_EquipItem; end end
#============================================================================== # *** DataManager #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # These modifications preserve the #`````````````````````````````````````````````````````````````````````````````` # Summary of Changes: # aliased methods - init; extract_save_contents; create_game_objects # new method - maiib_preserve_old_saves; set_data_to_instance_items #==============================================================================
class << DataManager #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Initialize #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_inz_2tg6 init def init(*args, &block) Game_BaseInstanceItem.init_auto_accessors # Initialize automatic maiib_inz_2tg6(*args, &block) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Extract Save Contents #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_extractsave_2jw6 extract_save_contents def extract_save_contents(contents, *args, &block) maiib_extractsave_2jw6(contents, *args, &block) # Call Original Methods maiib_preserve_old_saves end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Create Game Objects #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_creatgameobj_4hi8 create_game_objects def create_game_objects(*args, &block) maiib_creatgameobj_4hi8(*args, &block) # Call Original Method set_data_to_instance_items end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Preserve Save Contents #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def maiib_preserve_old_saves $game_system.init_maiib_data unless $game_system.instance_items set_data_to_instance_items end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Set Data Instance Items #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def set_data_to_instance_items $game_system.instance_items[:item].reset_data_array($data_items) $game_system.instance_items[:weapon].reset_data_array($data_weapons) $game_system.instance_items[:armor].reset_data_array($data_armors) $data_items = $game_system.instance_items[:item] $data_weapons = $game_system.instance_items[:weapon] $data_armors = $game_system.instance_items[:armor] end end
#============================================================================== # ** Game_BaseInstanceItem #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # This class holds an instance of an Item, Weapon, or Armor #==============================================================================
module Game_BaseInstanceItem #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Public Instance Variables #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attr_writer :id attr_accessor :data_type attr_accessor :database_id #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Object Initialization #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def initialize(id, data_type, database_id) @id = id @data_type = data_type @database_id = database_id self.class.auto_accessors.each { |method| instance_variable_set(:"@#{method}", Marshal.load(Marshal.dump(data.send(method)))) } end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Get ID #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def id ($game_system && $game_system.retrieve_database_id) ? database_id : @id end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Data #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def data case data_type when :item then $data_items[database_id] when :weapon then $data_weapons[database_id] when :armor then $data_armors[database_id] end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Method Missing #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def method_missing(method, *args, &block) if method.to_s[/^(.*?[^=])=$/] && !MA_INSTANCE_ITEMS_BASE[:ignore_accessors].include?(method) instance_exec($1.to_sym) { |new_meth| eval("def #{new_meth}=(val); @#{new_meth} = val; end; def #{new_meth}; @#{new_meth}; end") } send(method, *args, &block) else data ? data.send(method, *args, &block) : super(method, *args, &block) end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Equality? #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def ==(other); super(other) || (data && data == other); end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Is A? #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def is_a?(*args, &block) super(*args, &block) || (data && data.is_a?(*args, &block)) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Initialize All Automatic Accessors #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def self.init_auto_accessors # For all descendants ObjectSpace.each_object(Class) { |klass| klass.class_eval { klass.auto_accessors.each { |method| attr_accessor(method) } } if klass < self } end end
module Game_IUsableItem; include Game_BaseInstanceItem; end module Game_IEquipItem; include Game_BaseInstanceItem; end
class Game_IItem include Game_IUsableItem def initialize(*args); super(*args); end def self.auto_accessors; [:effects]; end end class Game_IWeapon include Game_IEquipItem def initialize(*args); super(*args); end def self.auto_accessors; [:params, :features]; end end class Game_IArmor include Game_IEquipItem def initialize(*args); super(*args); end def self.auto_accessors; [:params, :features]; end end
#============================================================================== # ** Game_InstanceItems #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # This is a special subclass of an array which holds instance items in a # separate hashes. It replaces the $data_ classe for items, weapons, and armors #==============================================================================
class Game_InstanceItems < Array #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Public Instance Variables #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attr_accessor :instance_items #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Object Initialization #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def initialize(type, data_array = []) @instance_items = {} @type = type @index_start = MA_INSTANCE_ITEMS_BASE[:index_start] @last_index = @index_start @free_indices = [] reset_data_array(data_array) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Type Class #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def type_class case @type when :item then Game_IItem when :weapon then Game_IWeapon when :armor then Game_IArmor end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Reset Data Array #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def reset_data_array(data_array) clear for item in data_array do self << item end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Create Instance #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def create_instance(base_item) base_item = self[base_item] if base_item.is_a?(Integer) return base_item if base_item.is_a?(Game_BaseInstanceItem) || !base_item.instance_based? # Get next free index if @free_indices.empty? index = @last_index @last_index += 1 else index = @free_indices.shift end @instance_items[index] = type_class.new(index, @type, base_item.id) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Destroy Instance #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def destroy_instance(index) @free_indices.push(index) @instance_items.delete(index) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Retrieve Value from key #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def [](key) return key < @index_start ? super(key) : @instance_items[key] end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Set Value to Key #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def []=(key, value) key < @index_start ? super(key, value) : @instance_items[key] = value end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Items with ID # This will return an array of all items with the specified ID #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def items_with_id(item_id) return [self[item_id]] unless self[item_id].instance_based? return @instance_items.values.select { |ins| ins.item_id == item_id } end end
#============================================================================== # ** Game_System #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Summary of Changes: # new attr_reader - instance_items # new attr_accessor - retrieve_database_id # aliased method - initialize # new method - init_maiib_data #==============================================================================
class Game_System #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Public Instance Variables #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attr_reader :instance_items attr_accessor :retrieve_database_id #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Object Initialization #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_intz_2sh7 initialize def initialize(*args, &block) maiib_intz_2sh7(*args, &block) # Call Original Method init_maiib_data end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Initialize Instance Items Base Data #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def init_maiib_data @instance_items = { item: Game_InstanceItems.new(:item), weapon: Game_InstanceItems.new(:weapon), armor: Game_InstanceItems.new(:armor) } @retrieve_database_id = false end end
class Game_Party #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Public Instance Variables #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ attr_reader :newest_instance_items #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Object Initialization #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_nitialz_4ld5 initialize def initialize(*args, &block) @newest_instance_items = [] maiib_nitialz_4ld5(*args, &block) # Call Original Method end [:items, :weapons, :armors].each { |method| #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Items/Weapons/Armors #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias_method(:"maiib_#{method}_3js6", method) define_method(method) do |*args| result = send(:"maiib_#{method}_3js6", *args) # Call Original Method # Delete the database items if they are instance items deletables = [] for i in 0...result.size item = result[i] next if item.nil? break if item.is_a?(Game_BaseInstanceItem) deletables << i if item.instance_based? end deletables.reverse.each { |i| result.delete_at(i) } # Sort by Database ID, then ID. result.sort {|a, b| (a.database_id <=> b.database_id).nonzero? || a.id <=> b.id } end } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Held Instances Of # item : the Item to check #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def held_instances_of(item) maiib_items_of_type(item).select { |item2| item2.database_id == item.database_id } end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Item Container #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_itmcontain_7hq9 item_container def item_container(item_class, *args, &block) return @items if item_class == Game_IItem return @weapons if item_class == Game_IWeapon return @armors if item_class == Game_IArmor maiib_itmcontain_7hq9(item_class, *args, &block) # Call Original Method end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Items of Type #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def maiib_items_of_type(item) case instance_item_type(item) when :item then items when :weapon then weapons when :armor then armors else [] end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Instance Type #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def instance_item_type(item) case item when RPG::Item, Game_IItem then :item when RPG::Weapon, Game_IWeapon then :weapon when RPG::Armor, Game_IArmor then :armor end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Gain Item #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_gainitm_3ky7 gain_item def gain_item(item, amount, include_equip = false, *args, &block) return if amount == 0 if item.is_a?(MAIIB_RPG_BaseItem) && item.instance_based? count = item_number(item) amount = [[amount, max_item_number(item) - count].min, 0].max if amount > 0 gain_instance_item(item, amount, include_equip) # Add the new items to the container @newest_instance_items.each { |ins| maiib_gainitm_3ky7(ins, amount <=> 0, include_equip) } # Prepare for database count item = item.data if item.is_a?(Game_BaseInstanceItem) end # Call Original Method and modify the count for database items maiib_gainitm_3ky7(item, amount, include_equip, *args, &block) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Gain Instance Item #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def gain_instance_item(item, amount, include_equip = false) @newest_instance_items.clear if item.is_a?(Game_BaseInstanceItem) if amount > 0 || (item_number(item) > 0 && amount < 0) # Add the item @newest_instance_items << item amount -= amount <=> 0 end # If amount was not 1 or -1, apply method to the database item item = item.data end return unless item if amount > 0 # Create new instances add_instance_items(item, amount) elsif amount < 0 # Find and remove instances of the same database item subtract_instance_items(item, -amount, include_equip) end end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Lose Instance Item #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def lose_instance_item (item, amount, include_equip = false) gain_instance_item(item, -amount, include_equip) end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Add Instance Item #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def add_instance_items(item, amount) data_array = $game_system.instance_items[instance_item_type(item)] amount.times { @newest_instance_items << data_array.create_instance(item) } end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Subtract Instance Item #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def subtract_instance_items(item, amount, include_equip = false) data_array = $game_system.instance_items[instance_item_type(item)] for ins in held_instances_of(item) break if amount == 0 @newest_instance_items << ins amount -= 1 end # Rely on discard_members_equip to dispose of equipped items end #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # * Discard Members Equip #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ alias maiib_discardequip_3hx7 discard_members_equip def discard_members_equip(item, amount, *args, &block) if item.is_a?(MAIIB_RPG_BaseItem) && item.instance_based? && !item.is_a?(Game_BaseInstanceItem) n = amount members.each { |actor| while n > 0 ins = actor.equips.find { |equip| equip.database_id == item.database_id } break unless ins @newest_instance_items << ins actor.discard_equip(ins) n -= 1 end } else # Call Original Method maiib_discardequip_3hx7(item, amount, *args, &block) end end end
Credit
modern algebra
Support
Please post in this topic at RMRK.net if you have any questions, suggestions, error reports, or comments about this script. Please do not message me privately, as it is more efficient and useful to answer any concerns you have in the topic where others may benefit from our correspondence. Additionally, others might be able to provide you with quicker answers to your questions, as I am occasionally unavailable due to work.
Known Compatibility Issues
This script will likely not work with any other script which purports to do the same thing.
Spoiler for Yanfly's Ace Equip Engine:
There is a small bug in Yanfly's Ace Equip Engine (http://yanflychannel.wordpress.com/rmvxa/gameplay-scripts/ace-equip-engine/). Although it works functionally, when scrolling through instances of the same item, differences in stats will not be shown unless it is the first one you select after looking at some other item. ekomega (http://rmrk.net/index.php/topic,47428.msg539086.html#msg539086) investigated the problem and determined that all you need to do to fix this error is to find line 1098 in Yanfly's script, which should look like this:
As far as I know, that should not cause any problems re: lag, since I don't believe that method is called except when the help window is likely to require updating. However, if deleting the line altogether makes you nervous, then you can replace it with:
Many thanks to ekomega for discovering and fixing this incompatibility.
Demo
This script does nothing on its own, so a demo would have no purpose.
Author's Notes
I actually finished this a few months ago, but then did not do anything with it as I planned to write a few sample scripts before releasing it. I never did that, so I let it stagnate for a while. Unfortunately, this means I am not entirely certain that it was actually finished, but I think it is. Please let me know if anything is missing.
Terms of Use
I adopt RMRK's default Terms of Use (http://rmrk.net/index.php/topic,45481.0.html).
Title: Re: [VXA] Item Instances Base
Post by: D&P3 on December 27, 2012, 09:33:46 AM
So this script is more of a scripters utility rather than something for the regular user? I don't see myself making any sort of script that would require such a base but nevertheless should the day arrive, I'm sure I'll put it to good use ^-^ Thanks for the base script Modern.
Title: Re: [VXA] Item Instances Base
Post by: modern algebra on December 27, 2012, 03:10:55 PM
Yeah, basically. It is mostly for my own purposes, since I intend to write a few of those scripts sometime in the unspecified future, but I figured it might be valuable to others as well.
Title: Re: [VXA] Item Instances Base
Post by: p3king on February 26, 2013, 08:53:23 PM
Hi modern algebra!
I really like this script! I´m currently using it together with your Equipment Stat Variance script and it works great.
What I still need for my project however is equip durability so I am currently trying to create this myself with your base. Well actually I think I already did kind of.
I did not yet implement any hud stuff or events to alter the durability though, because it would be nice to know if I am on the right way with this. Would you be so kind and fly over my code?
As I´m still very new to both the Maker and Ruby it would also be really cool if you (and of course everyone else here) could point out which parts I could do better as I´m always interested in using best practice if possible :)
# --------------------------------------------------------------- # Instanced Equip Durability script by p3king # -> Using InstanceItemBase script by modern algebra (rmrk.net) # ---------------------------------------------------------------
if $imported && $imported[:"MA_InstanceItemsBase 1.0.0"]
# The default maximum durability an item has when spawned. # Set this in the armor or weapon notebox to customize: # # \dur_max[200] # Sets max. durability of this item to 200 # # The value below is taken when you put nothing in the notebox. P3_IED_DEFAULT_MAX_DURABILITY = 100
# The default current durability an item has when spawned. # Set this in the armor or weapon notebox to customize: # # \dur_cur[150] # Sets current dur. for this item to 150 (without variance) # # The value below is taken when you put nothing in the notebox. P3_IED_DEFAULT_CUR_DURABILITY = 100
# The default variance in percent that will be applied to the # current durability. This value will be subtracted. # Set this in the armor or weapon notebox to customize: # # \dur_var[50] # Sets durability variance to 50%. This means the item's # current durability will be decreased by up to 50% (random). # # The value below is taken when you put nothing in the notebox. # Note that currently, when nothing is set in the notebox the # item won´t get instanced and will not use durability. P3_IED_DEFAULT_VAR_DURABILITY = 30
# prevent values going over min / max def anti_manaburn @durability = @durability_max if @durability > @durability_max @durability = 0 if @durability < 0 end
end
else # sentence and structure stolen from modern algebra msgbox("Item Durability could not be installed because you either do not have Instance Items Base or because you have that script placed below the Item Durability script.") end
Title: Re: [VXA] Item Instances Base
Post by: Fall From Eden on February 26, 2013, 11:04:47 PM
Well, I'm not Modern Algebra, but I can help you a little bit with the code that you have. :)
Firstly, you really don't need the get_* methods. Instead of defining a method named "get_durability", all you need is an attr_reader for the @durability instance variable. As it is, you have readers for methods, which isn't what you want to do. Readers and accessors make use of instance variables, not methods -- so defining the "get_durability" method and then creating a reader for "get_durability" is redundant and your hand-written "get_durability" method overrides the method generated for the (non-existent) @get_durability instance variable that your attr_reader created.
I'd also change the logic for your "is_broken?" method a little bit. Right now, you're checking if durability is in use for the item (good), and if its durability is equal to zero (not so good) -- so what if the durability is less than zero? Suddenly, it's not broken, which would be a bug, I think. :) Also, I don't see a "use_durability?" method anywhere, so I'm assuming you meant to reference the "is_durability_enabled?" method, which is really just checking if the @durability_enabled instance variable has a truth-y value. Why not check @durability_enabled directly?
In your "apply_variable_durability", you create a local variable named "rand" with a seeded random number, which is also kind of redundant: the Kernel#rand method already does this.
Here's a modified version so that you can hopefully see what I'm talking about with all of this:
# Note: I'd use symbols as keys here, not strings. P3_IED_REGEXP = { :cur => /\\DUR_CUR\[(\d+)\]/i, :max => /\\DUR_MAX\[(\d+)\]/i, :var => /\\DUR_VAR\[(\d+)\]/i }
P3_IED_REGEXP.each_value do |regexp| MA_INSTANCE_ITEMS_BASE[:regexp_array].push(regexp) end
module Game_IEquipItem alias :zsiid_initialize :initialize attr_reader :durability, :max_durability, :durability_enabled
def initialize(*args) zsiid_initialize(*args) # Note: technically, you could leave this out here, actually. If the # variable is not instantiated, it evaluates to nil, which would work # fine for conditionals. @durability_enabled = false # Note: I removed your checks for nil here because both nil and false are # automatically evaluated to false; no need to explicitly check for it. @durability = self.note[P3_IED_REGEXP[:cur]] ? $1.to_i : -1 @durability_max = self.note[P3_IED_REGEXP[:max]] ? $1.to_i : -1 dur_var_perc = self.note[P3_IED_REGEXP[:var]] ? $1.to_i : -1
if @durability > -1 or @durability_max > -1 or dur_var_perc > -1 @durability_enabled = true set_default_durability apply_variable_durability end end
def is_broken? @durability_enabled and @durability <= 0 end
def change_durability(amount) return unless @durability_enabled # Note: this is shorthand for what you were doing before. @durability += amount anti_manaburn end
def set_default_durability @durability_max = P3_IED_DEFAULT_MAX_DURABILITY if @durability_max == -1 @durability = @durability_max if @durability == -1 end
def apply_variable_durability var_perc = self.note[P3_IED_REGEXP[:var]] ? $1.to_i : P3_IED_DEFAULT_VAR_DURABILITY if var_perc != 0 # Note: no need to add .to_f to rand in my opinion. random_val = 1.0 - (rand(var_perc) / 100.0) @durability = (@durability * random_val).to_i anti_manaburn end end
# Note: I'd rename this method to something like "clamp_durability", # personally... describe what it does better. def anti_manaburn @durability = @durability_max if @durability > @durability_max @durability = 0 if @durability < 0 end end else msgbox("Item Durability could not be installed because you either do not have Instance Items Base or because you have that script placed below the Item Durability script.") end
Also, be aware of the fact that I wrote these changes really quickly and haven't tested them, so if something doesn't work, just assume that I put a problem in there intentionally to help you learn! :D
Title: Re: [VXA] Item Instances Base
Post by: p3king on February 26, 2013, 11:49:45 PM
Wow thanks alot for your effort, that helps alot.
I read about the accessors earlier and I already tried them but I probably did something wrong. Also, coming from php I´m kind of used to define my getters and setters, I need to stop that :)
I let is_broken? only check for zero because in theory it should never be able to get below.. but you´re right that it´s better checking again. use_durability was the name of durability_enabled before i renamed it.. but not the accessor.
That local rand var you found was a line I forgot to remove. I didn´t know of rand() and google first led me to Random.new.
Regarding the anti_manaburn method, I just couldn´t think of a fitting name in that moment and that was the first thing coming to my mind :D
I´ll update and test my script later tomorrow, now it´s time for me to sleep ;)
Title: Re: [VXA] Item Instances Base
Post by: Fall From Eden on February 27, 2013, 01:07:16 AM
Well, it looks like you were trying to use accessors as public / private declarations, which isn't what they are. For now, think of them as syntactic sugar for writing your own getter and setter methods (interesting tidbit, though: they're actually faster when executed than methods are).
And yes, I noticed that in theory, the durability should never get below zero -- but don't always rely on your design that way. It's safer to be sane than to rely on things going as planned. ;)