鳥小屋.txt

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

『魔導箱のグリモワール』をつくった話

ぼく、2年ぶりのゲーム公開なんです……(エターすぎる日々)

というわけで、『魔導箱のグリモワール -Leyak's Cube Grimoire-』というパズルゲームを公開しました。

思ったより遊んでもらえたりコメントしてもらえてて、とてもうれしい…!

で、せっかくとても久しぶりにゲームを公開できたので、ちょっとした雑記みたいなものを書いてみようかなと思います。

RPGジャナーイな話

えっとね、企画当初はRPG要素みたいのも入れようとしてたんですよ…?
赤のブロックを1000個消費して炎の魔法を覚えてダンジョンに〜みたいな。
(なので、内部的にはどの色を何個消したか記録できるようになってたり)

でもね……そんなこと始めたら絶対エターなることに気づいちゃったからやめたんです…ゆるして><;

ちなみにパズル部分以外はフツーのプラグインの形式でつくっているので、
実績機能とかは説明書とか書いて素材として公開するつもりです。

PCでのプレイがなんか不遇な話

ブロックの移動が斜めだからね! PCだと斜め移動難しいもんね!

PCだと難しいのは割とわざとです。
スマホで遊んでもらえるとうれしいな〜という感じなんです。
スマホからじゃないと解除されない実績もあるしね()

上でめっちゃしゃべってる話

スコアアタックしかないパズルでも世界観っぽいことしたい!

というわけで、魔導師のレヤックがめっちゃ喋ってます。
ゲームのヒントになる内容が2%くらいで、98%くらいはどうでもいいこと喋ってます。
(ちなみにセリフは70パターンくらいあるよ)

「ゲームとして面白ければ絵は記号でもいい」みたいな話もありますが、
実際そんなことないし、雰囲気とかも大事だと思うんですよね。
スコアアタック系のパズルは無機質な感じになりがちな気がするので、
セリフ吹き出しでゆるふわした雰囲気でてるといいな。

ちなみにキャラを2人置いて会話させようかとも考えたのですが、
会話だとじっくり見てないといけなくなるのと、
何より絵を2キャラ分描くのは僕が溶けるのでやめました……

ハイスコアの話

僕の最高スコアです。
これ超えたらすごすぎるので自慢しまくってください!(?)

次回作の話

次こそはRPGツクールしたいよね……!

【オートポーション】ダメージ時自動アイテム/スキル使用さん for MV(2019/05/12更新)

f:id:ru_shalm:20160619132005j:plain

  • 2019/05/12 回避時処理を追加
  • 2019/03/23 自動アイテムが発生したターンに、ステートのターンが進まないことがあるのを修正
  • 2019/02/03 指定のスイッチがONの場合のみ有効にできるモードを追加しました
  • 2018/05/01 複数回行動の間に発動すると行動が途中終了してしまうのを修正しました
  • 2016/09/19 かばう時に動作しない問題について対応しました

プラグイン概要

戦闘中に攻撃を受けた際に自動的に使うアイテムやスキルを設定できます。
いわゆる「オートポーション」とか「オートフェニックス」とかそういうやつです。

<注意>
カウンタースキルではないため、攻撃技を設定すると明後日の方向に飛んでいきます><;
回復アイテムとか回復スキルとか設定してね!おやくそくだよ!

使用方法

f:id:ru_shalm:20160619132938p:plain

メモ欄に設定を記述することで有効になります。 アクター / 職業 / 武器 / 防具 / 敵キャラ / ステート のメモ欄で設定できます。

メモ欄での設定項目について

<AutoItemMe/hp[50%]: 1>

■ 誰が攻撃されたときに発動するか?( Me の部分 )

  • Me:自分
  • Friend:味方の誰か

■ 条件を何にするか?( hp の部分 )

  • hp:残りHP
  • mp:残りMP
  • tp:残りTP
  • state:付けられたステート

■ 条件の値( 50% の部分 )

  • 条件が hp / mp / tp のとき
    • xx%: 指定%以下になったとき
  • 条件が state のとき
    • ステートのID(例:戦闘不能の場合は 1

■ 使うアイテムのID( 1 の部分 )

ここで指定したIDのアイテムを使用します。

アイテムではなくスキルにしたい!

<AutoSkill/hp[50%]: ○○>

↑のように AutoItem の部分を AutoSkill と記述することで、スキルを使用させることができます。

設定の例

##
## 基本的な使い方
##

# 自分のHPが50%以下になったらアイテムID: 1を使用する
<AutoItemMe/hp[50%]: 1>

# 仲間の誰かのMPが30%以下になったらアイテムID: 2を使用する
<AutoItemFriend/mp[30%]: 2>

# 仲間の誰かがステートID: 1(戦闘不能)になったら、スキルID: 100を使用する
<AutoItemFriend/state[1]: 100>


##
## 秘密の機能編
##

# 自分のHPが50%以下になったらアイテムID: 1を使用する。
# アイテムID: 1が使えない場合は、アイテムID: 2を使用する。
<AutoItemMe/hp[50%]: 1, 2>

# 自分のHPが50%以下になったらアイテムID: 1を消費せずに使用する。
<AutoItemMe/hp[50%]: 1!>

# 自分が敵の攻撃を回避したら、アイテムID: 2を使用する。
<AutoItemMe/onEvaded: 2>

注意点など

攻撃アイテム・攻撃スキルを設定すると正しく動きません

必ず効果範囲が「味方」または「自分」のアイテム・スキルを設定してください

発動する優先度

同じキャラクターに対して複数のオートアイテムが発動する場合、
以下のルールに従って、どちらを使用するかが決定されます。

【優先度:高】ステート > HP > MP > TP【優先度:低】

【優先度:高】自分スキル > 自分アイテム > 仲間スキル > 仲間アイテム【優先度:低】

あれ?発動しない?

  • 使用条件を満たしていないと発動できません
    • アイテムの場合:アイテムを持っている必要があります
    • スキルの場合:MPなどが足りている かつ そのスキルを覚えている必要があります
    • ただし <AutoItemMe/hp[50%]: 1!> のように IDの後ろに半角の ! が付いている場合は無視して発動します
  • 1人のキャラクターに対して複数人が同時にオートアイテムすることはできません
    • ハロルドが攻撃されたときに、他の3人全員がハロルドにアイテムを使ったりはしません

ちょっと条件がややこしいですね……
無限ループにならないように色々調整しています><

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

Torigoya_AutoItems ダウンロード

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

利用規約

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


作っているゲームで使いたくなって作りはじめたものです。
最初、他のプラグイン組み合わせてやろうとしたのですが、
すごく複雑になって「うーーーーん…」となり、
自分で必要な分だけプラグイン書くか〜すぐ終わるだろ〜と言って始めたのですが、
完全に見積もり失敗だったよね()

ワンボタンスキルさん for MV(2017/08/11更新)

f:id:ru_shalm:20160306160920p:plain


  • 2017/08/11 22:00頃 「スキル」の上でワンボタンスキルを使ってキャンセルするとエラーするのを修正

プラグイン概要

戦闘中、各キャラクターの行動選択中にShiftキーを押すと選択されるスキルを設定できます。

MPやTPなどが足りない場合は「ブブー」という音が出て使用できません。

使用方法

f:id:ru_shalm:20160306161931p:plain

スキルのメモ欄に

<OneButtonSkill>

と書くことで、そのスキルがShiftキーで選択されるようになります。

優先度について

ワンボタンスキルを複数覚えている場合、優先度が高いものが選択されます。

<OneButtonSkill>         # 何も書かないと優先度0
<OneButtonSkill: 100>    # 優先度100

優先度が同じスキルがある場合は、スキルIDが小さい方が選択されます。

プラグイン設定について

Key Name

ワンボタンスキルに使用するキー名を設定します。
デフォルトでは shift が設定されています。

他のキー大体使われているのであまりいじることはないかもしれません……
超独自のシステムを使っていてデフォとキーが全然違う!みたいな場合は設定が必要です。

Hide One Button Skill

ワンボタンスキルに設定したスキルを、スキル一覧から隠すかどうかを設定します。
デフォルトでは false 、つまり隠さない設定です。
隠したい場合は true に変更してください。

スキル一覧から隠すことによって、Shiftキーからしか発動できないスキルが作成できます。

ターン消費なしスキルとの併用について

このプラグインは「ターン消費なしスキルさん」との併用が主な使い道かなと思っています。

「ワンボタンスキルさん」と「ターン消費なしスキルさん」を両方設定した場合、
Shiftキーを押した瞬間に発動するスキルを作成することができます。

例:覚醒コマンド

f:id:ru_shalm:20160306162648p:plain

選んだ瞬間ギュイーン!とパワーアップします。
例えばTP100%消費する覚醒コマンドを使って、このターンの攻撃力を5倍!みたいな使い方ができそうですね。

  • 覚醒Lv:1:消費TP:25、ワンボタンスキル優先度1
  • 覚醒Lv:2:消費TP:50、ワンボタンスキル優先度2
  • 覚醒Lv:3:消費TP:100、ワンボタンスキル優先度3

みたいな設定をしておくのも面白そうかな。

例:イベントの呼び出し

f:id:ru_shalm:20160306161426p:plain

「コモンイベント」を呼び出す、ターン消費なし&ワンボタンスキルを設定することで、
行動選択中にShiftキーを押すと、メンバーの会話が始まる…!みたいなものが実現可能です。
(イベントの中身をつくるのは大変だけど…!)

戦闘中の相談コマンドみたいな使い方かなー

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

Torigoya_OneButtonSkill.js ダウンロード

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

利用規約

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

当然だけど、Shiftキーでしか発動できないスキル作ったら、スマホでプレイできないから注意な!!!!


オマケ:紹介のコーナー

※別作者さんのモノの紹介です。迷惑かけちゃだめだよ

奏ねこまさんの拡張プラグインを導入すると、
ワンボタンスキルさんで発動するスキル名が画面に表示されるようになります。

【オートセーブ】セーブコマンドプラグイン for MV(2019/01/26更新)

RPGツクールMZ版はこちら → https://torigoya-plugin.rutan.dev/system/saveCommand2/



f:id:ru_shalm:20160304014650p:plain

  • 2019/01/26 セーブデータを読み込むとセーブを実行してしまうのを回避するように変更
  • 2018/01/03 オートセーブ時にセーブ画面のカーソル位置を動かさない「notime」オプションを追加しました
  • 2016/06/12 「SaveCommand save latest」「SaveCommand load latest」を追加しました
  • 2016/06/12 セーブデータが無い時にロードコマンドを実行するとエラーする不具合を修正しました。
  • 2016/03/04 小物プラグイン集からページを分離しました。プラグイン自体の更新はありません。

プラグイン概要

プラグインコマンドからセーブ/ロードの実行ができるようになります。
オートセーブのような使い方がメインです。

オートセーブのゲームを作っていて生まれたプラグインなのですが、そのゲームはエターなりましたよ :)

使用方法

イベントコマンド一覧の3ページ目の右下「プラグインコマンド」から使用できます。

f:id:ru_shalm:20160304015150p:plain

以下、コマンド一覧です。枠の中のコマンドをコピペで使ってください!

最後にロード/セーブしたスロットに上書きセーブ

SaveCommand save last

最後にロード/セーブしたスロットの上に上書きでセーブを実行します。
オートセーブ的な強制的にセーブさせたいタイミングで使えると思います。

ニューゲームの場合、まだセーブされていない一番上のスロットにセーブされます。

指定したスロット番号にセーブ

SaveCommand save 1

スロット1番にセーブしたい!という場合は番号で直接指定できます。
1 の部分がスロットの番号なので 120 の間で設定してください。

変数で指定したスロット番号にセーブ

SaveCommand save [11]

スロット番号をツクールの変数で指定したい場合の指定方法です。
変数11番に入っている値のスロット番号を使いたい場合は↑のように指定します。

f:id:ru_shalm:20160304020137p:plain

こういうイメージ。

一番新しいセーブデータに上書きセーブ

SaveCommand save latest

lastlatest でまぎらわしいのですが別コマンドです。 セーブデータの中で一番新しいセーブスロットに上書きセーブを実行します。

【注意】

  • セーブデータ1(昨日保存したセーブ)
  • セーブデータ2(今日保存したセーブ)

↑のような2つのセーブデータがある場合、 セーブデータ1番をロードして、「SaveCommand save latest」を使用すると、 セーブデータ2番に上書きされてしまいます。

このオプションは後述のロード機能で使うのがメインで、 セーブコマンドでは last を使ったほうがいいかな…と思います。

セーブカーソルの位置を動かしたくない場合

ツクールMVではセーブ画面の初期カーソル位置が、
「最後にセーブまたはロードしたファイル」になるように設定されています。
そのため、このプラグインでオートセーブした場合に、
毎回カーソル位置が変わってしまって困ることがあります。
(たとえば、スロット20をオートセーブスロットにした場合、セーブ画面を開く度にスロット20になっていてめんどくさい、など)

SaveCommand save 1 notime

上のように、スロット番号指定のあとに notime と付けると、カーソル位置が動かないようになります。
内部的には「セーブした日時データを更新しない」ようにしています。

ロード機能

ここまで紹介したコマンドの SaveCommand save の部分を SaveCommand load にするとロード機能になります。

が!

ツクールのデフォルトの挙動にイベント中にゲームがロードされることは想定されて無いので、
ロードを実行するタイミングが悪いとバグることがあります。
ロードは上級者向け機能ということでお願いします。。。

セーブ削除機能

SaveCommand save の部分を SaveCommand remove にするとセーブデータを消せます。
使い方間違うと普通にプレイヤー激おこなので十分に注意してください。

ダウンロード

Torigoya_SaveCommand.js ダウンロード

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

利用規約

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


とはいえね、セーブデータバックアップされてたらあんまり意味ないけどね。

まぁ、絶対ロードさせないぞ!!というよりは、プレイヤーの便利のために使ってもらえると嬉しいなと思うのでした。
(スマホでやるゲームとかわざわざ自分でセーブ選択したくない〜)

スキル変化条件設定さん for MV(2020/06/20更新)

■ 最新版は ↓ コチラにあります
最新版はRPGツクールMZでも使うことができます。

以下は過去のバージョンです。


f:id:ru_shalm:20160221154801j:plain

  • 2020/06/20 YEP_X_BattleSysSTB併用時にエラーが出る問題の暫定対応
  • 2017/03/18 同一IDのスキル/アイテムの結果が混ざってしまう不具合を修正しました

プラグイン概要

スキルのメモ欄で指定した条件を満たした際に、別のスキルに変化する機能を追加します。

使用方法

f:id:ru_shalm:20160221155039p:plain

スキルのメモ欄で設定を行います。

<ChangeTo[変化先スキルのID]: 条件式>

変化先スキルのID の部分には、その条件を満たした際に変化する先のスキルIDを設定してください。
たとえば、 1 と設定したら、条件を満たしたときにスキルが通常攻撃に変化します。

条件式 の部分にはJavaScriptで条件式を記述することができます。
イメージとしては、スキル設定のダメージ計算式の入力欄と同じような感じです。
a という変数にスキル使用者の情報が入っています(ただし、 b (相手の情報)は使えません)

以下のような使用イメージです。

# 30%の確率でスキル100番に変化
<ChangeTo[100]: Math.random() < 0.3>

# HPが25%未満のとき、スキル100番に変化
<ChangeTo[100]: (a.hp / a.mhp) < 0.25>

# ステートID: 4(デフォルトだと毒)のとき、スキル100番に変化
<ChangeTo[100]: a.isStateAffected(4)>

RGSS3のときに残りMP量に応じて技の回数が変わる〜みたいなものをつくっていたので、
それに代わるものを作りたいなぁと思って作りました٩(๑❛ᴗ❛๑)۶

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

Torigoya_SkillChangeTo.js - スキル変化条件設定さん for MV

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

利用規約

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

RPGツクールMV小物プラグイン集(2020/06/20更新)

GitHubに丸投げしてた小物 についての簡易解説です。
1000000000番煎じ的なやつが結構多いです。。。

ターン消費なしスキルなどのまともなプラグインはこっちにあります。
鳥小屋.txt RPGツクールMVプラグイン

それぞれのプラグインは、右クリック→「名前をつけて保存」したものを plugins フォルダに入れてご利用ください٩(๑❛ᴗ❛๑)۶



小物プラグイン集更新履歴

  • 2020/06/20 「ステート追加/削除スキルプラグイン」でYEP_X_BattleSysSTB併用時にエラーが出る問題の暫定対応
  • 2017/07/21 「ステート追加/削除スキルプラグイン」で一度に複数のステートを付けたり外したりできるように。
  • 2016/3/20 「名前入力ダイアログプラグイン」で直後のメッセージがスキップ状態(決定キー押しっぱなし状態)と判定される問題を修正しました
  • 2016/1/25 「ステート追加スキルプラグイン」が「ステート追加/削除スキルプラグイン」になりました。「敵のスリップダメージ上限設定プラグイン」を追加。
  • 2016/1/13 「名前入力ダイアログプラグイン」に機能追加
  • 2016/1/5 「ステート追加スキルプラグイン」「WebStorageKeyにプレフィックス追加プラグイン」を追加
  • 2016/1/4 やっとまとめた

小物プラグイン一覧

Input.repeatウェイト設定プラグイン

かつてVXAce用に 高速Input.repeat?さん for RGSS3 として公開していたやつ。
そもそもRPGツクールMVではデフォルトでこの機能が実装されているので、そこの値をプラグイン設定から変更できるようにしたものです。

Torigoya_ChangeInputRepeatWait.js ダウンロード

武器は外せないようにするプラグイン

武器の変更はできるけど、武器無しにはできないようにするプラグインです。

Torigoya_NotRemoveWeapon.js ダウンロード

同じ名前の装備タイプなら同じものを装備できるようにするプラグイン

f:id:ru_shalm:20160104231214p:plain

こうやって同じ名前で装備タイプを設定したら…

f:id:ru_shalm:20160104231224p:plain

同じ名前の部分は同じ種類の装備のスロットとして使えるようになります。
装飾品とか2つくらい装備できるようにしたいじゃん?

Torigoya_SameEquipType.js ダウンロード

名前入力ダイアログプラグイン

f:id:ru_shalm:20160113013602p:plain

  • 2016/3/20 直後のメッセージがスキップ状態(決定キー押しっぱなし状態)と判定される問題を修正しました

コンシューマ機じゃないんだから名前入力くらいキーボードで文字入力したい!(スマホならなおさら!)
プラグインコマンドに名前入力ダイアログ機能を追加します。

# アクター1番の名前を変更するダイアログを表示
InputNamePrompt 1

# アクター1番の名前を変更するダイアログを表示(文字数上限を5文字に)
InputNamePrompt 1 5

# アクター1番の名前を変更するダイアログを表示(文字数上限を5文字 + メッセージを独自のものに)
InputNamePrompt 1 5 名前を変更するのじゃ

表示メッセージや最大文字数のデフォルト値はプラグイン設定で変更できます。
また、一部だけ別のものにしたい場合はプラグインコマンドで指定可能です。

Torigoya_InputNamePrompt.js ダウンロード

セーブコマンドプラグイン

ページ移動しました → 【オートセーブ】セーブコマンドプラグイン for MV(2019/01/26更新) - 鳥小屋.txt

プラグインコマンドからセーブ/ロードの実行ができます。
オートセーブのゲームを作っているので作りました。

SaveCommand save 1       # スロット1にセーブを実行します。
SaveCommand save [1]     # 変数[1]番のスロットにセーブを実行します。
SaveCommand save last    # 前回ロード/セーブしたスロットにセーブを実行します。
SaveCommand load 1       # スロット1からロードを実行します。
SaveCommand load [1]     # 変数[1]番のスロットからロードを実行します。
SaveCommand load last    # 前回ロード/セーブしたスロットからロードを実行します。
SaveCommand remove 1     # スロット1のセーブデータを削除します。
SaveCommand remove [1]   # 変数[1]番のスロットのセーブデータを削除します。
SaveCommand remove last    # 前回ロード/セーブしたスロットのセーブデータを削除します。

プラグインコマンドから SaveCommand save last をあちこちで呼び出せば、完全にオートセーブですね!
セーブ機能はいいんですが、ロード機能は場面によってバグりやすいので使いドコロに注意です。

Torigoya_SaveCommand.js ダウンロード

ステート追加/削除スキルプラグイン

使うと指定したステータス異常になるスキルを追加できるようにするプラグイン。
威力高いけど使うと自分が毒になってしまう〜〜みたいなものが作れます。戦闘不能を付ければ自爆スキルだね。

<AddState: 1>

スキルのメモ欄に↑のように設定するとステートの1番が付与されます。
逆にステートを消したい!みたいな場合は下のようにメモ欄に書いてください。

<RemoveState: 4>

Torigoya_AddStateSkill.js ダウンロード

WebStorageKeyにプレフィックス追加プラグイン

ツクールMVではWeb版プレイでのデータ保存先はブラウザのLocalStorageという機能を使っています。
このLocalStorageでは保存領域はドメインごとに別の場所になるように分けられています。
(例えば http://toripota.com/game1http://toripota.com/game2 では両方とも「http://toripota.com」というドメインで公開されているため、ゲーム自体は別物でも保存領域は同じ場所になります。)

ツクールMVはなぜか全ゲーム同じキー名(ファイル名)でセーブをしようとするので、もれなくセーブデータが一覧に混ざります。
セーブ一覧に他のゲームのセーブデータが表示されるのはどう考えてもジャマなので、このプラグインでは保存時のキー名(ファイル名)に、作者の好きな文字列を追加して、混ざるのを防止できるようにします。

Torigoya_AddPrefixToStorageKey.js ダウンロード

※ふりーむとかアツマールとかに投稿するときは使わないほうがいいと思うです

敵のスリップダメージ上限設定プラグイン

「毒のダメージは最大HPの4割にしよう!」→「アアアア、ボスが即死ィイィイ!」

という問題を解消します。敵キャラのメモ欄で毒などで受ける最大スリップダメージを設定できます。

<MaxSlipDamage: 100>  # 毒などで受けるダメージを最大100までにする

Torigoya_MaxSlipDamageSetting.js ダウンロード


利用規約

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

戦闘中セリフ表示さん for MV【2020/07/25更新】

RPGツクールMZ版は↓こちらのページです。


↓ ここから下はRPGツクールMV版の話。

f:id:ru_shalm:20151105024936p:plain

  • 2020/07/25 MOG_ConsecutiveBattles併用時に敵のセリフが出なくなる問題の暫定対応
  • 2020/06/20 YEP_X_BattleSysSTB併用時にエラーが出る問題の暫定対応
  • 2020/04/05 追加アドオン「時間で消去」を追加しました
  • 2019/05/12 エネミーに勝利メッセージを設定できるようにしました
  • 2018/03/24 「TMVplugin - バトルコマンド拡張」併用時に先頭アクターの戦闘開始メッセージが表示されないのを修正しました
  • 2018/03/23 YEP_BattleEngineCore併用時に戦闘開始メッセージが一瞬で消えるのを修正しました
  • 2018/03/18 ↓モンスターが死んでも喋ってるのを修正><
  • 2018/03/17 21:45 行動選択時メッセージについて、モンスターにも対応しました
  • 2018/03/17 行動選択時メッセージを追加しました
  • 2017/10/22 ステート解除時メッセージを追加しました
  • 2017/07/23 YEP_BattleEngineCore併用時に吹き出しの描画順序がおかしい問題を修正しました。
  • 2017/06/25 メッセージウィンドウのappend先を変更
  • 2017/02/16 他のプラグインコマンドが正常に動作しなくなる問題を修正しました。
  • 2016/11/23 YEP_BattleEngineCore併用時に動作しない問題を修正しました。
  • 2016/11/10 YEP_VictoryAftermath併用時に戦闘終了セリフの表示処理が何度も実行されてしまう問題を修正しました。
  • 2016/09/19 戦闘開始/終了時に行動不能な子は喋らないように修正しました。
  • 2016/06/04 「身代わり」に対応しました。
  • 2016/01/31 「ターン消費なしスキルさん」との競合を修正。両方とも更新が必要です><;
  • 2015/11/14 吹き出しのX/Y座標を調整できる設定メモ項目を追加しました
  • 2015/11/07 Recoveryのパラメータを一部追加 / RecoveryByRivalを追加 / 外部プラグインとの組み合わせについて追記

プラグイン概要

戦闘中に吹き出しでセリフを表示するようにします。 戦闘開始時、攻撃時、味方回復時、被弾時、死亡時、勝利時などに対応しています。

使用方法

f:id:ru_shalm:20151105024342p:plain

アクター / 敵キャラのメモ欄にいっぱい設定します。 <Speech/○○: ここにセリフ> といったフォーマットです。

以下のような設定項目があります。

■ 戦闘開始時(開始セリフはランダムでだれか1人だけ喋ります)
 \n と書くとそこで改行されます。
<Speech/Start:一気に決める!\n……よな?>


特定の敵グループにだけ特別なメッセージを表示することもできます。
以下は敵グループID: 10番にだけ表示する例

<Speech/Start[10]: こいつは強敵だ!>

■ 行動選択中
<Speech/Turn:いくぞ!>

敵グループID: 10番にだけ表示する場合
<Speech/Turn[10]: なかなかやるな…!>

■ 行動選択中(瀕死状態)
<Speech/Dying:まだまだ…っ!>

敵グループID: 10番にだけ表示する場合
<Speech/Turn[10]: 逃げるしか無いのか…?>

■ スキル使用時(\1 の部分が技名に置き換わります)
<Speech/Skill:唸れ、\1!>

■ スキルID: 1使用時( , で区切ることで複数登録できます。,自体をセリフに使う場合は前に \ を付けてね)
<Speech/Skill[1]:はっ!, てい!, くらえ!, Hey\, Attack!>

以下のように、「:」の前までだけを設定すると、その番号のスキルで喋らなくなります。
<Speech/Skill[2]>

■ アイテム使用時(\1 の部分が技名に置き換わります)
<Speech/Item:\1 を使う!>

■ アイテムID: 1使用時
<Speech/Item[1]:ポーションだ!>

■ 勝利時(勝利セリフはランダムでだれか1人だけ喋ります)
<Speech/Victory:やったぜ!>

■ ダメージ時
<Speech/Damage:うわっ!, ちっ!>

■ 味方を身代わりしたとき
<Speech/Substitute: させない!>

■ 味方ID: 1を身代わりしたとき(\1 の部分が身代わりしてあげた人の名前に置き換わります)
<Speech/Substitute[1]: \1は俺が守る!>

■ 味方に身代わりしてもらったとき
<Speech/Protected: ごめん!>

■ 味方ID: 1に身代わりしてもらったとき(\1 の部分が身代わりしてくれた人の名前に置き換わります)
<Speech/Protected[1]: \1!?>

■ 味方ID: 1による回復時(\1 の部分が回復した人の名前に置き換わります)
<Speech/Recovery[1]:ありがとう、\1>

※自分がアクターの場合はアクターID、敵キャラの場合は敵キャラIDを指定します
■ 味方による回復時(自分で回復したときは喋りません)
<Speech/Recovery:ありがとな!, 助かる!>

■ 味方ID: 1による回復時(\1 の部分が回復した人の名前に置き換わります)
<Speech/Recovery[1]:ありがとう、\1>

※自分がアクターの場合はアクターID、敵キャラの場合は敵キャラIDを指定します

■ 対戦相手による回復時
<Speech/RecoveryByRival:もらった!>

■ 対戦相手ID: 1による回復時(\1 の部分が回復した人の名前に置き換わります)
<Speech/RecoveryByRival[1]:なんのつもりだ、\1!>

※自分がアクターの場合は敵キャラID、敵キャラの場合はアクターIDを指定します

■ 味方によるステート1番回復時(自分で回復したときは喋りません)
<Speech/RemoveState_1: ふっかーつ!>

_1 の 1 の部分がステートIDに対応しています。
※例:毒の場合は Speech/RemoveState_4

■ 味方ID: 2によるステート回復時(\1 の部分が回復した人の名前に置き換わります)
<Speech/RemoveState_1[2]: \1のためなら戦える!>

_1 の 1 の部分がステートID、 [2] の 2 の部分がアクターIDに対応しています(むずかしいね)

■ 敵の攻撃がミスのとき
<Speech/Miss:危ない、危ない>

■ 敵の攻撃回避時(省略するとミスのセリフが流用されます)
<Speech/Evasion:避けた!>

■ 敵の魔法回避時(省略すると回避 or ミスのセリフが流用されます)
<Speech/MagicEvasion:見破った!>

■ 敵の攻撃をカウンターするとき
<Speech/Counter:返すぜ!>

■ 死んだとき
<Speech/Dead:ちくしょう…>

全て設定する必要はないです。設定しなかった部分については単に喋らなくなります。
なので、喋って欲しい部分だけ設定してください。

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

Torigoya_BalloonInBattle.js

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

他プラグインとの組み合わせについて

yanflyさま:YEP.3 – Battle Engine Core
プラグインの並び順により競合が発生します。
YEP.3 - Battle Engine Coreより下に、セリフ表示さんプラグインを設定してください。

ひきも記は閉鎖しました。さま:バトルコマンド拡張 TMBattleCommandEx.js
「パーティコマンドを省略する」オプション利用時に競合が発生します。
バトルコマンド拡張より下に、セリフ表示さんプラグインを設定してください。

追加アドオン

お好みで一部の挙動を変更できる、追加のプラグインです。
必要に応じてご利用ください。

※使う場合は、必ず「戦闘中セリフ表示さん for MV」より下に導入してください

スキルのセリフを時間で消去する

デフォルトではスキルの使用が完了するまで吹き出しが出たままになりますが、
このアドオンを追加すると、指定時間経過で時間で消えるようになります。
(※指定時間経つ前にスキルが完了した場合は、通常通りその時点で消えます)

Torigoya_BalloonInBattle_Addon_DisplayTime.js

利用規約

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

余談

イベント戦用などに特殊なスイッチがONのとき〜みたいな条件も付けたかったのですが、ちょっとメモ欄に無理が生じそうなのでそれはまた別の機会に…
そこまでやりたくなったらセリフ設定ツールも込みでつくろう٩(๑❛ᴗ❛๑)۶

【古いよ】戦闘不能メンバー自動入れ替えさん 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^)\
イベント組み直しあるよこれ!