大概在SEP Core里实现了自己的思路,并且避免了一些前述讨论中发现的问题 
 
装备附带(也包括以后扩展附带)的状态不再走add和remove逻辑,而是从装备中直接统计 
#--------------------------------------------------------------------------   # ● 获取额外状态(非附身但有效)   #--------------------------------------------------------------------------   def extra_states     set = armors.map {|a| a.auto_state_id} - [0]     i = 0     while i < set.size       set |= $data_states[set[i]].plus_state_set       i += 1     end     set.reject {|i| $data_states[i].zero_hp}   end 
 
 #--------------------------------------------------------------------------  
  # ● 获取额外状态(非附身但有效)  
  #--------------------------------------------------------------------------  
  def extra_states  
    set = armors.map {|a| a.auto_state_id} - [0]  
    i = 0  
    while i < set.size  
      set |= $data_states[set[i]].plus_state_set  
      i += 1  
    end  
    set.reject {|i| $data_states[i].zero_hp}  
  end  
 
  
自动状态就是你设置的状态以及该状态所有+的状态,可以连锁+,反正都会并进来 
注意XP在这里有一个编辑器约束,即(作为HP0的状态)是不可能被认定为防具自动状态的,在各种狂野模式备注,各种连锁附加的情况下,这里的最后一步还原了这个约束,保证游戏逻辑的正确。 
 
如果要增加技能附带、职业附带状态,就可以更改这里的定义。 
(在目前正在开发的基于SEP core的战斗类插件中,所有VA/MV的traits全部是定义在角色/敌人(固有)和状态(修正)上面的,这也是为了在设定的时候更符合习惯,但是技能和职业这种身外之物要附带traits,就只能通过类似自动状态的逻辑来附加,没法像VA那样直接设置) 
 
获取身上的有效状态使用reader方法,该方法会覆盖原本的attr_reader默认方法 
#--------------------------------------------------------------------------   # ● 获取状态   #--------------------------------------------------------------------------   def states     return @states_cache if @states_cache     extras = extra_states     denies = extras.inject([]) {|a, i| a |= $data_states[i].minus_state_set}     @states_cache = (@states - denies | extras).sort_by do |i|       s = $data_states[i]       [-s.rating, -s.restriction, i]     end   end 
 
 #--------------------------------------------------------------------------  
  # ● 获取状态  
  #--------------------------------------------------------------------------  
  def states  
    return @states_cache if @states_cache  
    extras = extra_states  
    denies = extras.inject([]) {|a, i| a |= $data_states[i].minus_state_set}  
    @states_cache = (@states - denies | extras).sort_by do |i|  
      s = $data_states[i]  
      [-s.rating, -s.restriction, i]  
    end  
  end  
 
  
由于状态调用委实过于频繁,采用了缓存的技术思路,防止反复取值时无意义地遍历装备、重新对状态排序等。当然代价就是缓存需要手工清除。 
 
换装备时若触发自动状态更新,只是简单的清掉状态缓存,可以看到脱钩了人物本身状态后,update_auto_state现在变得非常简单(默认系统的update_auto_state调用在实际换装以前,这样改的话没有问题),换装后任何试图读取states的方法(比如取能力值)都会重建缓存,fix_hp里面会取到maxhp,即会重建缓存,如此bug1和2被自动修复。 
#--------------------------------------------------------------------------   # ● 更新自动状态   #     old_equip : 卸下防具   #     new_equip : 装备防具   #--------------------------------------------------------------------------   def update_auto_state(old_equip, new_equip)     @states_cache = nil unless old_equip == new_equip   end   #--------------------------------------------------------------------------   # ● 变更装备   #     equip_type : 装备类型   #     id    : 武器 or 防具 ID  (0 为解除装备)   #--------------------------------------------------------------------------   def_after :equip do |equip_type, id|     fix_hp     fix_sp   end 
 
 #--------------------------------------------------------------------------  
  # ● 更新自动状态  
  #     old_equip : 卸下防具  
  #     new_equip : 装备防具  
  #--------------------------------------------------------------------------  
  def update_auto_state(old_equip, new_equip)  
    @states_cache = nil unless old_equip == new_equip  
  end  
  #--------------------------------------------------------------------------  
  # ● 变更装备  
  #     equip_type : 装备类型  
  #     id    : 武器 or 防具 ID  (0 为解除装备)  
  #--------------------------------------------------------------------------  
  def_after :equip do |equip_type, id|  
    fix_hp  
    fix_sp  
  end  
 
  
 
状态的两个检定用方法:这里将本来取@states的地方取成了states,并且所有取能力值的地方也同样都这么改了,共11处(状态在XP里默认能加成11项能力),就不列了,因为现在@states仅仅只是身上通过事件、战斗等方式附加上的实体状态,并不等同于身上的有效状态。特别要说明的是state_full?这个方法,这是覆写同一状态时用到的检定,由于自动状态里可能包括连锁-的状态,原来的逻辑中当换装时,连锁-的状态就会被清除掉。现在换装不走add_state,连锁-的状态就不会被清除,但按照游戏原本的正常逻辑,它却不是身上的有效状态。即,附加的实体状态在state?里检定不出来,因此state_full?检定中除了原先的state?调用外还加上了@states.include?调用(这个就是原始的state?逻辑),为什么不直接只写@states.include?是因为自动状态也是true,至于为什么保留回合==-1的逻辑下面谈。 
#--------------------------------------------------------------------------   # ● 检查状态   #     state_id : 状态 ID   #--------------------------------------------------------------------------   def state?(state_id)     states.include?(state_id)   end   #--------------------------------------------------------------------------   # ● 判断状态是否已满   #     state_id : 状态 ID   #--------------------------------------------------------------------------   def state_full?(state_id)     return false unless state?(state_id) or @states.include?(state_id)     return true if extra_states.include?(state_id)     return true if @states_turn[state_id] == -1     @states_turn[state_id] == $data_states[state_id].hold_turn   end 
 
 #--------------------------------------------------------------------------  
  # ● 检查状态  
  #     state_id : 状态 ID  
  #--------------------------------------------------------------------------  
  def state?(state_id)  
    states.include?(state_id)  
  end  
  #--------------------------------------------------------------------------  
  # ● 判断状态是否已满  
  #     state_id : 状态 ID  
  #--------------------------------------------------------------------------  
  def state_full?(state_id)  
    return false unless state?(state_id) or @states.include?(state_id)  
    return true if extra_states.include?(state_id)  
    return true if @states_turn[state_id] == -1  
    @states_turn[state_id] == $data_states[state_id].hold_turn  
  end  
 
  
 
重头戏来了:状态的附加过程,基本上是原先的逻辑,简化了一些代码,例如不再进行movable?的判定而是直接写restriction == 4(movable?会判定身上所有状态,没必要,清行动肯定是因为附加的当前状态将restriction提到了4啊),这里的接口force没有改,force时回合设为-1的逻辑也没有改,但实际上系统内部update_auto_state改了之后,已经不可能再用force=true来调这个方法了。但用户可能会用事件脚本来调这个方法,接口必须留下。而且这是一个对于游戏非常有用的feature:剧情来源的自动状态(比如难度选简单后atk, pdef, mdef都*110%,困难则都*90%)。因为剧情来源的自动状态没法绑定到角色身上的东西,只能让它真实附加到角色身上。而为了防止它被意外解除掉(完全回复或事件解除),做成自动状态是最简单的办法。连锁附加和连锁解除都将force给递归传了进去,确保逻辑不出问题。这种状态虽然不能被彻底解除,但通过装备自动状态对其打-,可以在装了某装备的时候暂时屏蔽掉,这也是应有之意,如用特定装备抵消剧情带来的队伍debuff(原系统连锁解除时不传递force进去,便无法做到屏蔽,而且它也没法屏蔽啊,一屏蔽就真解除了),参考前面取states时候的逻辑。 
#--------------------------------------------------------------------------   # ● 附加状态   #     state_id : 状态 ID   #     force    : 强制附加标志   #--------------------------------------------------------------------------   def add_state(state_id, force = false)     # 无效状态的情况下,过程结束     return unless state = $data_states[state_id]     # 不是强制附加,且状态被当前状态抵抗的情况下,过程结束     return if not force and states.any? {|i|       $data_states[i].minus_state_set.include?(state_id) and       not $data_states[state_id].minus_state_set.include?(i)}     # 并未附加本状态(任何来源)的情况下     unless state?(state_id) or @states.include?(state_id)       # 清除状态缓存       @states_cache = nil       # 附加状态       @states.push(state_id)       # HP 0的检查更改       @hp = 0 if state.zero_hp       # 限制不行动的检查更改       @current_action.clear if state.restriction == 4       # 状态变化 (+) (-) 处理       state.plus_state_set.each {|i| add_state(i, force)}       state.minus_state_set.each {|i| remove_state(i, force)}       # 修正当前 HP 及 SP       fix_hp       fix_sp     end     # 按强制附加与否设置解除回合数     if @states.include?(state_id)       @states_turn[state_id] = force ? -1 : state.hold_turn     end   end 
 
 #--------------------------------------------------------------------------  
  # ● 附加状态  
  #     state_id : 状态 ID  
  #     force    : 强制附加标志  
  #--------------------------------------------------------------------------  
  def add_state(state_id, force = false)  
    # 无效状态的情况下,过程结束  
    return unless state = $data_states[state_id]  
    # 不是强制附加,且状态被当前状态抵抗的情况下,过程结束  
    return if not force and states.any? {|i|  
      $data_states[i].minus_state_set.include?(state_id) and  
      not $data_states[state_id].minus_state_set.include?(i)}  
    # 并未附加本状态(任何来源)的情况下  
    unless state?(state_id) or @states.include?(state_id)  
      # 清除状态缓存  
      @states_cache = nil  
      # 附加状态  
      @states.push(state_id)  
      # HP 0的检查更改  
      @hp = 0 if state.zero_hp  
      # 限制不行动的检查更改  
      @current_action.clear if state.restriction == 4  
      # 状态变化 (+) (-) 处理  
      state.plus_state_set.each {|i| add_state(i, force)}  
      state.minus_state_set.each {|i| remove_state(i, force)}  
      # 修正当前 HP 及 SP  
      fix_hp  
      fix_sp  
    end  
    # 按强制附加与否设置解除回合数  
    if @states.include?(state_id)  
      @states_turn[state_id] = force ? -1 : state.hold_turn  
    end  
  end  
 
  
这里有一个我并不打算修复的"bug":若状态A连锁+状态B和C,状态B和C彼此连锁-,则最后附加的状态(不论是不是强制附加)除了A以外,要看B和C的ID号哪个在前,在前的会被解除掉。默认脚本里就是这样,现在改了之后还是这样。我觉得这个是自己数据库设置的问题,状态B和C既然彼此连锁-,那本来逻辑上就不应该同时共存,都被A连锁+上你是想要闹哪样? 
比如加速50%和减速50%,逻辑上互相抵销,但因为XP的状态能力乘算原理,如果真的都同时附加上,结果会是速度变成原来的(150%*50%)=75%,相当于半个减速。 
不过,如果装备的自动状态A,满足上述条件的话,则确实目前会把A、B、C都处理成自动状态,也问问大家,虽然这个"bug"我是不打算修,但如果希望逻辑弄成一致,那倒确实是可以的。 
 
 
状态的移除过程:基本直接copy代码,注意装备来的自动状态不在@states里面,是没法移除的,因装备自动状态被屏蔽掉的本体状态却在@states里面,是可以移除的,所以能不能移除只需要检查实体状态,有并能移除就移除。HP0的检查移到状态实际被删除之后,简化很多判断。最重要的是添加了连锁附加的状态连锁移除的过程。 
#--------------------------------------------------------------------------   # ● 解除状态   #     state_id : 状态 ID   #     force    : 强制解除标志 (处理自动状态时使用)   #--------------------------------------------------------------------------   def remove_state(state_id, force = false)     # 无效状态的情况下,过程结束     return unless state = $data_states[state_id]     # 战斗者本体未附加本状态的情况下,过程结束     return unless @states.include?(state_id)     # 被强制附加的状态、并不是强制解除的情况下,过程结束     return if @states_turn[state_id] == -1 and not force     # 清除状态缓存     @states_cache = nil     # 删除本体状态     @states.delete(state_id)     @states_turn.delete(state_id)     # HP 0的检查更改     if @hp == 0 and state.zero_hp and states.all? {|i|        not $data_states[i].zero_hp}       @hp = 1     end     # 强制解除的情况下,同样解除连锁附加的状态     state.plus_state_set.each {|i| remove_state(i, true)} if force     # 修正当前 HP 及 SP     fix_hp     fix_sp   end 
 
 #--------------------------------------------------------------------------  
  # ● 解除状态  
  #     state_id : 状态 ID  
  #     force    : 强制解除标志 (处理自动状态时使用)  
  #--------------------------------------------------------------------------  
  def remove_state(state_id, force = false)  
    # 无效状态的情况下,过程结束  
    return unless state = $data_states[state_id]  
    # 战斗者本体未附加本状态的情况下,过程结束  
    return unless @states.include?(state_id)  
    # 被强制附加的状态、并不是强制解除的情况下,过程结束  
    return if @states_turn[state_id] == -1 and not force  
    # 清除状态缓存  
    @states_cache = nil  
    # 删除本体状态  
    @states.delete(state_id)  
    @states_turn.delete(state_id)  
    # HP 0的检查更改  
    if @hp == 0 and state.zero_hp and states.all? {|i|   
      not $data_states[i].zero_hp}  
      @hp = 1  
    end  
    # 强制解除的情况下,同样解除连锁附加的状态  
    state.plus_state_set.each {|i| remove_state(i, true)} if force  
    # 修正当前 HP 及 SP  
    fix_hp  
    fix_sp  
  end  
 
  
 
其他零星修改:除了取能力值都要改成states以外,以下一些方法也得改。记住@states是身上的实体状态,(self.)states是身上的有效状态,两者既不等同,也不是子集关系就行。完全回复的那个bug犯的真的非常之蠢,只要将hp/sp的复设挪到状态被清除之后马上就可以了。 
#--------------------------------------------------------------------------   # ● 获取状态的动画 ID   #--------------------------------------------------------------------------   def state_animation_id     states.empty? ? 0 : $data_states[states[0]].animation_id   end   #--------------------------------------------------------------------------   # ● 获取限制   #--------------------------------------------------------------------------   def restriction     states.empty? ? 0 : states.max_by {|i| $data_states[i].restriction}   end   #--------------------------------------------------------------------------   # ● 判断状态 [无法获得 EXP]、[无法回避攻击]、[连续伤害]   #--------------------------------------------------------------------------   def cant_get_exp?;  states.any? {|i| $data_states[i].cant_get_exp};     end   def cant_evade?;    states.any? {|i| $data_states[i].cant_evade};       end   def slip_damage?;   states.any? {|i| $data_states[i].slip_damage};      end   #--------------------------------------------------------------------------   # ● 状态变化 (+) 的适用   #     plus_state_set  : 状态变化 (+)   #--------------------------------------------------------------------------   def states_plus(plus_state_set)     # 清除有效标志     effective = false     # 循环 (附加状态)     for i in plus_state_set       # 防御本状态的情况下,跳过       next if state_guard?(i)       # 非满状态的情况下,设置有效标志       effective |= !state_full?(i)       # 状态为 [不能抵抗],或状态非满且概率判定通过的情况下       if $data_states[i].nonresistance or (not state_full?(i) and         rand(100) < state_table[state_ranks[i]])         # 设置状态变化标志         @state_changed = true         # 附加状态         add_state(i)       end     end     # 过程结束     return effective   end   #--------------------------------------------------------------------------   # ● 状态变化 (-) 的使用   #     minus_state_set : 状态变化 (-)   #--------------------------------------------------------------------------   def states_minus(minus_state_set)     # 清除有效标志     effective = false     # 循环 (解除状态)     for i in minus_state_set       # 状态被实际附加的情况下,设置有效标志       effective |= @states.include?(i)       # 设置状态变化标志       @state_changed = true       # 解除状态       remove_state(i)     end     # 过程结束     return effective   end   #--------------------------------------------------------------------------   # ● 全回复   #--------------------------------------------------------------------------   def recover_all     @states.reject! {|i| @states_turn[i] >= 0}     @states_turn.reject! {|k, v| v >= 0}     @states_cache = nil     @hp = maxhp     @sp = maxsp   end 
 
 #--------------------------------------------------------------------------  
  # ● 获取状态的动画 ID  
  #--------------------------------------------------------------------------  
  def state_animation_id  
    states.empty? ? 0 : $data_states[states[0]].animation_id  
  end  
  #--------------------------------------------------------------------------  
  # ● 获取限制  
  #--------------------------------------------------------------------------  
  def restriction  
    states.empty? ? 0 : states.max_by {|i| $data_states[i].restriction}  
  end  
  #--------------------------------------------------------------------------  
  # ● 判断状态 [无法获得 EXP]、[无法回避攻击]、[连续伤害]  
  #--------------------------------------------------------------------------  
  def cant_get_exp?;  states.any? {|i| $data_states[i].cant_get_exp};     end  
  def cant_evade?;    states.any? {|i| $data_states[i].cant_evade};       end  
  def slip_damage?;   states.any? {|i| $data_states[i].slip_damage};      end  
  #--------------------------------------------------------------------------  
  # ● 状态变化 (+) 的适用  
  #     plus_state_set  : 状态变化 (+)  
  #--------------------------------------------------------------------------  
  def states_plus(plus_state_set)  
    # 清除有效标志  
    effective = false  
    # 循环 (附加状态)  
    for i in plus_state_set  
      # 防御本状态的情况下,跳过  
      next if state_guard?(i)  
      # 非满状态的情况下,设置有效标志  
      effective |= !state_full?(i)  
      # 状态为 [不能抵抗],或状态非满且概率判定通过的情况下  
      if $data_states[i].nonresistance or (not state_full?(i) and  
        rand(100) < state_table[state_ranks[i]])  
        # 设置状态变化标志  
        @state_changed = true  
        # 附加状态  
        add_state(i)  
      end  
    end  
    # 过程结束  
    return effective  
  end  
  #--------------------------------------------------------------------------  
  # ● 状态变化 (-) 的使用  
  #     minus_state_set : 状态变化 (-)  
  #--------------------------------------------------------------------------  
  def states_minus(minus_state_set)  
    # 清除有效标志  
    effective = false  
    # 循环 (解除状态)  
    for i in minus_state_set  
      # 状态被实际附加的情况下,设置有效标志  
      effective |= @states.include?(i)  
      # 设置状态变化标志  
      @state_changed = true  
      # 解除状态  
      remove_state(i)  
    end  
    # 过程结束  
    return effective  
  end  
  #--------------------------------------------------------------------------  
  # ● 全回复  
  #--------------------------------------------------------------------------  
  def recover_all  
    @states.reject! {|i| @states_turn[i] >= 0}  
    @states_turn.reject! {|k, v| v >= 0}  
    @states_cache = nil  
    @hp = maxhp  
    @sp = maxsp  
  end  
 
  
 
以上,对Game_Battler 2的重写基本就是这样。 |