じ☆ve冰风 发表于 2026-7-26 12:15:03

Add Note Support for XP Database

This sole-created script adds no game-performing features, only to add a "Note" field support for XP database, which is a later-generation feature starting from RGSS2.
The Note support will open a new horizon for game scripting, save numerous efforts on tampering with massive configurations before a customized script, and make it simpler and neater to create your own functions.

Special: The WILD MODE (default on) support allows you to override database values, so you can have weapons attack > 1000, attack < 0, or skills with atk_f, dex_f... over 200, or create potions that recovers 999999 HP.

For more help, just read the text before the script.

                Ruby:       
#==============================================================================
# ■ General Note Field for XP by SailCat
#------------------------------------------------------------------------------
#   Introduction:
#      This script "adds" a general Note field support for RPG Maker XP
#   database, which is a later-generation feature starting from VX.
#      The Note field is parsed automatically as Ruby Hash objects for easier
#   use in scripting.
#
#   Installation Guide:
#      Insert this script before the "Main" section, preferably right after
#   Scene_Debug, or before as many custom scripts as possible.
#
#   Date of release:
#      Sep. 1, 2024
#
#   Effects:
#   1. Splits "Name" (Actors, Classes, Enemies, States, Animations, Tileset)
#      field as a place where you write notes. (max = 40 chars)
#   2. Splits "Description" (Items, Skills, Weapons, Armors) field as a place
#      where you write notes. (max = 100 chars)
#   3. Splits "Name" of Events and Maps as a place for notes. (max = 100 chars)
#   4. In case you need longer notes, use labels to link to a storage common
#      event, or a file.
#   5. For event pages. Write notes in the "comment" command consecutively in
#      the beginning of the command list w/o limitations.
#      This applys to map event pages, troop event pages, and common events.
#
#   How to use:
#
#   1. Default Notes:
#      1) Use "#" char (default as configurated) to split the regular name or
#         description with your notes. (as if writing comments for ruby)
#         Ex: an item with a description "Recovers HP." and note "concoct=12"
#            is written as "Recovers HP.#concoct=12"
#      2) Use ";" char (default as configurated) to split note sections.
#         Ex: a note split as "concoct=12" and "wearout=60" is written as
#            "#concoct=12;wearout=60"
#
#   2. Extra Notes, choose either:
#      1) Use "#>" + label name to refer to a label in the common event.
#      2) Use "#<" + label name to refer to a label in a INI file.
#
#   3. Note Value-Pairs:
#      Write as standard: key=value, such as "concoct=12"
#      the key must be a valid ruby identifier
#      the value must be a valid ruby expression
#      or simplify as:
#      key or key+       for   key=true
#      key-            for   key=false
#      key:string      for   key="string"
#      key.label         for   key=(refer to a label section in common event)
#      key=v          for   key=$game_variables
#      Why simplify? You have 40 or 100 chars only for a standard note.
#      In case a semi-colon ";" char is used in value, use "\;" to escape.
#
#   4. Using Notes in your own script:
#      In RGSS, use object._key(default_value) to get the value.
#      Ex: Your character 1 is NAMED as "Alexus#a;b=4;c=5"
#          $data_actors.name       # => "Alexus"
#          $data_actors._a         # => true
#          $data_actors._b         # => 4
#          $data_actors._c         # => 5
#          $data_actors._d         # => nil --unused key returns nil
#          $data_actors._d(2)      # => 2   --unused key returns default
#      Ex: Your skill 1 is DESCRIBED as
#            "Recovers HP for an ally.#f:a.atk - b.def / 2;cd=1.5;no_ref-"
#          $data_skills._f         # => "a.atk - b.def / 2"
#          $data_skills._cd      # => 1.5
#          $data_skills._no_ref    # => false
#      Mind that setting a note for one entry will not add it to other entries
#          $data_skills._f         # => nil
#      unless you set note f=xx or f:xx for it as well.
#
#   5. For neater scripting and to save the trouble of setting a note for
#      every entry, we strongly recommend to encapsulate the note fields in
#      your own script, and assign default values. For example:
#
#      module RPG
#      class Actor
#          def gender;          _a(false);    end
#          def age;             _b(0);      end
#          def skill_per_level; _c(1);      end
#          def perk_count;      _d(2);      end
#      end
#      class Skill
#          def formula;         _f("");       end
#          def cooldown;      _cd(1.0);   end
#          def reflectable;   !_no_ref;   end
#      end
#      end
#
#      Then you can use:
#          $data_actors.gender             # => true
#          $data_actors.age                # => 4
#          $data_actors.skill_per_level    # => 5
#          $data_actors.perk_count         # => 2
#          $data_skills.formula            # => "a.atk - b.def / 2"
#          $data_skills.cooldown         # => 1.5
#          $data_skills.reflectable      # => true
#          $data_skills.formula            # => ""
#          $data_skills.cooldown         # => 1.0
#          $data_skills.reflectable      # => true
#      For any entry with or without notes.
#
#   6. WILD MODE: you can use note to override database default values.
#      When WILD MODE is activated (by default), you can override default
#      values by writing a note whose key corresponds to an existing field.
#      Ex: Your Weapon 1 is DESCRIBED as "An sword made of iron.#atk=1016"
#          $data_skills.atk                # => 1016
#      This is useful when you need a value that is beyond database limits.
#      (Only number fields is allowed in this case)
#
#   7. This script offers an easy interface for Note only, and without any
#      functions or features that deal with the notes. We leave them to your
#      own innovations and imaginations.
#
#   8. Writing Extra Notes in common events.
#      1) Always use an EEP command before the common event you referred to.
#      2) Use a unique Label command to mark a label section for reference.
#      3) Use "Show Text", "Comment" "Script" or "Conditional Branch: Script"
#         to write the note text.
#         * Conditional Branch: Script allows 10000 characters maximum, which
#         will more than suffice.
#      4) Refer to this label as either #key.label or #>label
#      Ex: Common Event 1
#          - End Event Processing
#          - Label: Alexus_pro
#          - Comment: A warrior that excels at swordfighting, born in
#                     190 here.
#          - Label: Alexus
#          - Comment: age=16; sex:M; profile.Alexus_pro
#          - Label: Basil
#          - ......
#          Actor 1 Name: Alexus #>Alexus
#          $data_actors._age               # => 16
#          $data_actors._profile         # =>
#               "A warrior that excels at swordfighting, born in\n190 here."
#      You can simply write "#>" without a label name, when the label name is
#      the entry name itself.
#
#   9. Writing Extra Notes in INI files.
#      1) Follow the standard INI file format:
#       Ex:
#         profile=Dorothy, a thief
#         age=28
#         gender=F
#         height=175
#         weight=60
#         is_dual_wield=false
#      2) Refer to this label using "#<"
#       Ex: Actor 4 Name: Dorothy #<
#         $data_actors._profile          # => "Dorothy, a thief"
#         $data_actors._age            # => 28
#==============================================================================
#==============================================================================
# ■ SailCat's XP Plugins
#==============================================================================
module SailCat
#--------------------------------------------------------------------------
# ● Configurations
#--------------------------------------------------------------------------
module DataNoteCore_Config
    SEPARATOR = "#"               # Separator before Note
    DELIMITER = ";"               # Separator between note sections (K/V pairs)
    NOTE_LABEL_CHAR = ?>          # Marker for extra long notes in common event
    NOTE_FILE_CHAR = ?<         # Marker for extra long notes in INI file
    NOTE_FILE = "Data/Note.ini"   # File name for the INI file
    ACTOR_COMMON_EVENT_ID = 1   # Common event ID for Notes for Actors
    CLASS_COMMON_EVENT_ID = 2   # Common event ID for Notes for Classes
    SKILL_COMMON_EVENT_ID = 3   # Common event ID for Notes for Skills
    ITEM_COMMON_EVENT_ID = 4      # Common event ID for Notes for Items
    WEAPON_COMMON_EVENT_ID = 5    # Common event ID for Notes for Weapons
    ARMOR_COMMON_EVENT_ID = 6   # Common event ID for Notes for Armors
    ENEMY_COMMON_EVENT_ID = 7   # Common event ID for Notes for Enemies
    STATE_COMMON_EVENT_ID = 8   # Common event ID for Notes for States
    ANIMATION_COMMON_EVENT_ID = 9 # Common event ID for Notes for Animations
    TILESET_COMMON_EVENT_ID = 10# Common event ID for Notes for Tilesets
    MAPINFO_COMMON_EVENT_ID = 11# Common event ID for Notes for Maps
    EVENT_COMMON_EVENT_ID = 12    # Common event ID for Notes for Events
    NOTE_STRING_LF = "\n"         # Line feed char for extra long signle note
    NOTE_DATA_LF = DELIMITER      # Line feed char for extra long note data
    USE_WILD_MODE = true          # Allow WILD MODE to override values
    #--------------------------------------------------------------------------
    # ● Don't change this part
    #--------------------------------------------------------------------------
    raise "Separator before and between Notes must be different" if
      SEPARATOR == DELIMITER
    raise "Extra long note markers must tell common event and file apart" if
      NOTE_LABEL_CHAR == NOTE_FILE_CHAR
end
end

#==============================================================================
# ■ DataNoteCore
#------------------------------------------------------------------------------
#   Core Engine for Note Field Support.
#==============================================================================
module DataNoteCore
include SailCat::DataNoteCore_Config
#--------------------------------------------------------------------------
# ● Constants
#--------------------------------------------------------------------------
SEP_REGEX = /#{SEPARATOR}.+$/# Don't change this
#--------------------------------------------------------------------------
# ● Cache for flat arrays
#--------------------------------------------------------------------------
$flat_array_cache = {}
#--------------------------------------------------------------------------
# ● Retrive note values
#--------------------------------------------------------------------------
def note
    # If not initialized
    if @note.nil?
      # For common events, use command list
      @note = split(get_command_note(list)) if self.is_a?(RPG::CommonEvent)
      # For map events, use command list
      @note = split(get_command_note(list)) if self.is_a?(Game_Event)
      # For troop, use command list in first page
      @note = split(get_command_note(pages.list)) if self.is_a?(RPG::Troop)
      # For others, use description, in case of no description, use name
      @note ||= has_description? ? split(@description) : split(@name)
      # Analyze
      analyze
    end
    # Retrieve the value
    return @note
end
#--------------------------------------------------------------------------
# ● Set note (Runtime support)
#      note: New note
#--------------------------------------------------------------------------
def note=(note)
    # Set new note
    @note = note
    # Reanalyze
    analyze
end
#--------------------------------------------------------------------------
# ● Get/set the note value in general
#--------------------------------------------------------------------------
def method_missing(param_name, *args, &block)
    return super unless respond_to?(param_name)
    param_str = param_name.to_s.sub!(/^_/, "")
    # Set
    if param_str[-1] == 61
      param_key = param_str.chop
      self.class.send :define_method, param_name do |value|
      set_note(param_key, value)
      end
      set_note(param_key, *args)
    # Get
    else
      self.class.send :define_method, param_name do |value|
      get_note(param_str, value)
      end
      return get_note(param_str, *args)
    end
end
#--------------------------------------------------------------------------
# ● Method name validating
#--------------------------------------------------------------------------
def respond_to?(method_name, *)
    method_name.to_s[/^_.+/].nil? ? super : true
end
#--------------------------------------------------------------------------
# ● Override in WILD MODE
#--------------------------------------------------------------------------
def define_wild_methods
    return unless USE_WILD_MODE
    v = instance_variables.select {|i| instance_variable_get(i).is_a?(Numeric)}
    v.each do |i|
      next if i == "@id"
      var = i
      get_method = var; wild_get = "_#{var}"
      set_method = "#{var}="; wild_set = "_#{var}="
      self.class.send :define_method, get_method do
      send wild_get, instance_variable_get(i)
      end
      self.class.send :define_method, set_method do |value|
      send wild_set, value
      instance_variable_set(i, value)
      end
    end
end
#--------------------------------------------------------------------------
# ● Flat array
#--------------------------------------------------------------------------
def flat_array(param)
    case param
    when []
      []
    when Array
      $flat_array_cache ||= param.inject([]) {|a, e|
      a.concat(flat_array(e))}
    when Hash
      flat_array(param.values)
    when Range
      param.entries
    else
      
    end
end
#--------------------------------------------------------------------------
# ● Check description (Private method)
#--------------------------------------------------------------------------
private
def has_description?
    instance_variables.include?("@description")
end
#--------------------------------------------------------------------------
# ● Cut note from commands (Private method)
#--------------------------------------------------------------------------
def get_command_note(list)
    for index in 0...list.length
      break if list.code != 108 and list.code != 408
    end
    join_command_note(list, DELIMITER)
end
#--------------------------------------------------------------------------
# ● Join notes from commands (Private method)
#--------------------------------------------------------------------------
def join_command_note(list, linefeed)
    (list.collect do |x|
      case x.code
      when 111
      x.parameters == 12 ? x.parameters : ""
      when 209
      ((x.parameters.list.select do |c|
          c.code == 45
      end).map do |c|
          c.parameters
      end).join(linefeed)
      else
      x.parameters
      end
    end).join(linefeed)
end
#--------------------------------------------------------------------------
# ● Split key/value pairs (Private method)
#--------------------------------------------------------------------------
def split(text)
    text.slice(SEP_REGEX).to_s
end
#--------------------------------------------------------------------------
# ● Get note value (Private method)
#--------------------------------------------------------------------------
def get_note(param_name, default = nil)
    return default if self.note.empty? or not @note_set.include?(param_name)
    value = @note_set.nil? ? default : @note_set
    value.is_a?(Proc) ? value.call($game_variables) : value
end
#--------------------------------------------------------------------------
# ● Set note value (Private method)
#--------------------------------------------------------------------------
def set_note(param_name, value)
    @note_set ||= {}
    @note_set = value
end
#--------------------------------------------------------------------------
# ● Get value from label (Private method)
#--------------------------------------------------------------------------
def get_label(label, identifier, linefeed)
    # Retrieve from cache if any
    event_id = label.sub!(/^(+),/, "") ? $1.to_i : note_event_id
    label = default_label(identifier) if label.empty?
    $data_notes ||= {}
    if $data_notes.has_key?()
      return $data_notes[]
    end
    # Initialize common event
    $data_common_events ||= load_data("Data/CommonEvents.rxdata")
    event = $data_common_events
    return "" if event.nil? or event.list.length == 1
    # Find label
    list = event.list
    start_index = 0
    end_index = list.length
    for index in 0...list.length
      next if list.code != 118
      if list.parameters == label
      start_index = index + 1
      elsif start_index > 0
      break end_index = index
      end
    end
    # Find note in commands
    if start_index == 0
      result = ""
    else
      cmds = list
      cmds.reject! do |x|
      not .include?(x.code)
      end
      result = join_command_note(cmds, linefeed)
    end
    $data_notes[] = result
end
#--------------------------------------------------------------------------
# ● Get value from INI file (Private method)
#--------------------------------------------------------------------------
def read_ini_file(label)
    return unless FileTest.exist?(NOTE_FILE)
    # Initialize label
    label = default_label(nil) if label.empty?
    # Open INI file
    File.open(NOTE_FILE, "r") do |f|
      label_key = "[#{label}]\n"
      found = false
      # Loop for each line
      f.each_line do |l|
      # Continue for remarks
      next if l == ?; or l == ?#
      # Continue for wrong labels
      next unless l == label_key or found
      # Continue for the next line
      (found = true; next) unless found
      # Find Labels
      break if l == ?[
      # Find key/value pair
      pair = l.split("=", 2)
      next if pair.size < 2
      key = pair.strip
      value = pair.strip
      # Try parse value as number, if failed, as string
      result = lambda{|v| eval(value) rescue value}
      result = result.call($game_variables) unless value =~ /v\[|\$/
      # Set the value
      @note_set = result
      end
    end
end
#--------------------------------------------------------------------------
# ● Get extra long notes' Event ID(Private method)
#--------------------------------------------------------------------------
def note_event_id
    class_name = self.class.to_s
    eval(class_name.upcase + "_COMMON_EVENT_ID") rescue 0
end
#--------------------------------------------------------------------------
# ● Get extra long notes' Label name(Private method)
#--------------------------------------------------------------------------
def default_label(id)
    if self.is_a?(RPG::Event)
      sprintf("%03d#%s%s", $game_map.map_id, self.name, id ? "_#{id}" : "")
    else
      self.name + (id ? "_#{id}" : "")
    end
end
#--------------------------------------------------------------------------
# ● Analyze the note string (Single run for every object)
#--------------------------------------------------------------------------
def analyze
    @note_set = {}
    # When empty, returns nil
    return if @note.nil? or @note.empty?
    # When label, read from reference
    if @note == NOTE_LABEL_CHAR
      @note = SEPARATOR + get_label(@note, nil, NOTE_DATA_LF)
    elsif @note == NOTE_FILE_CHAR
      read_ini_file(@note)
      return
    end
    # Split strings
    param_regex = /^ *(+)\b([+:=.\-]?(.*?))$/
    # Delimit sections
    note_array = @note.gsub(/\\#{DELIMITER}/, "\001").split(DELIMITER)
    note_array.each do |x|
      result = nil
      if x
      param_name = $1
      param_value = $2
      param_exp = $3.gsub(/\001/, DELIMITER)
      # Boolean (+)
      if param_value.strip.empty? or param_value == ?+
          result = true
      # Boolean (-)
      elsif param_value == ?-
          result = false
      # Numeric
      elsif param_value == ?=
          result = lambda{|v| eval(param_exp) rescue nil}
          result = result.call($game_variables) unless param_exp =~ /v\[|\$/
      # String
      elsif param_value == ?:
          result = param_exp
      # Label
      elsif param_value == ?.
          result = get_label(param_exp, param_name, NOTE_STRING_LF)
      end
      @note_set = result
      end
    end
end
end

#==============================================================================
# ■ RPG Module Inclusions
#------------------------------------------------------------------------------
#   Include this function for 14 RPG modules.
#==============================================================================
module RPG
.each do |c|
    c.send :include, DataNoteCore
    c.send :define_method, :name do
      @name1 ||= (@name.sub(DataNoteCore::SEP_REGEX) {|s| ""}).strip
    end
    c.send :define_method, :name= do |value|
      @name1 = value.strip
      @name = @name1 + DataNoteCore::SEPARATOR + note
    end
    c.new.define_wild_methods unless c == RPG::Event
end
.each do |c|
    c.send :include, DataNoteCore
    c.send :define_method, :description do
      @description1 ||= (@description.sub(DataNoteCore::SEP_REGEX) {|s|
      ""}).strip
    end
    c.send :define_method, :description= do |value|
      @description1 = value.strip
      @description = @description1 + DataNoteCore::SEPARATOR + note
    end
    c.new.define_wild_methods
end
.each do |c|
    c.send :include, DataNoteCore
end
end

#==============================================================================
# ■ Game_Event
#------------------------------------------------------------------------------
#   Include this function for Game Events (runtime map events).
#==============================================================================
class Game_Event
include DataNoteCore
end




本贴来自国际rpgmaker官方论坛作者:SailCat处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:https://forums.rpgmakerweb.com/threads/add-note-support-for-xp-database.171601/
页: [1]
查看完整版本: Add Note Support for XP Database