# @taroxd metadata 1.0
# @id task
# @require taroxd_core
# @display 简单任务系统
class Taroxd::Task
LIST = [
# 在此设置任务的内容。设置方式请参考 Taroxd::Task 的定义。
]
COMPLETED_PREFIX = '\I[125]' # 任务完成时的前缀,不需要可设置为 ''
ONGOING_PRIFIX = '\I[126]' # 任务进行中的前缀,不需要可设置为 ''
COMMAND = '任务' # 菜单上的指令名,不需要可设置为 nil
def initialize(id, name, description = '', goal = 1)
@id, @name, @description, @goal = id, name, description, goal
end
attr_reader :description
def name
(completed? ? COMPLETED_PREFIX : ONGOING_PRIFIX) + @name
end
def started?
$game_switches[@id]
end
def completed?
$game_variables[@id] >= @goal
end
# 设置任务列表
LIST.map! { |args| new(*args) }
def self.list
LIST.select(&:started?)
end
end
class Window_TaskList < Window_Selectable
Task = Taroxd::Task
def initialize(y)
super(0, y, Graphics.width, Graphics.height - y)
select Task.list.index { |task| !task.completed? }
refresh
end
def col_max
2
end
def item_max
Task.list.size
end
def draw_item(index)
rect = item_rect_for_text(index)
draw_text_ex(rect.x, rect.y, Task.list[index].name)
end
def update_help
@help_window.set_text(Task.list[index].description)
end
end
class Scene_Task < Scene_MenuBase
def start
super
create_help_window
create_list_window
end
# 任务列表窗口
def create_list_window
@list_window = Window_TaskList.new(@help_window.height)
@list_window.help_window = @help_window
@list_window.set_handler(:cancel, method(:return_scene))
@list_window.activate
end
end
if Taroxd::Task::COMMAND
class Window_MenuCommand < Window_Command
task = Taroxd::Task
# 指令“任务”
def_after :add_original_commands do
add_command(task::COMMAND, :task, !task.list.empty?)
end
end
class Scene_Menu < Scene_MenuBase
def_after :create_command_window do
@command_window.set_handler(:task, method(:command_task))
end
# 指令“任务”
def command_task
SceneManager.call(Scene_Task)
end
end
end
简单任务系统
Taroxd 基础设置
# @taroxd metadata 1.0
# @display Taroxd 基础设置
# @id taroxd_core
# @help
#
# 模块或类
# 方法名(参数) { block } / 别名 -> 返回值的类型或介绍
# 方法的介绍。
# 如果返回值没有给出,表明返回值无意义或没有确定的类型。
#
# Module
# get_access_control(method_name) -> Symbol or nil
# 获取方法的访问控制。返回 :public, :protected, :private 或 nil(未定义)
# method_name 为字符串或符号(Symbol),下同。
#
# def_after(method_name) { |args| block } -> method_name
# def_after(method_name, hook) -> method_name
# 重定义方法 method_name。
# 第一种形式中,将 block 定义为方法,在原方法之后调用。
# 第二种形式中,
# * 如果 hook 为符号或字符串,那么会在原方法之后调用对应的方法。
# * 如果 hook 可以响应方法 call,那么会在原方法之后调用 call。
# * 如果 hook 是 UnboundMethod,那么会将 hook 绑定到对象后调用。
#
# 不改变原方法的返回值和访问控制。
# 无论哪种调用,参数都和原来的参数相同。
# 以下 def_* 的所有方法均有这两种形式。为了方便起见只写出第一种。
#
# 例:
# class Game_Actor < Game_Battler
# def_after :initialize do |actor_id|
# @my_attribute = actor_id
# end
# end
#
# def_after!(method_name) { |args| block } -> method_name
# 与 def_after 类似,但改变原方法的返回值。
#
# def_before(method_name) { |args| block } -> method_name
# 与 def_after 类似,但在原方法之前调用。
#
# def_with(method_name) { |old, args| block } -> method_name
# 与 def_after! 类似,但参数不同。old 参数是原方法的返回值。
#
# def_chain(method_name) { |old, args| block } -> method_name
# 与 def_with 类似,但 old 参数为对应原方法的一个 Method 对象。
#
# def_and(method_name) { |args| block } -> method_name
# 与 def_after 类似,但仅当原方法的返回值为真时调用。
# 仅当原方法的返回值为真时,才会改变原方法的返回值。
#
# def_or(method_name) { |args| block } -> method_name
# 与 def_after 类似,但仅当原方法的返回值为伪时调用。
# 仅当原方法的返回值为假时,才会改变原方法的返回值。
#
# def_if(method_name) { |args| block } -> method_name
# 与 def_before 类似,但仅当调用结果为真时调用原方法。
# 仅当调用的结果为假时,改变原方法的返回值为 nil。
#
# def_unless(method_name) { |args| block } -> method_name
# 与 def_before 类似,但仅当调用结果为假时调用原方法。
# 仅当调用的结果为真时,改变原方法的返回值为 nil。
#
# Taroxd::ReadNote
# 该模块由以下类 extend。
# RPG::BaseItem
# RPG::Map
# RPG::Event(将事件名称作为备注)
# RPG::Tileset
# RPG::Class::Learning
#
# note_i(method_name, default = 0)
# 定义方法 method_name,读取备注中 <method_name x> 形式的内容。其中 x 为整数。
# 读取到的话,定义的方法会返回读取到的整数值,否则返回 default。
#
# 例:RPG::UsableItem.note_i :item_cost
#
# note_f(method_name, default = 0.0)
# 与 note_i 类似,但读取的是实数。
#
# note_s(method_name, default = '')
# 与 note_i 类似,但读取的是字符串。
#
# note_bool(method_name)
# 定义 method_name 方法,判断备注中是否存在 <method_name> 子字符串。
# 特别地,若 method_name 以问号或感叹号结尾,读取内容中不需要包含问号、感叹号。
# (上面几个方法也是一样)
#
# Taroxd::DisposeBitmap
# dispose
# 释放位图后调用父类的 dispose 方法。
#
# Spriteset_Map / Spriteset_Battle
# self.use_sprite(SpriteClass)
# self.use_sprite(SpriteClass) { block }
# 在 Spriteset 中使用一个 SpriteClass 的精灵。
# 如果给出 block,则生成精灵使用的参数是 block 在 Spriteset 的上下文中执行后的返回值。
# 自动管理精灵的生成、更新、释放。
#
# 例:Spriteset_Map.use_sprite(Sprite_OnMap) { @viewport1 }
#
# Fixnum
# id -> self
# 返回 self。这使得之后一些方法的参数既可以用数据库的数据,也可以用整数。
#
# Enumerable
# sum(base = 0) { |element| block }
# 对所有元素 yield 后求和。base 为初始值。
# 没有 block 参数时,对所有元素求和。
#
# 例:
# class Game_Unit
# def tgr_sum
# alive_members.sum(&:tgr)
# end
# end
#
# pi(base = 1) { |element| block }
# 与 sum 类似,但对所有元素求积。
#
# Game_BaseItem
# id / item_id -> Fixnum
# 返回物品 id。
#
# Game_BattlerBase
# mtp -> Numeric
# 返回 max_tp。
#
# initialized? -> true
# 返回 true。
#
# Game_Battler
# note_objects -> Enumerator
# note_objects { |obj| ... } -> self
# 迭代战斗者拥有的所有带有备注的对象。
# (角色、职业、装备、技能、敌人、状态等)
# 没有 block 给出时,返回 Enumerator 对象。
#
# note -> String
# 返回数据库对象的备注。
#
# equips / weapons / armors -> []
# 返回空数组。
#
# skill?(skill) -> true / false
# 判断是否拥有技能。skill 可以为技能 ID,也可以为 RPG::Skill 的实例。
#
# skill_learn?(skill) -> true / false
# 判断是否习得技能。skill 可以为技能 ID,也可以为 RPG::Skill 的实例。
#
# Game_Actor
# data_object -> RPG::Actor
# 返回数据库对象,等价于 actor。
#
# weapon?(item) / armor?(item) -> true / false
# 检测是否装备对应的物品。item 可以为装备 ID,也可以为 RPG::EquipItem 的实例。
#
# initialized? -> true / false
# 判断角色是否已经初始化。
#
# Game_Enemy
# id -> Fixnum
# 返回敌人 id。
#
# data_object -> RPG::Enemy
# 返回数据库对象,等价于 enemy。
#
# skills -> Array
# 返回敌人的所有技能实例的数组。
# skill? 方法判断是否拥有技能与该数组有关。
#
# basic_skills -> Array
# 返回敌人行动列表中的技能 ID 的数组(元素可以重复)。
# skill_learn? 方法判断是否学会技能与该数组有关。
#
# Game_Actors
# include Enumerable
#
# each -> Enumerator
# each { |actor| block } -> self
# 迭代已经初始化的每个角色。
# 如果没有给出 block,返回一个 Enumerator 对象。
#
# include?(actor)
# 角色是否已经初始化。actor 可以为 Game_Actor / RPG::Actor 的对象或 ID。
#
# Game_Unit
# include Enumerable
#
# each -> Enumerator
# each { |battler| block } -> self
# 迭代队伍中的每个成员。
# 如果没有给出 block,返回一个 Enumerator 对象。
# 等价于 members.each。
#
# each_member -> Enumerator / self
# each 的别名。
#
# self[*args] / slice(*args) -> Game_Actor / Array / nil
# 等价于 members[*args]
#
# empty? -> true / false
# 判断队伍是否为空。
#
# size / length -> Integer
# 返回队伍人数。
#
# Game_Party
# include?(actor) -> true / false
# 队伍中是否存在角色。actor 可以为 Game_Actor / RPG::Actor 的对象或 ID。
#
# Game_Map
# id -> Fixnum
# 返回地图 ID。
#
# data_object -> RPG::Map
# 返回数据库对象。
#
# note -> String
# 返回备注内容。
#
# Game_CharacterBase
# same_pos?(character) -> true / false
# 判定是否处在相同位置。
# character 是任意能够响应方法 x 和 y 的对象。
# 仅作为点(x, y)进行比较,不考虑 Game_Vehicle 的地图 ID 等问题。
module Taroxd end
module Taroxd::Def
Singleton = Module.new { Object.send :include, self }
Module.send :include, self
def get_access_control(sym)
return :public if public_method_defined? sym
return :protected if protected_method_defined? sym
return :private if private_method_defined? sym
nil
end
template = lambda do |singleton|
if singleton
klass = 'singleton_class'
get_method = 'method'
define = 'define_singleton_method'
else
klass = 'self'
get_method = 'instance_method'
define = 'define_method'
end
%(
def <name>(sym, hook = nil, &b)
access = #{klass}.get_access_control sym
old = #{get_method} sym
if b
#{define} sym, &b
hook = #{get_method} sym
end
if hook.respond_to? :to_sym
hook = hook.to_sym
#{define} sym do |*args, &block|
<pattern_sym>
end
elsif hook.respond_to? :call
#{define} sym do |*args, &block|
<pattern_call>
end
elsif hook.kind_of? UnboundMethod
#{define} sym do |*args, &block|
<pattern_unbound>
end
end
#{klass}.__send__ access, sym
sym
end
)
end
# 保存模板和替换 'hook(' 字符串的字符
template = {false => template.call(false), true => template.call(true)}
# 替换掉 pattern 中的语法
gsub_pattern = lambda do |pattern, singleton|
old = singleton ? 'old' : 'old.bind(self)'
pattern.gsub('*', '*args, &block')
.gsub(/old(\()?/) { $1 ? "#{old}.call(" : old }
end
# 存入代替 "hook(" 的字符串
template['sym'] = '__send__(hook, '
template['call'] = 'hook.call('
template['unbound'] = 'hook.bind(self).call('
# 获取定义方法内容的字符串
# 得到的代码较长,请输出查看
code = lambda do |name, pattern, singleton|
pattern = gsub_pattern.call(pattern, singleton)
template[singleton]
.sub('<name>', name)
.gsub(/<pattern_(\w+?)>/) { pattern.gsub('hook(', template[$1]) }
end
main = TOPLEVEL_BINDING.eval('self')
# 定义 def_ 系列方法的方法
define_singleton_method :def_ do |name, pattern|
name = "#{__method__}#{name}"
module_eval code.call(name, pattern, false)
Singleton.module_eval code.call("singleton_#{name}", pattern, true)
main.define_singleton_method name, &Kernel.method(name)
end
# 实际定义 def_ 系列的方法
def_ :after, 'ret = old(*); hook(*); ret'
def_ :after!, 'old(*); hook(*)'
def_ :before, 'hook(*); old(*)'
def_ :with, 'hook(old(*), *)'
def_ :chain, 'hook(old, *)'
def_ :and, 'old(*) && hook(*)'
def_ :or, 'old(*) || hook(*)'
def_ :if, 'old(*) if hook(*)'
def_ :unless, 'old(*) unless hook(*)'
end
module Taroxd::ReadNote
include RPG
BaseItem.extend self
Map.extend self
Event.extend self
Tileset.extend self
Class::Learning.extend self
# 获取 note 的方法
def note_method
:note
end
# 事件名称作为备注
def Event.note_method
:name
end
# 备注模板
def note_any(name, default, re, capture)
name = name.to_s
mark = name.slice!(/[?!]\Z/)
re = re.source if re.kind_of?(Regexp)
re = "/<#{name.gsub('_', '\s*')}#{re}>/i"
default = default.inspect
class_eval %{
def #{name}
return @#{name} if instance_variable_defined? :@#{name}
@#{name} = #{note_method} =~ #{re} ? (#{capture}) : (#{default})
end
}, __FILE__, __LINE__
alias_method name + mark, name if mark
end
def note_i(name, default = 0)
note_any(name, default, '\s*(-?\d+)', '$1.to_i')
end
def note_f(name, default = 0.0)
note_any(name, default, '\s*(-?\d+(?:\.\d+)?)', '$1.to_f')
end
def note_s(name, default = '')
note_any(name, default, '\s*(\S.*)', '$1')
end
def note_bool(name)
note_any(name, false, '', 'true')
end
end
module Taroxd::DisposeBitmap
def dispose
bitmap.dispose if bitmap
super
end
end
module Taroxd::SpritesetDSL
# 方法名
CREATE_METHOD_NAME = :create_taroxd_sprites
UPDATE_METHOD_NAME = :update_taroxd_sprites
DISPOSE_METHOD_NAME = :dispose_taroxd_sprites
# 定义管理精灵的方法
def self.extended(klass)
klass.class_eval do
sprites = nil
define_method CREATE_METHOD_NAME do
sprites = klass.sprite_list.map do |sprite_class, get_args|
if get_args
sprite_class.new(*instance_eval(&get_args))
else
sprite_class.new
end
end
end
define_method(UPDATE_METHOD_NAME) { sprites.each(&:update) }
define_method(DISPOSE_METHOD_NAME) { sprites.each(&:dispose) }
end
end
def use_sprite(klass, &get_args)
sprite_list.push [klass, get_args]
end
def sprite_list
@_taroxd_use_sprite ||= []
end
# 在一系列方法上触发钩子
def sprite_method_hook(name)
def_after :"create_#{name}", CREATE_METHOD_NAME
def_after :"update_#{name}", UPDATE_METHOD_NAME
def_after :"dispose_#{name}", DISPOSE_METHOD_NAME
end
end
class Fixnum < Integer
alias_method :id, :to_int
end
module Enumerable
def sum(base = 0)
block_given? ? inject(base) { |a, e| a + yield(e) } : inject(base, :+)
end
def pi(base = 1)
block_given? ? inject(base) { |a, e| a * yield(e) } : inject(base, :*)
end
end
class Game_BaseItem
attr_reader :item_id
alias_method :id, :item_id
end
class Game_BattlerBase
def initialized?
true
end
def mtp
max_tp
end
end
class Game_Battler < Game_BattlerBase
# 迭代拥有备注的对象
def note_objects
return to_enum(__method__) unless block_given?
states.each { |e| yield e }
equips.each { |e| yield e if e }
skills.each { |e| yield e }
yield data_object
yield self.class if actor?
end
def regenerate_tp
self.tp += max_tp * trg
end
def data_object
raise NotImplementedError
end
def note
data_object.note
end
def id
data_object.id
end
def skills
(basic_skills | added_skills).sort.map { |id| $data_skills[id] }
end
def equips
[]
end
alias_method :weapons, :equips
alias_method :armors, :equips
alias_method :basic_skills, :equips
def skill?(skill)
basic_skills.include?(skill.id) || added_skills.include?(skill.id)
end
def skill_learn?(skill)
basic_skills.include?(skill.id)
end
end
class Game_Actor < Game_Battler
alias_method :data_object, :actor
def weapon?(weapon)
@equips.any? { |item| item.id == weapon.id && item.is_weapon? }
end
def armor?(armor)
@equips.any? { |item| item.id == armor.id && item.is_armor? }
end
def initialized?
$game_actors.include?(self)
end
private
def basic_skills
@skills
end
end
class Game_Enemy < Game_Battler
alias_method :data_object, :enemy
alias_method :id, :enemy_id
def basic_skills
enemy.actions.map(&:skill_id)
end
end
class Game_Actors
include Enumerable
def each
return to_enum(__method__) unless block_given?
@data.each { |actor| yield actor if actor }
self
end
def include?(actor)
@data[actor.id]
end
end
class Game_Unit
include Enumerable
def to_a
members
end
def each
return to_enum(__method__) unless block_given?
members.each { |battler| yield battler }
self
end
alias_method :each_member, :each
def [](*args)
members[*args]
end
alias_method :slice, :[]
def empty?
members.empty?
end
def size
members.size
end
alias_method :length, :size
end
class Game_Party < Game_Unit
def include?(actor)
@actors.include?(actor.id)
end
end
class Game_Map
alias_method :id, :map_id
def data_object
@map
end
def note
@map.note
end
end
class Game_CharacterBase
def same_pos?(character)
@x == character.x && @y == character.y
end
end
class Spriteset_Map
extend Taroxd::SpritesetDSL
sprite_method_hook :timer
end
class Spriteset_Battle
extend Taroxd::SpritesetDSL
sprite_method_hook :timer
end
使用目标的扩展
# @taroxd metadata 1.0
# @require taroxd_core
# @id target_ext
# @display 使用目标的扩展
# @help 设置技能、物品的使用目标。
# 使用方法:
# 在技能/物品的备注栏写下类似于下面例子的备注,设置可选择的全体目标。
#
# 该脚本不影响菜单中使用技能/物品。
#
# 用 a 指代使用者,用 b 或 self 指代目标。
#
# 例1:存活队员中 hp 比例最小者。
# <target>
# select: alive?
# min_by: hp_rate
# </target>
#
# 例2:所有 hp 大于 50 的队员
# <target>
# select: hp > 50
# </target>
#
# 例3:除自己之外的全体队友
# <target>
# select: alive? && b != a
# </target>
#
# 例4:无视生死
# <target></target>
module Taroxd::TargetExt
RE_OUTER = /<target>(.*?)<\/target>/mi # 整体设置
SEPARATOR = ':' # 每一行中的分隔符
# 实例方法,用于选择目标的窗口中
# virtual
# 返回可以选择的所有目标
def targets_to_select
[]
end
# 返回设置的目标
# 若 actor 未初始化,或没有设置目标,返回 nil
def selectable_targets
actor = BattleManager.actor
return unless actor
item = actor.input.item
return unless item
item.get_targets(actor, targets_to_select)
end
# 由于父类可能未定义,不调用 super
def enable?(battler)
targets = selectable_targets
!targets || targets.include?(battler)
end
def current_item_enabled?
super && enable?(targets_to_select[index])
end
# 模块方法,用于读取备注
def self.parse_note(note)
note =~ RE_OUTER ? parse_settings($1) : false
end
private
# lambda do |battlers, a|
# battlers.select { |b| b.instance_eval { alive? && b != a } }
# end
def self.parse_settings(settings)
eval %(
lambda do |battlers, a|
battlers#{extract_settings(settings)}
end
)
end
def self.extract_settings(settings)
settings.each_line.map { |line|
method, _, block = line.partition(SEPARATOR).map(&:strip)
if method.empty?
''
elsif block.empty?
".#{method}"
else
".#{method} { |b| b.instance_eval { #{block} } }"
end
}.join
end
end
class RPG::UsableItem < RPG::BaseItem
# 缓存并返回生成的 lambda。
# 如果不存在,返回伪值。
def get_target_lambda
@get_target = Taroxd::TargetExt.parse_note(@note) if @get_target.nil?
@get_target
end
# 返回目标的数组。a:使用者。
# 如果没有设置,返回 nil。
def get_targets(a, battlers = nil)
return unless get_target_lambda
battlers ||= (for_friend? ? a.friends_unit : a.opponents_unit).members
Array(get_target_lambda.call(battlers, a))
end
end
class Game_Action
def_chain :targets_for_opponents do |old|
targets = item.get_targets(@subject)
if !targets
old.call
elsif item.for_random?
Array.new(item.number_of_targets) { random_target(targets) }
elsif item.for_one?
num = 1 + (attack? ? subject.atk_times_add.to_i : 0)
target = if @target_index < 0
random_target(targets)
else
eval_smooth_target(opponents_unit, @target_index)
end
Array.new(num, target)
else
targets
end
end
def_chain :targets_for_friends do |old|
targets = item.get_targets(@subject)
if !targets
old.call
elsif item.for_user?
[subject]
else
if item.for_one?
if @target_index < 0
[random_target(targets)]
else
[eval_smooth_target(friends_unit, @target_index)]
end
else
targets
end
end
end
private
def eval_smooth_target(unit, index)
unit[index] || unit[0]
end
def random_target(targets)
tgr_rand = rand * targets.sum(&:tgr)
targets.each do |target|
tgr_rand -= target.tgr
return target if tgr_rand < 0
end
targets.first
end
end
class Game_BattlerBase
# 如果设置了目标,必须存在目标才可使用
def_and :usable_item_conditions_met? do |item|
targets = item.get_targets(self)
!targets || !targets.empty?
end
end
class Game_Battler < Game_BattlerBase
# 如果设置了目标,删除是否死亡的测试
def_chain :item_test do |old, user, item|
if item.get_target_lambda
return true if $game_party.in_battle
return true if item.for_opponent?
return true if item.damage.recover? && item.damage.to_hp? && hp < mhp
return true if item.damage.recover? && item.damage.to_mp? && mp < mmp
return true if item_has_any_valid_effects?(user, item)
false
else
old.call(user, item)
end
end
end
class Window_BattleActor < Window_BattleStatus
include Taroxd::TargetExt
def targets_to_select
$game_party.battle_members
end
def draw_actor_name(actor, x, y, width = 112)
change_color(hp_color(actor), enable?(actor))
draw_text(x, y, width, line_height, actor.name)
end
end
class Window_BattleEnemy < Window_Selectable
include Taroxd::TargetExt
def targets_to_select
$game_troop.alive_members
end
def draw_item(index)
enemy = $game_troop.alive_members[index]
change_color(normal_color, enable?(enemy))
name = enemy.name
draw_text(item_rect_for_text(index), name)
end
end