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]