鳥小屋.txt

主に自作ゲームをつくったりしているよ。制作に関することやそうじゃないことのごった煮ブログ

【古いよ】戦闘不能メンバー自動入れ替えさん for MV

↓ イカした新しいバージョンをつくりました ↓

今後は↑のページからダウンロードできる新しいほうを使ってくださいー。


以下古いバージョンの記事です。


  • 2017/01/21 ひきも記さんの先頭並び替え不可プラグイン(TMTopFix.js)に対応しました
  • 2015/11/04 パーティメンバーが少ないときにエラーするのを修正しました

プラグイン概要

戦闘中に戦闘不能になったメンバーが発生したとき、控えのメンバーと自動的に入れ替えます。

使用方法

設定は特にありません。プラグイン設定からONにするだけで動きます。

プラグインのダウンロード

ReplaceDeadMember MV - 戦闘不能メンバー自動入れ替えさん for MV

右クリック→「名前をつけて保存」したものを plugins フォルダに入れてご利用ください。

利用規約

RPGツクールMV(RPG Maker MV)内での使用の場合は自由に使用できます。
有償、改変配布など、制限項目はありません。

ターン消費なしスキルさん for MV(2019/08/24更新)

RPGツクールMZ用は ↓ こちらのページで公開しています。

このページでは、RPGツクールMV用のターン消費なしスキルを公開しています。


  • 2020/05/06 アドオンを追加
  • 2019/08/24 戦闘の中断などを行うと次の戦闘で正常に動作しなくなるのを修正
  • 2019/06/26 NumbState.js併用時にエラーが発生しないように
  • 2019/03/23 YEPBattleCore使用時に行動後にモーションが待機状態に戻ってしまうのを修正
  • 2019/02/03 サイドビュー時、行動後にモーションが待機状態に戻ってしまうのを修正
  • 2018/12/29 やなさんの連携発動スキル(ChainInvokeSkill.js)の競合対応コードを追加
  • 2018/07/01 プラグインの設定に行動回数の再計算を行うかオプションを追加
  • 2018/05/16 「バトルの中断」を呼び出すとバトルが終わらなくなるのを修正
    また、「戦闘行動の強制」を呼び出した場合はエラーを吐くことがあるのを修正
  • 2018/05/01 コモンイベントでステートを変更した際にステータスウィンドウに表示が反映されないのを修正
  • 2017/05/02 「戦闘行動の強制」に仮対応しました(うごかないかも)
  • 2017/01/21 ターン消費なしスキル使用時にアクターが行動不能になった場合、行動選択ウィンドウがおかしくなる不具合を修正しました
  • 2016/03/03 コモンイベントが実行されないのを修正+「ステート追加/削除スキルプラグイン」をはじめとしたいくつかのプラグインとの競合を修正しました
  • 2016/02/20 複数回行動できるキャラクターの場合、正常に動作しないのを修正しました。
  • 2016/01/31 「戦闘中セリフ表示さん」との競合を修正。両方とも更新が必要です><;
  • 2015/12/06 トドメを刺した際に勝利モーションが一瞬しか再生されないのを修正しました

プラグイン概要

スキル/アイテムを選択した瞬間に、ターンを消費せず発動できるようにします。

RGSS3版ターン消費なしスキル を元にRPGツクールMV用に作りなおしたものです。

RGSS3版からの変更点

RGSS3版ではターン消費なしスキルスクリプト自体に様々な機能が入っていましたが、競合のこととか考えるとあまりよくないので基本機能を最低限に絞っています。

  • 味方のみ対応です。敵はターン消費なしになりません。
  • 1ターン内の回数制限の設定機能はありません。別プラグインを使用してください。

使用方法

ターン消費なし性能を持たせたいスキル/アイテムのメモ欄に以下のように書いてください。

<QuickSkill>

例:
f:id:ru_shalm:20151029031704p:plain

上級者向けオプション

行動回数の再計算について

プラグインの設定で、行動回数の再計算を行うかどうかを指定できます。

ターン消費なしスキルはデフォルトでは、行動回数増加系のステートなどがついたとしても、
行動回数は元のままにするようにしています。

  • 「50%の確率で行動回数が2回」のような設定をしているときに確率がおかしくなる
  • すでに行動選択済みのキャラクターの行動回数が増えたり減ったりするときつい

という理由のため、再計算をしていません。

が、ゲームによっては再計算をしたほうが良い場合もあるとおもうため、
プラグインの設定で再計算をさせられるようにしています。
ただし、回数が増える方向のみ反映されます。2回動けたはずが1回に!などはできません。

  • なし
    • 再計算をしません(デフォルト)
  • 使用者のみ
    • ターン消費なしスキルを使ったキャラのみ再計算します
  • 味方全員
    • パーティキャラクター全員再計算します
    • 敵は再計算しません

プラグインのダウンロード

QuickSkill - ターン消費なしスキルさん for MV

右クリック→「名前をつけて保存」したものを plugins フォルダに入れてご利用ください。

ターン消費なしスキルさんのアドオン

「ターン消費なしスキルさん」の一部機能を変化させる追加アドオンです。
アドオンだけでは動作しません。必ず Torigoya_QuickSkill より下に導入してください

スキル使用後、スキル選択画面に戻るようにするアドオン

ターン消費なしスキル使用後、行動選択ではなくスキル選択画面に戻すアドオンです。 ※注意:性質上、他のプラグインとの競合が起こりやすいです

Torigoya_QuickSkill_Addon_OpenSkillWindow.js ダウンロード

利用規約

RPGツクールMV(RPG Maker MV)内での使用の場合は自由に使用できます。
有償、改変配布など、制限項目はありません。著作表示もご自由にどうぞ。

第9羽「青山ツクールマウンテン」

この投稿は「ごちうさ住民 Advent Calendar 2014」の9日目の記事です。

昨日はkazuheiさんの『私の所持金52円!!』でした。
雑コラメーカーのスマホ対応、心よりお待ちしております(チラッチラッ


ごちうさ1羽コメントスクリプトさん for RGSS3

概要

RPGツクールVX Ace(RGSS3)用のスクリプト素材です。
ゲーム画面にニコニコ動画の『ご注文はうさぎですか? 第1羽「ひと目で、尋常でないもふもふだと見抜いたよ」』のコメントを表示します。

f:id:ru_shalm:20141208005237p:plain

f:id:ru_shalm:20141208005245p:plain

f:id:ru_shalm:20141208235409p:plain

利用規約

いつも通りテキトーにどうぞ。許諾も表記も何もナシでOKです。
ただし、画面に流れるコメントにはそれぞれ権利があるのでご注意ください。

なお、本スクリプトに関しては完全に一切のサポートを行いません。よろしくお願いします(ぺこり)

スクリプト

# coding: utf-8
#===============================================================================
# ■ ごちうさ1羽コメントスクリプトさん for RGSS3
#-------------------------------------------------------------------------------
# 2014/12/09 Ru/むっくRu (@ru_shalm)
#-------------------------------------------------------------------------------
# ゲーム画面にニコニコ動画の
# 『ご注文はうさぎですか? 第1羽「ひと目で、尋常でないもふもふだと見抜いたよ」』の
# コメントを表示します。
#===============================================================================

module Torigoya
  module Base64
    def self.encode(str)
      [str].pack('m*')
    end

    def self.decode(str)
      str.unpack('m*').join
    end
  end
end

module Torigoya
  module Win32
    INTERNET_OPEN_TYPE_PRECONFIG = 0
    INTERNET_SERVICE_HTTP = 3

    def self.internet_open
      ::Win32API.new('wininet.dll', 'InternetOpen', %w(p l p p l), 'l')
    end

    def self.internet_connect
      ::Win32API.new('wininet.dll', 'InternetConnect', %w(p p l p p l l l), 'l')
    end

    def self.http_open_request
      ::Win32API.new('wininet.dll', 'HttpOpenRequest', %w(p p p p p p l l), 'l')
    end

    def self.http_send_request
      ::Win32API.new('wininet.dll', 'HttpSendRequest', %w(p p l p l), 'i')
    end

    def self.internet_read_file
      ::Win32API.new('wininet.dll', 'InternetReadFile', %w(l p l p), 'l')
    end

    def self.internet_close_handle
      ::Win32API.new('wininet.dll', 'InternetCloseHandle', %w(l), 'l')
    end
  end
end

module Torigoya
  class URI
    # URLエンコード
    # @param [String] str
    # @return [String]
    def self.encode(str)
      str.to_s.gsub(/([^A-Za-z0-9\-_\.!\~\*\'\(\);\/\?\:@&=\+\$,\[\]])/) do
        '%' + $1.unpack('H*').join('').scan(/.{2}/).join('%').upcase
      end
    end

    def self.parse(uri)
      self.new(uri)
    end

    def initialize(uri)
      /\A(?<scheme>[^:]+):\/\/(?<host>[^\/:]+)(?::(?<port>\d+))?(?<path>\/[^\?]*)?(?:\?(?<query>.*))?\z/ =~ uri
      @scheme = scheme.downcase
      @host = host
      @port = (port || default_port).to_i
      @path = path || '/'
      @query = query || ''
    end
    attr_reader :scheme
    attr_reader :host
    attr_reader :port
    attr_reader :path
    attr_reader :query

    private
    def default_port
      case self.scheme
      when 'http'
        80
      when 'https'
        443
      else
        raise 'unknown scheme'
      end
    end
  end

  module Http
    def self.client
      @client ||= Client.new
    end

    class Client
      SESSION_NAME = 'Torigoya RGSS'

      def get(uri, params = {}, headers = [])
        request('GET', uri, params, headers)
      end

      def post(uri, params = {}, headers = [])
        request('POST', uri, params, headers)
      end

      private
      def request(method, uri_str, params = {}, headers = [])
        uri = URI.parse(uri_str)
        payload = nil
        result_body = []

        headers.push "Host: #{uri.host}"
        if params.kind_of?(String)
          path = uri.path
          payload = params
        else
          if method == 'GET'
            # TODO: uri.queryとdeep_mergeしましょう
            query = convert_query(params)
            path = "#{uri.path}?#{query}"
          else
            query = convert_query(params)
            path = "#{uri.path}#{uri.query ? "?#{uri.query}" : ''}"
            payload = params
          end
        end

        begin
          handle = Torigoya::Win32.internet_open.call(SESSION_NAME, Torigoya::Win32::INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0)
          http_session = Torigoya::Win32.internet_connect.call(handle, uri.host, uri.port, nil, nil, Torigoya::Win32::INTERNET_SERVICE_HTTP, 0, 0)
          http_request = Torigoya::Win32.http_open_request.call(http_session, method, path, nil, nil, nil, 0, 0)
          Torigoya::Win32.http_send_request.call(http_request, headers.join("\n"), -1, payload, (payload ? payload.size : 0))

          while true
            buf = "\0" * 10240
            read_size = "\0" * 4 # DWORD
            break if Torigoya::Win32.internet_read_file.call(http_request, buf, buf.size, read_size) && (size = read_size.unpack('i*')[0]) == 0
            result_body.push buf[0, size]
          end
        rescue => e
          puts e.inspect
          puts $@
          result_body = []
        ensure
          Torigoya::Win32.internet_close_handle.call(http_request) if http_request
          Torigoya::Win32.internet_close_handle.call(http_session) if http_session
          Torigoya::Win32.internet_close_handle.call(handle) if handle
        end

        result_body.join
      end

      def convert_query(params = {})
        params.to_a.map { |n| n.map { |n| URI.encode(n) }.join('=') }.join('&')
      end
    end
  end
end

module Torigoya
  module PoorXml
    # 超簡易XMLパーサー
    # - UTF-8以外読み込ませちゃダメ
    # - コメント(<!-- -->)を含むやつもダメ
    # - というかいろいろ読めない
    class Parser
      # 初期化
      # @param [String] raw_doc XMLテキスト
      def initialize(raw_doc)
        @raw_doc = raw_doc
      end

      # パース処理
      # @return [Node] XMLのrootノード
      def parse
        buffer = ''
        str = @raw_doc.dup
        stacks = []
        root = Node.new('root')
        stacks.push root

        while (str.strip! || str.size > 0)
          case str
          when /^(<\?xml.+\?>)/ # XMLヘッダ(UTF-8以外読まないので無視)
            str.sub!($1, '')
          when /^(<([^>]+)\/>)/ # 単独タグ
            params = $2
            str.sub!($1, '')
            child = line_to_node(params)
            stacks.last.children.push child
          when /^(<\/([^>]+)>)/ # 閉じタグ
            name = $2
            str.sub!($1, '')
            stacks.pop
          when /^(<([^>]+)>)/ # 開始タグ
            params = $2
            str.sub!($1, '')
            child = line_to_node(params)
            stacks.last.children.push child
            stacks.push child
          when /^([^<]+)</
            text = $1
            str.sub!($1, '')
            child = TextNode.new('text')
            child.text = text
            stacks.last.children.push child
          else
            raise 'invalid xml'
          end
        end

        root
      end

      private
      def line_to_node(line)
        name, attr_str = line.split(/\s+/, 2)
        node = Node.new(name)

        if attr_str
          i = 0
          key = ''
          value = ''
          read_key_flag = true
          while i < attr_str.size
            if read_key_flag
              case attr_str[i]
              when /\s/
              when '='
                read_key_flag = false
                i += 1 # 次は「"」のはずなのでスキップ
              else
                key << attr_str[i]
              end
            else
              case attr_str[i]
              when "\\"
                i += 1
              when '"'
                read_key_flag = true
                node.attributes[key] = value
                key = ''
                value = ''
              else
                value << attr_str[i]
              end
            end
            i += 1
          end
        end

        node
      end
    end

    class Node
      # 初期化
      # @param [String] name ノード名
      def initialize(name)
        @name = name
        @attributes = {}
        @children = []
      end
      attr_reader :name
      attr_reader :attributes
      attr_reader :children

      # ノードの子の中から指定の名を持つものを取り出す
      # @param [String] name 検索するノードの名前
      # @return [Array] 配列
      def [](name)
        self.children.select { |child| child.name == name }
      end

      # 属性の取得
      # @param [String] name 属性名
      # @return [Object] 指定属性の値
      def attr(name)
        self.attributes[name]
      end

      # ノード内に含むテキストを返す
      # @return [String] 子ノードのテキストを全て連結した文字列
      def text
        self.children.map(&:text).join('')
      end

      # Hash化する
      # @return [Hash] Hash化した値
      def to_h
        {
          name: @name,
          attributes: @attributes,
          children: @children.map(&:to_h),
        }
      end
    end

    class TextNode < Node
      # 初期化
      # @param [String] name ノード名
      def initialize(name)
        super
        @text = ''
      end
      attr_accessor :text

      # Hash化する
      # @return [Hash] Hash化した値
      def to_h
        super.tap { |o| o['text'] = @text }
      end
    end
  end
end

module Torigoya
  module NicoVideo
    class Comment
      def initialize(no, user_id, vpos, mail, text)
        @no = no
        @user_id = user_id
        @vpos = vpos
        @mail = mail
        @text = text
      end
      attr_reader :no
      attr_reader :user_id
      attr_reader :vpos
      attr_reader :mail
      attr_reader :text
    end

    class CommentLoader
      def initialize(thread_id, message_url)
        @thread_id = thread_id
        @message_url = message_url
      end

      def fetch
        fetch_comment_xml(fetch_threadkey)
      end

      def fetch_threadkey
        resp = Torigoya::Http.client.get(
          "http://flapi.nicovideo.jp/api/getthreadkey",
          thread: @thread_id
        )
        response_set = {}
        resp.split('&').each do |n|
          set = n.split('=', 2)
          response_set[set[0].to_s] = set[1].to_s
        end
        response_set
      end

      def fetch_comment_xml(threadkey_data, size = 1000)
        thread_key = threadkey_data['threadkey']
        force_184 = threadkey_data['force_184']
        message_server_url = 'http://msg.nicovideo.jp/24/api/'
        data = "<thread res_from=\"-#{size}\" version=\"20061206\" thread=\"#{@thread_id}\" threadkey=\"#{thread_key}\" force_184=\"#{force_184}\" scores=\"1\" />"
        Torigoya::Http.client.post(
            message_server_url,
            data,
        )
      end
    end
  end
end

module Torigoya
  class RabbitComment
    # ごちうさ1羽のコメントサーバ情報
    # ログイン状態でgetflv API叩いて取得できるよ
    MESSAGE_SERVER_URL = 'http://msg.nicovideo.jp/24/api/'
    THREAD_ID = '1397552685'

    def self.load
      rc = RabbitComment.new
      rc.data['comments']
    end

    def initialize
      @data = nil
      load_comment
      unless @data['fetched_at'] and @data['fetched_at'] > Time.now.to_i - (60 * 60 * 3)
        @data['fetched_at'] = Time.now.to_i
        @data['comments'] = fetch_comment
        File.open('tmp/comment.dat', 'wb') do |f|
          Marshal.dump(@data, f)
        end
      end
    end
    attr_reader :data

    def load_comment
      Dir.mkdir('tmp') unless File.exist?('tmp')
      if File.exist?('tmp/comment.dat')
        begin
          File.open('tmp/comment.dat', 'rb') do |file|
            @data = Marshal.load(file)
          end
        rescue => e
          puts e.inspect
        end
      end
      @data ||= {}
    end

    def fetch_comment
      nico_comment = Torigoya::NicoVideo::CommentLoader.new(THREAD_ID, MESSAGE_SERVER_URL)
      parser = Torigoya::PoorXml::Parser.new(nico_comment.fetch)
      doc = parser.parse
      chat_elements = doc['packet'].first['chat'].map { |node|
        Torigoya::NicoVideo::Comment.new(
          node.attr('no').to_i,
          node.attr('user_id'),
          node.attr('vpos').to_i,
          (node.attr('mail') || '').split(/\s+/),
          node.text,
        )
      }.sort { |a, b| a.vpos <=> b.vpos }
    end
  end
end

module Torigoya
  module CommentPlayer
    module Manager
      def self.init(comments)
        @stage = Spriteset_Stage.new(comments)
      end

      def self.stage
        @stage
      end
    end

    class Sprite_Comment < Sprite
      def initialize(sprite_set, viewport = nil)
        super(viewport)
        @sprite_set = sprite_set
        @test_bitmap = Bitmap.new(1, 1)
        @speed = 1
        @life = -1
        self.z = 255
      end

      def dispose
        @test_bitmap.dispose
        super
      end

      def set(comment)
        unset
        @comment = comment

        self.bitmap.dispose if self.bitmap
        apply_font(@test_bitmap)
        lines = @comment.text.strip.split(/\r?\n/)
        rect = @test_bitmap.text_size(lines.max_by(&:size))
        if self.ue? or self.shita?
          rect.width = Graphics.width unless rect.width < Graphics.width
          align = 1
        else
          align = 0
        end

        self.bitmap = Bitmap.new(rect.width, rect.height * lines.size)
        apply_font(self.bitmap)
        lines.each do |line|
          self.bitmap.draw_text(rect, line, align)
          rect.y += rect.height
        end

        @speed = 0
        case
        when self.ue?
          self.x = (Graphics.width - self.bitmap.width) / 2
          self.y = @sprite_set.find_ue_position(self)
        when self.shita?
          self.x = (Graphics.width - self.bitmap.width) / 2
          self.y = @sprite_set.find_shita_position(self) - self.bitmap.height
        else
          self.x = Graphics.width
          @speed = (Graphics.width + self.bitmap.width) / (4.0 * Graphics.frame_rate)
          self.y = rand(Graphics.height - self.bitmap.height)
        end
        @life = Graphics.frame_rate * 4
      end

      def apply_font(bitmap)
        bitmap.font.size =
          case
          when @comment.mail.include?('small')
            24
          when @comment.mail.include?('big')
            48
          else
            32
          end

        # TODO: 16進数指定もあるよ
        bitmap.font.color =
          case
          when @comment.mail.include?('red')
            Color.new(255, 0, 0)
          when @comment.mail.include?('pink')
            Color.new(255, 128, 128)
          when @comment.mail.include?('orange')
            Color.new(255, 192, 0)
          when @comment.mail.include?('yellow')
            Color.new(255, 255, 0)
          when @comment.mail.include?('green')
            Color.new(0, 255, 0)
          when @comment.mail.include?('cyan')
            Color.new(0, 255, 255)
          when @comment.mail.include?('blue')
            Color.new(0, 0, 255)
          when @comment.mail.include?('purple')
            Color.new(192, 0, 255)
          when @comment.mail.include?('black')
            Color.new(0, 0, 0)
          when @comment.mail.include?('white2'), @comment.mail.include?('niconicowhite')
            Color.new(204, 204, 153)
          when @comment.mail.include?('red2'), @comment.mail.include?('truered')
            Color.new(204, 0, 51)
          when @comment.mail.include?('pink2')
            Color.new(255, 51, 204)
          when @comment.mail.include?('orange2'), @comment.mail.include?('passionorange')
            Color.new(255, 102, 0)
          when @comment.mail.include?('yellow2'), @comment.mail.include?('madyellow')
            Color.new(153, 153, 0)
          when @comment.mail.include?('green2'), @comment.mail.include?('elementalgreen')
            Color.new(0, 204, 102)
          when @comment.mail.include?('cyan2')
            Color.new(0, 204, 204)
          when @comment.mail.include?('blue2'), @comment.mail.include?('marineblue')
            Color.new(51, 153, 255)
          when @comment.mail.include?('purple2'), @comment.mail.include?('nobleviolet')
            Color.new(102, 51, 204)
          when @comment.mail.include?('black2')
            Color.new(102, 102, 102)
          else
            Color.new(255, 255, 255)
          end
      end

      def unset
        @comment = nil
        @life = 0
        self.bitmap.dispose if self.bitmap
      end

      def update
        if @comment
          self.x -= @speed
          @life -= 1
          if @life <= 0
            self.unset
          end
        end
        super
      end

      def living?
        @life > 0
      end

      def ue?
        @comment && @comment.mail.include?('ue')
      end

      def shita?
        @comment && @comment.mail.include?('shita')
      end
    end

    class Spriteset_Stage
      SPRITE_SIZE = 50

      def initialize(comments)
        @comments = comments
        @comment_index = 0
        @timer = 0
        @prev_frame_count = Graphics.frame_count 

        @viewport = Viewport.new
        @viewport.z = 65535
        @sprites = Array.new(SPRITE_SIZE).map { Sprite_Comment.new(self, @viewport) }
        @sprite_index = 0
      end

      def dispose
        @sprites.each do |sprite|
          sprite.bitmap.dispose if sprite.bitmap
          sprite.dispose
        end
        @viewport.dispose
      end

      def update
        # 時間を進める
        prev_timer = @timer
        @timer += ((Graphics.frame_count - @prev_frame_count).to_f / Graphics.frame_rate)
        @prev_frame_count = Graphics.frame_count

        # 経過時間中に登場するコメントを流す
        while @comments[@comment_index] && @comments[@comment_index].vpos <= (@timer * 100)
          @sprites[@sprite_index].set(@comments[@comment_index])
          @sprite_index = (@sprite_index + 1) % SPRITE_SIZE
          @comment_index += 1
          unless @comment_index < @comments.size
            @comment_index = 0
            @timer = 0
          end
        end

        @viewport.update
        @sprites.each(&:update)
      end

      # ue表示の表示位置を探して返す
      def find_ue_position(target_sprite)
        y = 0
        @sprites.select(&:living?).select(&:ue?).sort { |a, b| a.y <=> b.y }.each do |sprite|
          return y if y + target_sprite.bitmap.height < sprite.y
          y = sprite.y + sprite.bitmap.height
        end
        y
      end

      # shita表示の表示位置を探して返す
      def find_shita_position(target_sprite)
        y = Graphics.height
        @sprites.select(&:living?).select(&:shita?).sort { |a, b| b.y <=> a.y }.each do |sprite|
          return y if y - target_sprite.bitmap.height > sprite.y + sprite.bitmap.height
          y = sprite.y
        end
        y
      end
    end
  end
end

class << DataManager
  alias gochiusa_init init
  def init
    gochiusa_init
    comments = Torigoya::RabbitComment.load
    Torigoya::CommentPlayer::Manager.init(comments)
  end
end

class Scene_Base
  alias gochiusa_update_basic update_basic
  def update_basic
    gochiusa_update_basic
    Torigoya::CommentPlayer::Manager.stage.update
  end
end

一見、めっちゃ長いんですけど、RGSSからnet/httpとrexmlが使えないのが悪いんです…!XMLパーサー書くとか昭和かよ。

注意

  • コメント表示の再現度が絶望的にダメです
    • ニコ動のコメントシステム複雑すぎてつらいので誰かまとめてほしい
  • コメントの取得数が足りません(直近1000件しか取ってきてない)
  • よくコメント表示レイヤーが消失します
    • シーンをまたがったSprite大量に置くのよくないと思う
  • 間違ってもマジメなゲームに使ってはダメです

ごちうさの話

当時、タイトルの「うさぎ」に釣られて1羽を視聴しました。
「なるほどな」という感じだったので本来ならそのまま視聴継続になるはずだったのですが、4月当時、僕は完全に炎上案件の真っ只中で、仕事と睡眠を繰り返す日々で気づいたら夏になっており、僕の中でごちうさは1羽が最終回になってしまいました。
あのとき、リアルタイムに視聴していたら僕もどうなっていたかわかりませんね。。。

しかし、幸か不幸かはわかりませんが、弟がごちうさ民になっており、現在では家に原作もBlue-rayもある状態のため、ごちうさ分に関しては特に問題がない状態になっています。なので原作は3巻まで読みました。あと一応、電子版も買ったです。

シャロちゃんとリゼ先輩の関係がとても良いですね。
あの2人の関係は見てるだけでこう…グッとね。はい。


明日はゆっくりしないさんです٩(๑❛ᴗ❛๑)۶

VXAce(RGSS3)でTweenアニメーションするスクリプトつくった


実は僕、Flashなどではお馴染みのTweenアニメーションって
全然つかったことなかったのです……
で、こないだの4月バカのときに初めて使ってみて、
「やべー便利すぎるー!ツクールでも使いてー!」という衝動に。

ちょっとググってみたら外人さんが作ったやつとかもあったんですが、
僕の求めてるものとはちょっと違ったので、自分でつくってみました。
動機的にちょっとArctic.jsっぽいです。

スクリプト

gistにおいてあります 【Tweenアニメーションさん for RGSS3

使い方

こんな感じ。
「60フレーム(1秒間)かけて、X座標64、Y座標128に移動する」アニメーションです。

# 【補足】
# object : 動かしたいもの(SpriteとかWindowとか)

# アニメーションの準備
animation = HZM::Tween::Animation.new(object, {
  # 必須設定(省略しても勝手に設定して動きますが……)
  :time => 60,                   # アニメーション時間(フレーム数。60フレーム=1秒)
  :transition => :ease_in_quad,  # 動作方法。詳細は後述。
  # ここから先は変更するものを設定
  :x =>  64,  # X座標を64へ
  :y => 128,  # Y座標を128へ
})

# アニメーションの開始
animation.play


「:transition」の部分は毎回のフレームに移動させる量を計算するメソッドを指定する部分です。
要するに計算式を設定する部分です。
この辺りのサイト様を参考にしていくつか用意してあります↓↓↓

  • :linear
  • :ease_in_quad
  • :ease_out_quad
  • :ease_in_out_quad
  • :ease_in_cubic
  • :ease_out_cubic
  • :ease_in_out_cubic
  • :ease_in_quart
  • :ease_out_quart
  • :ease_in_out_quart
  • :ease_in_quint
  • :ease_out_quint
  • :ease_in_out_quint
  • :ease_in_sine
  • :ease_out_sine
  • :ease_in_out_sine
  • :ease_in_expo
  • :ease_out_expo
  • :ease_in_out_expo
  • :ease_in_circ
  • :ease_out_circ
  • :ease_in_out_circ


上の以外を使いたい場合は、HZM_VXA::Tween::Transitionの中に
新しくメソッドを増やすことで追加できます。

また、例ではx座標とy座標を指定していますが、別にほかのも指定できます。
「○○.hoge = 数値」で設定できるものなら、「:hoge => 数値」でOK。
ただし、計算結果を強制的に整数にしてしまっているので、
小数の結果が欲しい場合はうまく動かないです。

ついでに別にSpriteとかWindowじゃなくても、何でも使えます。
Spriteに限定せず何にでも使えるやつが欲しかったので自分でつくったのです。
まぁ、通常用途ではあんまり意味ないかもしれませんが。。。僕には必要。

わかりにくいから実際に試したい

実用性ゼロのサンプル。
メニューを開くときにアニメーションします。

# メニュー画面を開いたときにうぃんうぃんするスクリプト
class Scene_Menu < Scene_MenuBase
  ANIMATION_TIME = 15
  #-----------------------------------------------------------------------------
  # ● 開始処理
  #-----------------------------------------------------------------------------
  alias hzm_vxa_tween_sample_start start
  def start
    hzm_vxa_tween_sample_start
    unless Window_MenuCommand.last_command_symbol
      # 各アニメーションを設定
      anim_command = HZM_VXA::Tween::Animation.new(@command_window, {
        :time => ANIMATION_TIME,
        :transition => :ease_out_quad,
        :x => @command_window.x,
        :y => @command_window.y,
        })
      anim_gold = HZM_VXA::Tween::Animation.new(@gold_window, {
        :time => ANIMATION_TIME,
        :transition => :ease_out_quad,
        :x => @gold_window.x,
        :y => @gold_window.y,
        })
      anim_status = HZM_VXA::Tween::Animation.new(@status_window, {
        :time => ANIMATION_TIME,
        :transition => :ease_out_quad,
        :x => @status_window.x,
        :y => @status_window.y,
        })
      # 初期値を指定
      @command_window.x = 0 - @command_window.width
      @command_window.y = 0 - @command_window.width
      @gold_window.x = 0 - @gold_window.width
      @gold_window.y = Graphics.height + @gold_window.width
      @status_window.x = Graphics.width
      # アニメーション開始
      anim_command.play
      anim_gold.play
      anim_status.play
    end
  end
end
class Window_MenuCommand < Window_Command
  #-----------------------------------------------------------------------------
  # ● コマンド選択位置の取得(クラスメソッド)(独自)
  #-----------------------------------------------------------------------------
  def self.last_command_symbol
    @@last_command_symbol
  end
end


うわー、うぜー(

RPGツクールVX Ace Liteの思うところと、イケナイこと!


お久しぶりですRuたんです!
制作の類が吐きそうになるくらい進んでないので、死にそうです(

最近あったことと言えば、RPGツクールVX Ace Liteが公開されましたね。
ちょっと僕もインストールしてみたので、気になったところを書いてみます。
まぁ、スクリプトいじれないので、僕がやることはほとんどないですがw

起動時ロゴの表示


Lite版で作られたゲームは起動時にエンターブレインでツクールなロゴが入ります。
これは実行ファイルが特別なものになってる……わけではなく、
スクリプトに以下の処理が追加されています。

def show_logo
  sprite = Sprite.new
  Graphics.fadeout(0)
  sprite.bitmap = Cache.system('Logo1')
  Graphics.fadein(30)
  Graphics.wait(30)
  Graphics.fadeout(30)
  sprite.bitmap = Cache.system('Logo2')
  Graphics.fadein(30)
  Graphics.wait(30)
  Graphics.fadeout(30)
end

show_logo unless $TEST

製品版持ってる人で起動ロゴ入れたい人は、
コレそのまま使えばいいんじゃないかな!

起動時にしか表示されない(F12リセット時は出ない)のに、
わざわざキャッシュにするのもどうかとは思いますけど……
わかりやすくするって意味でこうなってるのかな?

あと、Graphics/Systemに入ってるロゴ画像表示してるだけなので、
この画像を差し替えたらLite版でも……(駄目です

コモンイベントは使えないわけじゃない


イベントコマンドの「コモンイベント」は機能制限がかかっているので、
使うことはできないですが、データベースのコモンイベントは普通に使えます。
(※もちろん、最大数は変更できないので10個まで)


なので、上みたいにスイッチONをトリガーに実行するようにすれば、
コモンイベントを使ってあげることが可能です。
使うとイベントが発生するアイテムも問題なく作れますね!

ちなみにコレやるときはちゃんと最後にスイッチ1をOFFにしないとダメですよ?
スイッチ1がONのままだと永遠におっさんと話し続けることになるので……!

イベントコマンドの「コモンイベント」も使える!?

用意するものは簡単! VX Ace LiteとVX Ace(製品版)です!(


まず、製品版でコモンイベントの呼出のイベントを作ります。


それをコピーします。



VX Ace Liteのほうを開いてペーストします。


おー


わーお


同じやり方で、スクリプトのイベントもコピーすることができます。
つまり製品版を買えばやりたい放題ってことですね!!!!……あれ?

ちなみに貼り付けたイベントコマンドは編集はできないけど、
のコピー&ペーストは問題なくできたりします。
なので、製品版持ってる人にコモンイベントの呼出1〜10を作ってもらって、
そのマップデータを読み込めb……おっと誰か来たようだ。
(※普通に駄目です)

製品版のプロジェクトを読み込める

製品版のプロジェクトファイルのGame.rvproj2を
Lite版で作ったプロジェクトファイルのGame.rvproj2で上書きすると
一応、開くことが出来ます。

が、エディタの画面(マップ)がおかしくなるっぽい?ので注意。
というか、別に意味ないですし……

むしろLite版のプロジェクトを製品版で読み込める

「Liteで作成したプロジェクト(ゲームデータ)を
 そのまま製品版で読み込むことができません」という公式の記述通り、
そのまま読み込むことはできないですが、
上に書いた逆、つまり製品版のGame.rvproj2で上書きしてあげれば、
Liteのプロジェクトを製品版に引き継げます。

なので、「Lite版で作ってたけどもっといろいろやりたい」とか、
鳥小屋.txtっていうサイトで公開されてるスクリプト使いたい」って人は、
製品版買えばいいんじゃないかな!! スクリプトいいよ!!(

というかGame.rvproj2って、ただのテキストファイルなので、
メモ帳かなんかで開いて編集するだけで、Lite版と製品版切り替えられます。

製品版は

RPGVXAce 1.01

Lite版は

RPGVXAce-Lite 1.01

になってます。
バージョン情報書いてあるだけー。

(製品版持ってる人)インストールすると関連付けに困る

製品版インストール済みなのにVX Ace Liteをインストールすると
Game.rvproj2をダブルクリックしたときに、
Lite版が起動するようになります。仕方ないね。

直すのだいぶ面倒くさいんで、
よくわからない人はインストールしないほうがいいかなー。
実行ファイル名が同じせいか、
Windowsの関連付けのほうからだとうまく設定できない感じ?
僕は関連付けいじるソフト使いました。

結論

スクリプトいじれないから、Ruたんやることない(
そもそも製品版持ってるのでやる必要もないですが……

純粋に保存できるようになった体験版って感じですね。
ちょっとした作品だったら十分作れるんじゃないかな?と思います。

ニコニコ自作ゲームフェスに応募する方は頑張ってください!!
たぶん期限内に完成させるのが一番大変w

「新」音量変更スクリプトさん for RGSS3


  • 2021/12/15 スイッチアドオンを更新
  • 2017/11/14 アドオンを追加。ベーススクリプトも最新版に更新してね。
  • 2016/04/23 アドオンを追加しました。アドオンを利用する際は「音量変更スクリプトさん」を最新版へ更新してください。
  • 2013/05/25 タイプ設定を変更すると強制終了する不具合修正しました。使っている方は最新版に差し替えお願いします。

前にも1回載せてますが、あれはVXAceの体験版が出て飛びついて書いた記事なので、今回スクリプトをいろいろ直したついでに解説記事をちゃんと書きます。

スクリプト概要

ゲーム中の音量を設定するメニューを追加します。
タイトル画面やメニューに項目として追加することができます。

詳しくはスクリプト内の設定項目を御覧ください。

応用編

イベントコマンドの「スクリプト」に以下のように記述することで、音量設定メニューを呼び出すことができます。

SceneManager.call(
HZM_VXA::AudioVol::Scene_VolConfig
)

1行で書こうとするとエラーになるので、↑のように改行を入れるのがオススメです。

利用規約

RPGツクールVX Ace(RPG Maker VX Ace)での使用の場合は自由に使用できます。
有償利用、改変配布など特に制限はありません。


音量変更スクリプトさん用のアドオン

音量変更スクリプトさんに機能追加をするスクリプトです。
音量変更スクリプトさんより下に必ず設置してください。

スイッチ設定さん for RGSS3

音量変更画面にスイッチのON/OFFを設定する項目を追加します。

[音量変更スクリプトさんアドオン] スイッチ設定さん for RGSS3

ウィンドウ倍率設定さん for RGSS3

音量変更画面にウィンドウ倍率設定の項目を追加します。

[音量変更スクリプトさんアドオン] ウィンドウ倍率設定さん for RGSS3

VXAceのRTPでけーよ!

ちょっとお休み期間のRuたんです。
ツクールじゃないことちまちまやったり、ツクールに戻ったりしてます。
RGSSはそのうち?

VXAceのRTPのファイルサイズ

どこ見てもみんな言ってるのでやっぱでかいよね。

VXAceのRTPは約185MBという大ボリューム。
ちなみにVXは約35MBです。5倍くらいになってRu!

そんなわけで30分くらいでクリアできると噂の
超短編なノミノネをプレイするのに、
わざわざ185MBものファイルをDLさせるのは
いかがなものかと思ったのです。

なので、RTP不要になるようにファイル詰めて、
そのままだとファイルサイズが大きすぎるので、
戦闘アニメをJPEGにして画質落としたり、
タイルの数減らしたり減色したり頑張った結果、
今のところ約22MBになりました。
ちなみに今のRTP必要版が約6MBです。約4倍……

個人的には15MBくらいに収まってほしいなぁと思うところ。
普通の人の感覚だとどのくらいまでならOKな範囲なんですかね?

あとは効果音あたりを削るかなぁ……
でもどのファイル使ってるかわからない/(^o^)\
イベント組み直しあるよこれ!

敵バトラーに影を表示 for RGSS3

メモ欄シリーズ、スクリプト名に「さん」つけ忘れてて泣きたい。
そんなわけで、ノミノネに使ったスクリプトをどんどん素材にします!

敵バトラーの下に影を自動的に表示するスクリプトさんです。
まぁRTPのモンスターはみんな画像自体に影が付いてたりするので、
このスクリプト意味ないんですけどね。他の素材使う時などに><

[hzm]敵バトラーに影を表示 for RGSS3
※使用するためには、このスクリプトより上に[hzm]メモ欄拡張共通部分 for RGSS3を設置する必要があります。

機能は必要最低限です。
動いたり、敵の形の影になったりはしません。全部同じ形です。
ただ、大きさだけは半自動調整です。
でも実際に使うと手動調整しないと使い物にならないという……(体験談)

使う時は影用の画像が必要です。
Graphics/Battlersの中に入れてください。
上のサンプル画像はノミノネに使ってたやつですが、勝手に使ってもOKですよん。

実際に設定した例です。
「[hzm]影」までは共通で、その後に手動設定する場合は数値を入れます。
上の図だと、横方向はそのまま、縦方向は上に16ドット、拡大率は1.8倍です。
あ、位置だけ手動設定したい場合は、拡大率は書かなくてもいけます。
「[hzm]影:0,-16」までにすればOK。

拡張スキルデータベース設定さん&ターン消費無しスキルさん for RGSS3(VX Ace)

  • 2020/8/23 ターン消費無しスキルさん更新
  • 2013/5/11 記事タイトルを「スキルのメモ欄系スクリプト4点セット」から変更し、文章を書きなおしました

ノミノネ用に作ったスキル系のスクリプトをベースに修正したものです。

その前に

ここのスクリプトを使うためには「[hzm]メモ欄拡張共通部分さん+ for RGSS3」が必要です。

[hzm]メモ欄拡張共通部分さん+ for RGSS3

以下のスクリプトより上に必ず入れて使ってください。じゃないと動かないよ。

拡張スキルデータベース設定さん for RGSS3

スキル・武器のデータベースのいくつかの項目をメモ欄で設定できるようにするもの。
おまけとしてHP消費攻撃なども作れるようになってます。

[hzm]拡張スキルデータベース設定さん for RGSS3

目玉としては各設定に計算式が使えるので「[hzm]連続回数:1+rand(3)」みたいな
設定をすると、ランダムに1〜3回攻撃するスキルが作れたりします。

ターン消費無しスキルさん+ for RGSS3

ある意味、鳥小屋.txtの大目玉スクリプトという説もある子。よくバグがあります(
言葉で説明しにくいので、動画でどうぞ。


[hzm]ターン消費無しスキルさん+ for RGSS3

つまりターンを消費することなく行動できる技を作ることができます。ゼロリロードっ!(
ついでにオマケとして、行動順序をスキルごとに反映する機能を追加します。
元々、別スクリプトにしてましたが、ターン消費無しスキルの一部機能に必須なので、くっつけちゃいました。
にしても、行動順序のやつはRGSS3の仕様上のバグなんじゃないですかねぇ……?

遅延型スクリーンショット撮影さん for RGSS3(VXAce用)

2012/01/07追記 ↓多分修正できたはず
2012/01/01追記 たまに動かないことがあるみたいです.少し原因調べますね.

↑みたいなスクリーンショットを撮影できると便利です.
誰が便利って作者さんが便利ですね.自サイト載せる用とか.
そんなわけで,ワンボタンで撮れるのを作ってみました.
PrintScreenキーを押すとパシャパシャします.

というかVXの時にも作ってたんですけど,
撮ると急激にガクっと処理落ちしてしまうので,
うまく使えなくてうーん……でした

なので今回は処理を遅延型(?)にすることで,
1フレームあたりの負荷を小さくして,
なるべく処理落ちしないようにしてみました.
それでも押した瞬間とファイル保存の瞬間は
少し処理落ちしますけどね……
20fpsとかになるよりはマシということで><

プレイヤー視点で考えると,
「●●に保存しました」みたいな通知が出るといいかなぁ.
それはそのうち……(

RPGツクールVXAce(RGSS3)スクリプト素材一覧

RPGツクールVX Ace用です。
RPGツクールMV/MZのプラグイン素材は 鳥小屋プラグイン置き場 をみてね!

更新履歴

  • 2021/12/15
    • 「[音量変更スクリプトさんアドオン] スイッチ設定さん for RGSS3」を更新
    • 「共有スイッチ・変数スクリプトさん」を追加
  • 2017/11/14
    • ベーススクリプトをちょっとだけ更新
  • 2016/04/23
    • 「音量変更スクリプトさん for RGSS3」をアドオン対応のため更新

新スクリプト(Torigoya系)

最近のRuたんが作ったスクリプト素材です。まぁまぁ安全(?)

スクリプト名 更新日 備考
バトルログに再生量表示スクリプト 2019/03/09 参考記事
スイッチでスキル非表示スクリプトさん 2019/12/15
二刀流の2本目のスロット名称変更さん 2021/05/06
共有スイッチ・変数スクリプトさん 2021/12/15

旧スクリプト(HZM系)

むかーし、むかしに作っていたスクリプト素材です。あやしい。

基本スクリプト

単体で効果するものではなく、他のスクリプトの共通処理が入ったスクリプトです。
「ベーススクリプト必須」や「[hzm]メモ拡張必須」などのスクリプトを使用する場合は、それらより上に導入する必要があります。

スクリプト名 更新日 備考
HZM_VXA ベーススクリプトさん 2017/11/14
[hzm]メモ欄拡張共通部分さん+ for RGSS3 2017/11/14

システム関係

システム系のスクリプト素材

スクリプト名 更新日 備考
HZM_VXAベースショートコマンドさん for RGSS3 2012/08/01 ベーススクリプト必須
高速Input.repeat?さん for RGSS3 2012/01/02 参考記事
音量変更スクリプトさん for RGSS3 2018/09/02 参考記事
[音量変更スクリプトさんアドオン] スイッチ設定さん for RGSS3 2021/12/15 音量変更スクリプトさん必須
メニューからコモンイベント呼び出しさん 2011/12/04
遅延型スクリーンショット撮影さん 2012/06/10
F5でウィンドウ拡大さん 2012/08/01 ※ベーススクリプト必須
セーブデータ保存場所変更さん 2012/11/14 ※ベーススクリプト必須

戦闘関係

デフォルト戦闘の不満点をちょいちょい

スクリプト名 更新日 備考
[hzm]ターン消費無しスキルさん+ 2014/06/22 参考記事
[hzm]メモ拡張スクリプト必須
「各行動ごとに行動順を設定さん」の機能を統合
[hzm]敵バトラーに影を表示 2012/01/07 参考記事
[hzmメモ拡張スクリプト必須]
[hzm]拡張スキルデータベース設定さん for RGSS3 2016/01/17 参考記事
[hzm]メモ拡張スクリプト必須
エネミーのトループターゲットランダム化さん 2012/03/03

スクリプト素材のライセンス・利用ルール

このブログで公開しているRGSS3スクリプト素材は、自由に使って大丈夫です。

  • ゲームに使う → OK
  • 有料のゲームや年齢制限があるゲームに使う → OK
  • 使ったゲームをコンテストに出す → OK
  • 改変する → OK
  • 再配布する → OK
  • 著作表記 → してもしなくてもいいよ!

なお、各スクリプト素材や解説ページに特別なルールが記載されている場合はそちらのルールに従ってください。

RGSS3素材のサポートについて(2021/12/15)

非公式のため自己責任でご利用ください。
また、RGSS3素材は基本的に積極的なサポートを行いません。
不具合の修正なども行わない場合があります(10年前に書いたスクリプト、もう覚えてない……)

高速Input.repeat?さん for RGSS3(VXAce用)

  • 2013/05/11 スクリプトのリンク切れ直しました
  • 2011/12/25 起動時にキーが押されているとエラーする不具合を修正


ツクールのInput.repeat?は遅すぎると思います!

高速Input.repeat?さん for RGSS3

そんなわけで前に作ったVX版のやつを移植してみました。
前とほとんど変わってないですけどね
あと置き場はたまにこっそり増えるかもです。
あんまりデバッグしてないやつは大っぴらに出せなくて(
これもあんまりしてないけどね!

VXAceでTwitterAPIしたい

最近よくあるよね、ゲームからTwitterに投稿するっていうの。
「アリアハンなう」的なあーゆーことできたら面白いかなぁとか。

とりあえず簡易版作ってみた

で、よくブログとかについてる
「このページをツイート」みたいの押すと出てくる
ツイート欄を表示させたらそれっぽいかなと思って
ちょっと作ってみたのです。

超簡易ツイート機能さん for RGSS3
https://gist.github.com/rutan/3224292https://gist.github.com/rutan/3224289 に移行しました。

でも、やっぱりこれもなんか違うよなぁと。
これだったら普通にTwitterで投稿するのと変わらないし

それにツイートだけじゃなくて、
そのゲームに関するツイートとかも取得できたら面白いよね。
右上からピョコピョコ出てくるの。
で、開始直後にネタバレされて死ぬの(

そんなわけで考え中

C++でDLL作ってそっちから呼べるかなと思い、
ちょっとライブラリ借りてきてやってみたんですが、
認証ページ開くだけで処理に10秒くらいかかってぐぬぬ……
何がおかしいのかよくわかんないー

本体と別に実行ファイル用意して、
そっち経由で投稿させるのは試した感じ簡単にできそうかも。
ただ作りとしてはあんまりきれいじゃないかなぁw
(DLLも方法としてはきれいじゃないかもしれないけど)

もうちょっと悩んでみます。そして進まない制作(

ツクールDS+風 頭上アイテム表示スクリプト for RGSS3(VXAce用)


みなさーん、ツクツクー!(
そんなわけで、ツクールDS+の頭上アイコン表示をVXAceでも使ってみましょう!(

# coding: utf-8
#===============================================================================
# ■ ツクールDS+風 頭上アイテム表示さん for RGSS3
# ※このスクリプトはRGSS3(RPGツクールVXAce)専用です
#-------------------------------------------------------------------------------
# 2011/12/06 Ru/むっくRu
#-------------------------------------------------------------------------------
# RPGツクールDS+のアイテムアイコン頭上表示のような機能を追加します
#
# 【使い方】
#  ・イベントコマンドの「スクリプト」の中で以下の命令を行ってください
#
#     startItemDSP(MAPイベントのID, アイコンのID)
#
#     ● MAPイベントのID
#     イベント編集ウィンドウのタイトルバー部分にでるIDの値
#     主人公を指定する場合は-1、このイベントを指定する場合は0にしてください
#     ● アイコンのID
#     データベースのアイコン選択画面左下に出るIndex:の値
#     ただし、Index:0のアイコンは表示されません
#
#   例)
#     startItemDSP(-1, 1)
#   ↑主人公の頭上に1番のアイコン(RTPだとドクロ)が表示される
#
#  ・消すときには「スクリプト」の中で以下の命令を行ってください
#
#     endItemDSP(MAPイベントのID)
#
#   例)
#     endItemDSP(-1)
#   ↑主人公の頭上のアイコンが消える(もともと無い場合は何もおきない)
#
#-------------------------------------------------------------------------------
# 【問題点など】
# VXAce発売前なのでちゃんと動くかわからないし、
# ツクールDS+も出てないので、本当にDS+風なのかどうかもわからない
#-------------------------------------------------------------------------------

#==============================================================================
# ● 設定項目
#==============================================================================

module HZM_VXA
  module DSP_OHICON
    # 表示する高さ微調整
    D_HEIGHT = 0
  end
end

#==============================================================================
# ↑   ここまで設定   ↑
# ↓ 以下、スクリプト部 ↓
#==============================================================================

# 定数
module HZM_VXA
  module DSP_OHICON
    # startItemDSP、endItemDSP命令を使用可能にする
    CAN_SHORT_COMMAND = true
  end
end

# アイコン表示用の変数を追加
class Game_CharacterBase
  attr_accessor :hzm_vxa_dsp_ohicon_id
  
  alias hzm_vxa_dsp_ohicon_init_public_members init_public_members
  def init_public_members
    hzm_vxa_dsp_ohicon_init_public_members
    @hzm_vxa_dsp_ohicon_id = 0
  end
end

# アイコン表示処理追加
class Sprite_Character < Sprite_Base
  alias hzm_vxa_dsp_ohicon_initialize initialize
  def initialize(viewport, character = nil)
    hzm_vxa_dsp_ohicon_initialize(viewport, character)
    @hzm_vxa_dsp_ohicon_icon_index = 0
  end
  
  alias hzm_vxa_dsp_ohicon_dispose dispose
  def dispose
    hzm_vxa_dsp_ohicon_end_ohicon
    hzm_vxa_dsp_ohicon_dispose
  end
  
  alias hzm_vxa_dsp_ohicon_update update
  def update
    hzm_vxa_dsp_ohicon_update
    hzm_vxa_dsp_ohicon_update_ohicon
  end
  
  alias hzm_vxa_dsp_ohicon_setup_new_effect setup_new_effect
  def setup_new_effect
    # デバッグ用
    #@character.hzm_vxa_dsp_ohicon_id = 0 unless @character.hzm_vxa_dsp_ohicon_id
    hzm_vxa_dsp_ohicon_setup_new_effect
    if @hzm_vxa_dsp_ohicon_sprite
      hzm_vxa_dsp_ohicon_end_ohicon   if @character.hzm_vxa_dsp_ohicon_id <= 0
    else
      hzm_vxa_dsp_ohicon_start_ohicon if @character.hzm_vxa_dsp_ohicon_id > 0
    end
  end
  
  HZM_VXA_DSP_OHICON_ICON_SIZE = 24
  def hzm_vxa_dsp_ohicon_start_ohicon
    @hzm_vxa_dsp_ohicon_icon_index = @character.hzm_vxa_dsp_ohicon_id
    @hzm_vxa_dsp_ohicon_sprite = Sprite.new(viewport)
    @hzm_vxa_dsp_ohicon_sprite.bitmap = Bitmap.new(HZM_VXA_DSP_OHICON_ICON_SIZE, HZM_VXA_DSP_OHICON_ICON_SIZE)
    bitmap = Cache.system("Iconset")
    rect = Rect.new(@hzm_vxa_dsp_ohicon_icon_index % 16 * HZM_VXA_DSP_OHICON_ICON_SIZE, @hzm_vxa_dsp_ohicon_icon_index / 16 * HZM_VXA_DSP_OHICON_ICON_SIZE, HZM_VXA_DSP_OHICON_ICON_SIZE, HZM_VXA_DSP_OHICON_ICON_SIZE)
    @hzm_vxa_dsp_ohicon_sprite.bitmap.blt(0, 0, bitmap, rect)
    @hzm_vxa_dsp_ohicon_sprite.ox = HZM_VXA_DSP_OHICON_ICON_SIZE / 2
    @hzm_vxa_dsp_ohicon_sprite.oy = HZM_VXA_DSP_OHICON_ICON_SIZE
    hzm_vxa_dsp_ohicon_update_ohicon
  end
  
  def hzm_vxa_dsp_ohicon_end_ohicon
    @character.hzm_vxa_dsp_ohicon_id = 0
    @hzm_vxa_dsp_ohicon_icon_index   = 0
    hzm_vxa_dsp_ohicon_dispose_ohicon
  end
  
  def hzm_vxa_dsp_ohicon_dispose_ohicon
    return unless @hzm_vxa_dsp_ohicon_sprite
    @hzm_vxa_dsp_ohicon_sprite.bitmap.dispose
    @hzm_vxa_dsp_ohicon_sprite.dispose
    @hzm_vxa_dsp_ohicon_sprite = nil
  end
  
  def hzm_vxa_dsp_ohicon_update_ohicon
    return unless @hzm_vxa_dsp_ohicon_sprite
    @hzm_vxa_dsp_ohicon_sprite.x = x
    @hzm_vxa_dsp_ohicon_sprite.y = y - height - HZM_VXA::DSP_OHICON::D_HEIGHT
    @hzm_vxa_dsp_ohicon_sprite.z = z + 190
  end
end

# コマンド追加
class Game_Interpreter
  def hzm_vxa_dsp_ohicon_start_item_over_head(id, icon_index)
    return unless character = get_character(id)
    character.hzm_vxa_dsp_ohicon_id = icon_index
  end
  
  # ショートカットコマンドの追加
  if HZM_VXA::DSP_OHICON::CAN_SHORT_COMMAND
    def startItemDSP(id, icon_index)
      begin
        hzm_vxa_dsp_ohicon_start_item_over_head(id, icon_index)
      rescue
        puts "startItemDSP(#{id}, #{icon_index})を実行中にエラーが発生しました"
        puts "#{$!} - #{$@}"
        puts "----------"
      end
    end
    def endItemDSP(id)
      begin
        hzm_vxa_dsp_ohicon_start_item_over_head(id, 0)
      rescue
        puts "endItemDSP(#{id})を実行中にエラーが発生しました"
        puts "#{$!} - #{$@}"
        puts "----------"
      end
    end
  end
end

フキダシ表示とほとんど変わらないじゃん!

他にもDS+の機能追加するぜーと思ったのですが、
タイトルイラストの表示とかはピクチャでやればいいので必要ないかな……

次は前につくった高速Input.repeat移植しようかなーRGSS3楽しいです!
発売前から神ゲー!!(