今更ながらRPGツクールXPのRGSSのバグについて

#はじめに

※参考にしたサイトがアクセス不能になったため、リンクを解除（2018/5/8追記）
※厳密にはRGSSのバグではなく、初期状態のScripts.rxdataに存在するバグですが、表現として通りの良いタイトルにしてあります。（2018/2/17追記）

RPGTKOOLXP/RGSS Wiki ~~http://tkool.web-ghost.net/wiki/wiki.cgi~~（※アクセス不能）
RPGツクールXPVer1.02に含まれるRGSSのバグ ~~http://p-sight.net/Annex/bugs/~~（※以下「★参考」の形で言及／アクセス不能）

この辺で指摘されたRPGツクールXPのバグの話です。
VXやVX Aceはスクリプトの修正が配信されましたが、XPは何もないままですね。 ~~★参考では、現在も修正スクリプトをダウンロードすることができますが、~~ 微細ながら修正点が異なるスクリプトを用意しました。

#修正スクリプトについて

[RMXPfanpatch.rb](https://gist.github.com/DICE2000/f6b452de1ae84e007f974ad0c8fc4bd7)
Scene_Debugの直後に導入してください。他の「RPGツクールXPのバグを修正する」スクリプトと競合する可能性が極めて高いので、併用は避けてください。修正点は下記の5点のみで、軽量化などは含みません。

#修正点の解説

##戦闘時スキルのバグ

###1. 命中率が99%以下になると一切の攻撃スキルが命中しなくなるバグ

```ruby:Game_Battler修正前.rb
    # 第一命中判定
    hit = skill.hit
    if skill.atk_f > 0
      hit *= user.hit / 100
    end
    hit_result = (rand(100) < hit)
```

skill.atk_fはスキルの「攻撃力F」で、1以上であれば物理攻撃スキル扱いになります（第一命中判定が行われる）。ですが、user.hit(Game_Battler#hit)はint型なので、100で除算すると100未満は0になります。そのまま自己代入で乗算するためhitも0になってしまいます。
これについては、★参考で採用された三項演算子による修正をそのまま適用しました。

```ruby:Game_Battler修正後.rb
    # 第一命中判定
    hit = skill.atk_f > 0 ? skill.hit * user.hit / 100 : skill.hit
    hit_result = (rand(100) < hit)
```

###2. スキルの威力が0に設定されている場合、ダメージを与えても「Miss」と表示されるバグ

skill_effectのコメントをよくよく読むと、メソッド中の変数「power」（威力）を、スキルの「skill.power」（威力）と取り違えてしまったようなんですね。というわけで、下記のような修正が正しいものと思われます。★参考は条件分岐を書き換えているので、ステート衝撃解除の条件が変わっています。

```ruby:Game_Battler修正後.rb
      # 威力 0 以外の物理攻撃の場合
      if power != 0 and skill.atk_f > 0 #<= 修正前 if skill.power != 0 and skill.atk_f > 0
        # ステート衝撃解除
        remove_states_shock
        # 有効フラグをセット
        effective = true
      end
      # （～中略～）
      # 威力が 0 の場合
      if power == 0 #<= 修正前 if skill.power == 0
        # ダメージに空文字列を設定
        self.damage = ""
        # ステートに変化がない場合
        unless @state_changed
          # ダメージに "Miss" を設定
          self.damage = "Miss"
        end
      end
```

##インタプリタのバグ

###3. イベントコマンドの「条件分岐」のアクターが特定の防具を装備している場合の処理に不備があるバグ

簡単に見つかるので有名な（？）バグだったように思います。修正方法も簡単です。

```ruby:Interpreter修正後.rb
   when 4 # 防具
     result = (actor.armor1_id == @parameters[3] or
       actor.armor2_id == @parameters[3] or
       actor.armor3_id == @parameters[3] or actor.armor4_id == @parameters[3])   #<= 追加
```

###4. イベントコマンドの「スクリプト」の一行目がfalseになるとフリーズするバグ

スクリプト素材を追加して制作していると出くわしやすいバグだったと思います。
インタプリタの各コマンドについては、falseで返る前には必ずインデックスを進めないといけません。ところが「スクリプト」の定義だけ何故かインデックスを進めるタイミングが妙なことになっています。下記のように、スクリプトが読み出された直後にインデックスを進めた方が分かりやすいように思います。

ただし、インタプリタがtrueで返る際にはインデックスを進める必要がないので、進みすぎたインデックスを戻す必要があります。（2018/3/6追記）

```ruby:Interpreter修正後.rb
  #--------------------------------------------------------------------------
  # ● スクリプト
  # イベントコマンドの「スクリプト」の一行目がfalseになると
  # フリーズするバグの修正
  #--------------------------------------------------------------------------
  def command_355
    # script に 1 行目を設定
    script = @list[@index].parameters[0] + "\n"
    # インデックスを増やす（修正）
    @index += 1
    # ループ
    loop do
      # 次のイベントコマンドがスクリプト 2 行目以降の場合（修正）
      if @list[@index].code == 655
        # script に 2 行目以降を追加
        script += @list[@index].parameters[0] + "\n"
        # インデックスを進める
        @index += 1
      # イベントコマンドがスクリプト 2 行目以降ではない場合
      else
        # ループ中断
        break
      end
    end
    # 評価
    result = eval(script)
    # 戻り値が false の場合
    if result == false
      # 終了
      return false
    end
    # 戻り値がfalseでない場合、インデックスを戻す
    @index -= 1
    # 継続
    return true
  end
```

##マップイベントのバグ

###5.イベントの自律移動の判定バグ

これはRPGTKOOLXP/RGSS Wikiで指摘され、★参考では指摘されていないバグです。マップイベントの自律移動が「近づく」の時、プレイヤーとイベントの距離の判定が正常に行われていません。

```ruby:Game_Character修正後.rb
class Game_Character
  #--------------------------------------------------------------------------
  # ● 移動タイプ : 近づく
  # 求めた絶対値を判定に使用していないバグの修正
  #--------------------------------------------------------------------------
  def move_type_toward_player
    # プレイヤーの座標との差を求める
    sx = @x - $game_player.x
    sy = @y - $game_player.y
    # 差の絶対値を求める
    abs_sx = sx > 0 ? sx : -sx
    abs_sy = sy > 0 ? sy : -sy
    # 縦横あわせて 20 タイル以上離れている場合（修正）
    if abs_sx + abs_sy >= 20 #<= 修正前 if sx + sy >= 20
      # ランダム
      move_random
      return
    end
    # 乱数 0～5 で分岐
    case rand(6)
    when 0..3  # プレイヤーに近づく
      move_toward_player
    when 4  # ランダム
      move_random
    when 5  # 一歩前進
      move_forward
    end
  end
end
```

#おわりに

というより、余談。むかーし、RPGTKOOLXP/RGSS Wikiの掲示板で、RPGツクールXPだと特定のメソッド名でC++のバグが出るというのを見たんですが、その名前を忘れました。どなたか覚えてないですかね。