# 简介
该系统可以让状态变得可堆叠,也就是说重复获得状态时会累计层数。同时,该系统支持将状态作为战斗资源使用,可以让技能以消费状态层数的方式打出。
# 使用方式
将脚本粘贴到数据库的单独一页内。
# 如何配置状态
给希望可堆叠的状态的备注栏加入一行:
[stackable]
这样重复获得状态时,不仅会刷新持续时间,还会增加计数。
如果希望限制最大层数,可以增加max属性:
[stackable max=3]
# 如何配置技能的发动条件
给希望消费状态的技能的备注栏加入一行:
[consume_state state=状态在数据库内的编号]
默认会消费全部层数的状态。如果想指定消费数量,可以使用count属性,例如:
[consume_state state=26 count=1]
这会消费一层26号状态。
特别地,如果count为0,表示只有在该状态下才能使出技能,但不会消费状态。
# 如何在脚本中读取状态的层数
使用Game_Battler的state_stack_count(skill_id)方法。
# 如何根据技能消费的状态层数决定威力
虽然理论上可以使用state_stack_count,但是由于VA的默认脚本会先支付技能消耗后使出技能,所以在计算伤害时状态层数已经变化了。
Game_Battler实例的last_state_cost属性表示上一次消耗的状态层数。
例如,伤害公式可以写成
1000 * a.last_state_cost
表示造成1000*攻击者发动技能前身上状态层数的伤害。
# 课后作业
1. 如何实现最多可蓄力3次的攻击?
2. 如何实现宝可梦系列的集气拳类技能(一回合蓄力后下一回合发动,但期间若受到攻击则蓄力会被打消而失败)?
3. 如何实现可以叠加威力的中毒debuff?
4. 如何实现技能连击系统(按照特定顺序使出特定技能的话会获得额外收益)?
5. 如何实现状态叠加到5层时即死?
# 使用许可
MIT
# 源代码
RUBY 代码
[Ruby] 纯文本查看 复制代码
# Stackable States by AzureFx
# Revision 20220519.1
# Licensed under the MIT License
def parse_note(note)
result=[]
note.each_line{|line|
m=/\[\s*([^\s=]+)\s*([^\]]+)?\s*\]/i.match(line)
if m!=nil
elem=m[1]
attr={}
attr_s=m[2]
if attr_s!=nil
attr_s.to_enum(:scan, /([^=\s]+)\s*=\s*([^=\s]+)/)
.map{Regexp.last_match}
.each{|m|attr[m[1]]=m[2]}
end
result.push([elem,attr])
end
}
result
end
class RPG::State
def stackable?
if @stackable==nil
parse_note_stackable
end
return @stackable
end
def max_stack
if @max_stack==nil
parse_note_stackable
end
return @max_stack
end
def parse_note_stackable
stackable=false
max_stack=0
parse_note(note).each{|entry|
elem, attr=entry
if elem=='stackable'
stackable=true
if attr['max']!=nil
max_stack=attr['max'].to_i
end
end
}
@stackable=stackable
@max_stack=max_stack
end
end
class RPG::Skill
def consume_stack
if @consume_stack_parsed==nil
parse_consume_stack
@consume_stack_parsed=true
end
@consume_stack
end
def parse_consume_stack
parse_note(note).each{|entry|
elem, attr=entry
if elem=='consume_state'
if attr['state']!=nil
state_id=attr['state'].to_i
@consume_stack={state: state_id}
if attr['count']!=nil
@consume_stack[:count]=attr['count'].to_i
end
end
end
}
end
end
class Game_BattlerBase
alias clear_states_b1f2b6 clear_states
def clear_states
clear_states_b1f2b6
@state_stacks={}
end
alias erase_state_b1f2b6 erase_state
def erase_state(state_id)
erase_state_b1f2b6(state_id)
@state_stacks.delete(state_id)
end
def state_stack_count(state_id)
@state_stacks[state_id]||0
end
def decrease_state_stack(state_id, count)
new_count=state_stack_count(state_id)-count
if new_count<=0
erase_state(state_id)
else
@state_stacks[state_id]=new_count
end
end
alias skill_cost_payable_b1f2b6? skill_cost_payable?
def skill_cost_payable?(skill)
cs=skill.consume_stack
if cs!=nil
count=state_stack_count(cs[:state])
cost=cs[:count]||-1
return false unless count>0&&count>=cost
end
skill_cost_payable_b1f2b6?(skill)
end
alias pay_skill_cost_b1f2b6 pay_skill_cost
def pay_skill_cost(skill)
pay_skill_cost_b1f2b6(skill)
cs=skill.consume_stack
if cs!=nil
cost=cs[:count]||-1
if cost<0
cost=state_stack_count(cs[:state])
end
@@last_state_cost=cost
decrease_state_stack(cs[:state], cost)
end
end
def last_state_cost
@@last_state_cost
end
end
class Game_Battler
alias reset_state_counts_b1f2b6 reset_state_counts
def reset_state_counts(state_id)
reset_state_counts_b1f2b6(state_id)
state = $data_states[state_id]
if state.stackable?
if @state_stacks[state_id]==nil
@state_stacks[state_id]=0
end
if state.max_stack<=0||@state_stacks[state_id]<state.max_stack
@state_stacks[state_id]+=1
end
end
end
alias on_action_end_b1f2b6 on_action_end
def on_action_end
on_action_end_b1f2b6
@@last_state_cost=nil
end
end
STACK_COUNT_FONT_SIZE=14
STACK_COUNT_FONT=Font.new
STACK_COUNT_FONT.size=STACK_COUNT_FONT_SIZE
STACK_COUNT_FONT.color=Color.new(0,255,0)
STACK_COUNT_FONT.bold=true
STACK_COUNT_FONT.outline=false
STACK_COUNT_FONT.shadow=true
class Window_Base
alias draw_actor_icons_b1f2b6 draw_actor_icons
def draw_actor_icons(actor, x, y, width = 96)
draw_actor_icons_b1f2b6(actor, x, y, width)
last_font=contents.font
last_size=last_font.size
last_bold=last_font.bold
contents.font=STACK_COUNT_FONT
actor.states.select{|s|s.icon_index!=0}.each_with_index {|s, i|
if s.stackable?
count=actor.state_stack_count(s.id)
contents.draw_text(x, y+1, 22, STACK_COUNT_FONT_SIZE, count, 2)
end
}
contents.font=last_font
contents.font.size=last_size
contents.font.bold=last_bold
end
end