#==============================================================================
# ■ 技能消耗依赖 v1.3 by SailCat
#------------------------------------------------------------------------------
# 方法:本脚本插入到Main之前使用,并依赖数据库通用备注接口插件(在其之后)
# 版本:v1.3 (Build 171122)
# 效果:
# 1. 技能消耗SP以外的游戏数据,包括HP、道具、武器、防具、金钱、经验、变量
# 2. 技能使用场合依赖游戏条件,包括开关、状态、地图相关、装备、能力、步数等
# 3. 技能消耗额外的回合(技能冷却)
# 配置:插件为即插即用型,没有任何配置项,也不需要在脚本中设定任何东西
# 冲突:其他同类脚本,以及魔改了Scene_Skill的脚本
# 说明:
# 1. 技能消耗道具、武器、防具、金钱、变量时,有使用检查,不够消耗不让用。
# 2. 技能消耗HP、经验时,无使用检查,扣到0为止。
# 3. 技能依赖开关、状态、地图、地形、装备、属性均检查至所有条件严格相符。
# 4. 技能依赖能力检查条件为能力在指定范围内,步数检查条件为指定步数以上。
# 5. 备注写法:
# (写在描述里,不同条件可以叠加用分号隔开,备注和描述以#号分隔)
# (当[XX集]内容只有一条时,方括号可省略,当内容序号连续时,可写成子界)
# (条件太多写不下时,可用超长备注法,见依赖插件的说明)
# a) 技能消耗HP:ch=值
# b) 技能消耗道具:ci=[消耗道具ID集]
# 消耗道具个数>1的情况下,ID后缀两位小数为消耗个数,如4.05消耗4号道具5个
# 写成4和4.00是不一样的,前者消耗4号道具1个,后者要求持有4号道具但不消耗
# c) 技能消耗武器:cw=[消耗武器ID集],说明同道具,消耗的是持有的武器
# d) 技能消耗防具:ca=[消耗防具ID集],说明同道具,消耗的是持有的防具
# e) 技能消耗金钱:cg=值
# f) 技能消耗经验:cx=值
# g) 技能消耗变量:cv={变量ID=>消耗值},写成hash形式,不能省略花括号
# h) 技能消耗回合:cd=值
# i) 技能依赖开关:cs=[开关集],开关ID为正数要求ON,为负数要求OFF
# j) 技能依赖状态:cc=[状态集],状态ID为正数要求有,为负数要求没有
# k) 技能依赖地图:cm=[地图ID集],地图ID为正数要求在,为负数要求不在
# l) 技能依赖地形:ct=[地形标志集],标志为正数要求是,为负数要求不是
# m) 技能依赖装备:cq=[装备ID集],查身上装备,武器ID写负数,防具ID写正数
# n) 技能依赖步数:cp=值
# o) 技能依赖属性:ce=[属性ID集],查装备属性,正数要求有,负数要求没有
# p) 技能依赖能力:cn=能力字符串,如"str300",有多个条件直接连写
# 能力可以用hp/sp/str/dex/agi/int,大小写不敏感
# 条件值的写法:300或300+表示大于等于300;300-表示小于等于300;
# =300表示恰好300;300~400表示300到400之间(闭区间)
# q) 技能依赖茂密:cb+(要求茂密处)或cb-(要求非茂密处)
# r) 技能依赖公式:cf:公式脚本字符串,公式要能返回true或false的真伪值
# 公式中可以使用a代表技能使用者,v代表变量,s代表开关
#==============================================================================
#==============================================================================
# ■ SailCat's 插件公用
#==============================================================================
module SailCat
$sailcat_import ||= {}
#--------------------------------------------------------------------------
# ● 植入与依赖检查
#--------------------------------------------------------------------------
if $sailcat_import[:DataNoteCore].to_f >= 2.0
$sailcat_import[:SkillCost] = 1.3
else
raise "缺少依赖插件,通用数据库备注接口(v2.0以上版本)"
end
end
module RPG
#============================================================================
# ■ Skill_ItemCost
#----------------------------------------------------------------------------
# 处理技能消耗道具、武器、防具的内部类
#============================================================================
class Skill_ItemCost
#--------------------------------------------------------------------------
# ● 定义实例变量
#--------------------------------------------------------------------------
attr_accessor :id # 消耗的物品ID
attr_accessor :number # 消耗的数目
#--------------------------------------------------------------------------
# ● 初期化
#--------------------------------------------------------------------------
def initialize(n)
n = 0 unless n.is_a?(Numeric)
n += 0.01 if n.is_a?(Fixnum)
@id = Integer(n).abs
@number = [Integer((n - @id) * 100.0 + 1e-6), 0].max
end
#--------------------------------------------------------------------------
# ● 检查符合性
#--------------------------------------------------------------------------
def match?(proc)
return true if @id == 0
proc.call(@id) >= [@number, 1].max
end
end
#============================================================================
# ■ Skill_EquipCheck
#----------------------------------------------------------------------------
# 处理技能依赖装备状态的内部类
#============================================================================
class Skill_EquipCheck
#--------------------------------------------------------------------------
# ● 定义实例变量
#--------------------------------------------------------------------------
attr_accessor :weapons # 依赖的武器ID(空为不检查)
attr_accessor :armors1 # 依赖的盾牌ID(空为不检查)
attr_accessor :armors2 # 依赖的头盔ID(空为不检查)
attr_accessor :armors3 # 依赖的护甲ID(空为不检查)
attr_accessor :armors4 # 依赖的饰品ID(空为不检查)
#--------------------------------------------------------------------------
# ● 初期化
#--------------------------------------------------------------------------
def initialize(ary)
@weapons = @armors1 = @armors2 = @armors3 = @armors4 = []
ary.map! {|i| i.to_a}.flatten!
ary.each do |i|
if i < 0
@weapon_id.push(-i)
else
kind = $data_armors[i].kind + 1
instance_eval("@armors#{kind}.push(#{i})") rescue nil
end
end
end
#--------------------------------------------------------------------------
# ● 检查符合性
#--------------------------------------------------------------------------
def match?(a)
return false if !@weapons.empty? and !@weapons.include?(a.weapon_id)
return false if !@armors1.empty? and !@armors1.include?(a.armor1_id)
return false if !@armors2.empty? and !@armors2.include?(a.armor2_id)
return false if !@armors3.empty? and !@armors3.include?(a.armor3_id)
return false if !@armors4.empty? and !@armors4.include?(a.armor4_id)
return true
end
end
#============================================================================
# ■ Skill_AbilityCheck
#----------------------------------------------------------------------------
# 处理技能依赖能力的内部类
#============================================================================
class Skill_AbilityCheck
#--------------------------------------------------------------------------
# ● 常量
#--------------------------------------------------------------------------
REGEX = /(hp|sp|str|dex|agi|int)(=?([0-9]+)([+\-~])?([0-9]+)?)/i
#--------------------------------------------------------------------------
# ● 定义实例变量
#--------------------------------------------------------------------------
attr_accessor :hp_range # 依赖的 HP % 范围
attr_accessor :sp_range # 依赖的 SP % 范围
attr_accessor :str_range # 依赖的力量值范围
attr_accessor :dex_range # 依赖的灵巧值范围
attr_accessor :agi_range # 依赖的速度值范围
attr_accessor :int_range # 依赖的魔力值范围
#--------------------------------------------------------------------------
# ● 初期化
#--------------------------------------------------------------------------
def initialize(str)
@hp_range = @sp_range = 0..100
@str_range = @dex_range = @agi_range = @int_range = 0..999
ary = str.scan(REGEX)
ary.each do |a|
name = a[0].downcase
min = a[2]
max = a[4] || a[2]
if a[1][0] != 61
max = (name[1] == 112 ? 100 : 999) if a[3] == nil or a[3] == "+"
min = 0 if a[3] == "-" and a[4] == nil
end
instance_eval("@#{name}_range = #{min}..#{max}") rescue nil
end
end
#--------------------------------------------------------------------------
# ● 检查符合性
#--------------------------------------------------------------------------
def match?(a)
return false unless @hp_range === a.hp * 100 / a.maxhp
return false unless @sp_range === a.sp * 100 / [a.maxsp, 1].max
return false unless @str_range === a.str
return false unless @dex_range === a.dex
return false unless @agi_range === a.agi
return false unless @int_range === a.int
return true
end
end
#============================================================================
# ■ RPG::Skill
#----------------------------------------------------------------------------
# 数据库的技能类扩展
#============================================================================
class Skill
#--------------------------------------------------------------------------
# ● 备注定义
#--------------------------------------------------------------------------
def hp_cost; _ch(0).abs; end
def exp_cost; _cx(0).abs; end
def gold_cost; _cg(0).abs; end
def cooldown; _cd(0).abs; end
def variable_cost; _cv({}); end
def item_cost; _ci([]).to_a.map {|f| Skill_ItemCost.new(f)}; end
def weapon_cost; _cw([]).to_a.map {|f| Skill_ItemCost.new(f)}; end
def armor_cost; _ca([]).to_a.map {|f| Skill_ItemCost.new(f)}; end
def switch_check; flat_array(_cs([])); end
def state_check; flat_array(_cc([])); end
def map_check; flat_array(_cm([])); end
def terrain_check; flat_array(_ct([])); end
def element_check; flat_array(_ce([])); end
def bush_check; _cb(nil); end
def step_check; _cp(0).abs; end
def equip_check; Skill_EquipCheck.new(_cq([]).to_a); end
def ability_check; Skill_AbilityCheck.new(_cn("").to_s); end
def eval_check; _cf("true"); end
#--------------------------------------------------------------------------
# ● 公式依赖判定
#--------------------------------------------------------------------------
def eval_match?(actor)
result = lambda {|a, s, v| eval(eval_check) rescue true}
result.call(actor, $game_switches, $game_variables)
end
#--------------------------------------------------------------------------
# ● 通用正负依赖判定
#--------------------------------------------------------------------------
def pn_match?(set, obj, proc = Proc.new{|a, b| a == b})
(set.reject {|s| (s > 0) == proc.call(obj, s.abs)}).empty?
end
#--------------------------------------------------------------------------
# ● 变量消耗判定
#--------------------------------------------------------------------------
def variable_match?
variable_cost.each do |k, v|
return false if $game_variables[k] < v
end
return true
end
#--------------------------------------------------------------------------
# ● 道具消耗判定
#--------------------------------------------------------------------------
def item_match?(set, proc)
set.each do |s|
return false unless s.match?(proc)
end
return true
end
end
end
#==============================================================================
# ■ Game_Battler
#==============================================================================
class Game_Battler
#--------------------------------------------------------------------------
# ● 使用技能的额外消耗
# skill : 特技
#--------------------------------------------------------------------------
def skill_cost_extra(skill)
self.hp -= skill.hp_cost
end
end
#==============================================================================
# ■ Game_Actor
#==============================================================================
class Game_Actor
#--------------------------------------------------------------------------
# ● 定义实例变量
#--------------------------------------------------------------------------
attr_reader :cooldowns # 冷却中的技能集
#--------------------------------------------------------------------------
# ● 方法重定义
#--------------------------------------------------------------------------
unless method_defined? :sailcat_skill_can_use?
alias sailcat_skillcost_skill_can_use? skill_can_use?
end
#--------------------------------------------------------------------------
# ● 可以使用特技判定
# skill_id : 特技 ID
#--------------------------------------------------------------------------
def skill_can_use?(skill_id)
# 获得对应的特技实体
skill = $data_skills[skill_id]
# 装备不符的情况下,不能使用
if not skill.equip_check.match?(self)
return false
# 能力不符的情况下,不能使用
elsif not skill.ability_check.match?(self)
return false
# 步数不够的情况下,不能使用
elsif $game_party.steps < skill.step_check
return false
# 金钱不够的情况下,不能使用
elsif $game_party.silver < skill.gold_cost
return false
# 属性不符的情况下,不能使用
elsif not skill.pn_match?(skill.element_check, self, Proc.new{|a,b|
a.element_set.include?(b) or ([a.armor1_id, a.armor2_id,
a.armor3_id, a.armor4_id].inject(false) {|res, id|
res |= id > 0 and $data_armors[id].guard_element_set.include?(b)})
})
return false
# 地图不符的情况下,不能使用
elsif not skill.pn_match?(skill.map_check, $game_map.map_id)
return false
# 地形不符的情况下,不能使用
elsif not skill.pn_match?(skill.terrain_check, $game_player.terrain_tag)
return false
# 状态不符的情况下,不能使用
elsif not skill.pn_match?(skill.state_check, self,
Proc.new{|a, b| a.state?(b)})
return false
# 茂盛不符的情况下,不能使用
elsif skill.bush_check != nil and
skill.bush_check != ($game_player.bush_depth == 12)
return false
# 开关不符的情况下,不能使用
elsif not skill.pn_match?(skill.switch_check, $game_switches,
Proc.new{|a, b| a[b]})
return false
# 战斗时,冷却中的情况下,不能使用
elsif $game_temp.in_battle and cooldown?(skill_id)
return false
# 变量不符的情况下,不能使用
elsif not skill.variable_match?
return false
# 道具不够的情况下,不能使用
elsif not skill.item_match?(skill.item_cost,
Proc.new{|n| $game_party.item_number(n)})
return false
# 武器不够的情况下,不能使用
elsif not skill.item_match?(skill.weapon_cost,
Proc.new{|n| $game_party.weapon_number(n)})
return false
# 防具不够的情况下,不能使用
elsif not skill.item_match?(skill.armor_cost,
Proc.new{|n| $game_party.armor_number(n)})
return false
# 公式计算为false或nil的情况下,不能使用
elsif not skill.eval_match?(self)
return false
end
# 进行原始判定
sailcat_skillcost_skill_can_use?(skill_id)
end
#--------------------------------------------------------------------------
# ● 清除冷却技能
#--------------------------------------------------------------------------
def reset_cooldown
@cooldowns = {}
end
#--------------------------------------------------------------------------
# ● 设置冷却技能
# skill_id : 特技 ID
#--------------------------------------------------------------------------
def set_cooldown(skill_id)
if $data_skills[skill_id].cooldown > 0
@cooldowns[skill_id] = $data_skills[skill_id].cooldown
end
end
#--------------------------------------------------------------------------
# ● 更新冷却技能,该方法一回合调用一次
#--------------------------------------------------------------------------
def update_cooldown
@cooldowns.each_key {|k| @cooldowns[k] -= 1}
@cooldowns.delete_if {|k, v| v == 0}
end
#--------------------------------------------------------------------------
# ● 冷却中判定
# skill_id : 特技 ID
#--------------------------------------------------------------------------
def cooldown?(skill_id)
@cooldowns.has_key?(skill_id)
end
#--------------------------------------------------------------------------
# ● 使用技能的额外消耗
# skill : 特技 ID
#--------------------------------------------------------------------------
def skill_cost_extra(skill)
super
self.exp -= skill.exp_cost
$game_party.lose_gold(skill.gold_cost)
skill.item_cost.each {|i| $game_party.lose_item(i.id, i.number)}
skill.weapon_cost.each {|i| $game_party.lose_weapon(i.id, i.number)}
skill.armor_cost.each {|i| $game_party.lose_armor(i.id, i.number)}
skill.variable_cost.each_pair {|k, v| $game_variables[k] -= v}
set_cooldown(skill.id) if $game_temp.in_battle
end
end
#==============================================================================
# ■ Game_Party
#==============================================================================
class Game_Party
#--------------------------------------------------------------------------
# ● 清除冷却技能
#--------------------------------------------------------------------------
def reset_cooldown
actors.each {|a| a.reset_cooldown}
end
#--------------------------------------------------------------------------
# ● 更新冷却技能,该方法一回合调用一次
#--------------------------------------------------------------------------
def update_cooldown
actors.each {|a| a.update_cooldown}
end
end
#==============================================================================
# ■ Scene_Battle
#==============================================================================
class Scene_Battle
#--------------------------------------------------------------------------
# ● 方法重定义
#--------------------------------------------------------------------------
unless method_defined? :sailcat_start_phase1
alias sailcat_skillcost_start_phase1 start_phase1
alias sailcat_skillcost_start_phase4 start_phase4
alias sailcat_skillcost_make_skill_action_result make_skill_action_result
end
#--------------------------------------------------------------------------
# ● 开始自由战斗回合
#--------------------------------------------------------------------------
def start_phase1
# 调用原方法
sailcat_skillcost_start_phase1
# 清除技能冷却
$game_party.reset_cooldown
end
#--------------------------------------------------------------------------
# ● 开始主回合
#--------------------------------------------------------------------------
def start_phase4
# 调用原方法
sailcat_skillcost_start_phase4
# 更新技能冷却
$game_party.update_cooldown
end
#--------------------------------------------------------------------------
# ● 生成特技行动结果
#--------------------------------------------------------------------------
def make_skill_action_result
# 调用原方法
sailcat_skillcost_make_skill_action_result
# 额外消耗
@active_battler.skill_cost_extra(@skill)
end
end
#==============================================================================
# ■ Scene_Skill
#==============================================================================
class Scene_Skill
#--------------------------------------------------------------------------
# ● 刷新画面 (特技窗口被激活的情况下)
#--------------------------------------------------------------------------
def update_skill
# 按下 B 键的情况下
if Input.trigger?(Input::B)
# 演奏取消 SE
$game_system.se_play($data_system.cancel_se)
# 切换到菜单画面
$scene = Scene_Menu.new(1)
return
end
# 按下 C 键的情况下
if Input.trigger?(Input::C)
# 获取特技窗口现在选择的特技的数据
@skill = @skill_window.skill
# 不能使用的情况下
if @skill == nil or not @actor.skill_can_use?(@skill.id)
# 演奏冻结 SE
$game_system.se_play($data_system.buzzer_se)
return
end
# 演奏确定 SE
$game_system.se_play($data_system.decision_se)
# 效果范围是我方的情况下
if @skill.scope >= 3
# 激活目标窗口
@skill_window.active = false
@target_window.x = (@skill_window.index + 1) % 2 * 304
@target_window.visible = true
@target_window.active = true
# 设置效果范围 (单体/全体) 的对应光标位置
if @skill.scope == 4 || @skill.scope == 6
@target_window.index = -1
elsif @skill.scope == 7
@target_window.index = @actor_index - 10
else
@target_window.index = 0
end
# 效果在我方以外的情况下
else
# 公共事件 ID 有效的情况下
if @skill.common_event_id > 0
# 预约调用公共事件
$game_temp.common_event_id = @skill.common_event_id
# 演奏特技使用时的 SE
$game_system.se_play(@skill.menu_se)
# 消耗 SP
@actor.sp -= @skill.sp_cost
# 额外的消耗
@actor.skill_cost_extra(@skill)
# 再生成各窗口的内容
@status_window.refresh
@skill_window.refresh
@target_window.refresh
# 切换到地图画面
$scene = Scene_Map.new
return
end
end
return
end
# 按下 R 键的情况下
if Input.trigger?(Input::R)
# 演奏光标 SE
$game_system.se_play($data_system.cursor_se)
# 移至下一位角色
@actor_index += 1
@actor_index %= $game_party.actors.size
# 切换到别的特技画面
$scene = Scene_Skill.new(@actor_index)
return
end
# 按下 L 键的情况下
if Input.trigger?(Input::L)
# 演奏光标 SE
$game_system.se_play($data_system.cursor_se)
# 移至上一位角色
@actor_index += $game_party.actors.size - 1
@actor_index %= $game_party.actors.size
# 切换到别的特技画面
$scene = Scene_Skill.new(@actor_index)
return
end
end
#--------------------------------------------------------------------------
# ● 刷新画面 (目标窗口被激活的情况下)
#--------------------------------------------------------------------------
def update_target
# 按下 B 键的情况下
if Input.trigger?(Input::B)
# 演奏取消 SE
$game_system.se_play($data_system.cancel_se)
# 删除目标窗口
@skill_window.active = true
@target_window.visible = false
@target_window.active = false
return
end
# 按下 C 键的情况下
if Input.trigger?(Input::C)
# 因为 SP 不足而无法使用的情况下
unless @actor.skill_can_use?(@skill.id)
# 演奏冻结 SE
$game_system.se_play($data_system.buzzer_se)
return
end
# 目标是全体的情况下
if @target_window.index == -1
# 对同伴全体应用特技使用效果
used = false
for i in $game_party.actors
used |= i.skill_effect(@actor, @skill)
end
end
# 目标是使用者的情况下
if @target_window.index <= -2
# 对目标角色应用特技的使用效果
target = $game_party.actors[@target_window.index + 10]
used = target.skill_effect(@actor, @skill)
end
# 目标是单体的情况下
if @target_window.index >= 0
# 对目标角色应用特技的使用效果
target = $game_party.actors[@target_window.index]
used = target.skill_effect(@actor, @skill)
end
# 使用特技的情况下
if used
# 演奏特技使用时的 SE
$game_system.se_play(@skill.menu_se)
# 消耗 SP
@actor.sp -= @skill.sp_cost
# 额外的消耗
@actor.skill_cost_extra(@skill)
# 再生成各窗口内容
@status_window.refresh
@skill_window.refresh
@target_window.refresh
# 全灭的情况下
if $game_party.all_dead?
# 切换到游戏结束画面
$scene = Scene_Gameover.new
return
end
# 公共事件 ID 有效的情况下
if @skill.common_event_id > 0
# 预约调用公共事件
$game_temp.common_event_id = @skill.common_event_id
# 切换到地图画面
$scene = Scene_Map.new
return
end
end
# 无法使用特技的情况下
unless used
# 演奏冻结 SE
$game_system.se_play($data_system.buzzer_se)
end
return
end
end
end