こんにちはから始まる関係性でありたい。今日は日曜日でしたので(※実は私、今日本に居ますので日本時間では日曜日だったのです。)RPGツクールなるゲームをちまちま愛でていたのです。そうしましたら吸収スキルの仕様に「異議あり!」と申し立てを行いまして、折角の休日をほとんどスクリプトに費やすという悲喜交々の「悲」マシマシで候。以下、デフォルト仕様で変更したくなった部分。
・吸収率(割合)を設定できない。
たったこれだけ設定出来れば、他の細かい部分はさほど気にならなかったわけだが、どうしても解せなかった。例えばHP吸収で100ダメージ与えた場合に、HPを100回復出来るのは強力すぎるでありんすでやんす。元々知っていたので、速度補正や得TPで代用していた。例えば速度補正0なら10%、9なら100%吸収、という具合だ。掛ける10設定だったので、0~9程度なら許容できると思い、スキル設定をちまちまやっていた。そしてドラクエ11Sのウィッチネイルのようなスキルを作ろうとした時に、はたと気が付いた。思わず「はた!?」と声に出たかどうかはご想像にお任せしやんすでありんす。
結論から言うとデフォルト状態でドラクエのウィッチネイルは設定不可能だった。何故なら、HP吸収を設定した場合、HPが吸収対象となり、MP吸収を設定した場合はMPだけが吸収対象となる。ちなみに前述の技は「敵にHPダメージを与え、与えたダメージの5%、自分のMPを回復する」という効果を持つ。これだけで既に2点、出来ないことが確定している。ダメージの5%、HPダメージを与えてMP回復、この2点だ。という経験から、もう自分で作るしかないと奮起した。
せっかく作るからには、自分用だけに留めておくのも勿体ないと思ったので、出来ることをもう少し増やしてみた。下記の4点を盛り込むこととし、更に吸収時のダメージ挙動も自分好みに少し変更してみた。あとこれは余談だが、インデントが無くなる件、一部記号がタグ判定されてしまう件は、HTMLエディターの機能を使うことで解決できるようだ。それも試してみようと思ったので連日スクリプトを弄る切っ掛けとなった。
・吸収率を設定できる。
・吸収成功率を設定できる。
・回復対象を設定できる。
・吸収失敗時にメッセージが出る。
#==============================================================================
# ! 吸収の仕様変更 Ver1.0
#==============================================================================
=begin
スキルの属性に「吸収」を準備(データベースの用語タブ)しておき、
吸収属性の場合に与えたダメージを吸収する。
タイプのHP吸収、MP吸収は使わず、HPダメージ、MPダメージを用いる。
何が出来るようになる?
①HPダメージまたはMPダメージを与えてHP,MP,TPのいずれかを回復する。
②吸収率(回復量)を割合で設定できる。
③成功率を設定できる。
その他の仕様
・ダメージが入らなかった場合は吸収しない。
・与えたダメージより大きい値は吸収しない。
⇒HP50の敵に100ダメージ与えても吸収できるのは50まで。
・通常攻撃と同じようにダメージ効果(揺れたり)が発生する。
スキルのメモ欄に記載
体裁⇒タグ文言:種別,吸収率,成功率
種別は0=HP、1=MP、2=TP
記入例;
<吸収:0,50,100>
100%の確率で、与えたダメージの50%自分のHPを回復する。
<吸収:1,100,20>
20%の確率で、与えたダメージの100%自分のMPを回復する。
スクリプト内の凡例
● 独自メソッド(競合無し)
〇 エイリアス(競合注意)
◎ 再定義(競合要注意)
=end
module GCC
DRAIN_ELEMENT = 19 # 吸収属性のID
DRAIN_MARKER = "吸収" # メモ欄に記載する吸収のタグ文言
ACTOR_DRAIN_FAILURE_MESSAGE = "%sは%sを吸収されなかった。" # 吸収失敗の表示、アクター名が入る
ENEMY_DRAIN_FAILURE_MESSAGE = "%sの%sを吸収できなかった。" # 吸収失敗の表示、エネミー名が入る
end
#---------------------設定ここまでと言いたいがための点線---------------------
class RPG::UsableItem < RPG::BaseItem
#--------------------------------------------------------------------------
# ● 何を吸収(回復)するか判断するためのそれ
#--------------------------------------------------------------------------
def drain_configuration
/<#{GCC::DRAIN_MARKER}[::](\S+)>/ =~ note ? $1.to_s.split(/\s*,/).inject([]) {|r,i| r.push(i.to_i)} : []
end
end
class Game_ActionResult
attr_accessor :drain_configuration # 吸収判定
attr_accessor :drain_flag # 成否 判定
attr_accessor :tp_drain # TP吸収
#--------------------------------------------------------------------------
# 〇 オブジェクト初期化
#--------------------------------------------------------------------------
alias initialize_for_drain initialize
def initialize(battler)
@drain_configuration = []
@drain_flag = false
@tp_drain = 0
initialize_for_drain(battler)
end
#--------------------------------------------------------------------------
# 〇 ダメージの作成
#--------------------------------------------------------------------------
alias make_damage_for_drain make_damage
def make_damage(value, item)
make_damage_for_drain(value, item)
## OR条件:ダメージが0の時、攻撃属性が吸収ではない時、回復の時は吸収判定無し
return @success if @success == false || item.damage.element_id != GCC::DRAIN_ELEMENT || value < 1
##メモ欄の記述を取得
@drain_configuration = item.drain_configuration
if @drain_configuration == []
p "吸収属性スキルのメモ欄に吸収項目が正しく設定されていません。"
return @success
end
## 吸収攻撃と判断
@drain_flag = true
## 吸収成功の時、吸収量を得る。
## 最大吸収量は、相手のHPまたはMP残量まで。
if rand(100) < @drain_configuration[2]
case @drain_configuration[0]
when 0
@hp_drain = [@battler.hp, value * @drain_configuration[1] / 100].min if @hp_damage > 0
@hp_drain = [@battler.mp, value * @drain_configuration[1] / 100].min if @mp_damage > 0
when 1
@mp_drain = [@battler.hp, value * @drain_configuration[1] / 100].min if @hp_damage > 0
@mp_drain = [@battler.mp, value * @drain_configuration[1] / 100].min if @mp_damage > 0
when 2
@tp_drain = [@battler.hp, value * @drain_configuration[1] / 100].min if @hp_damage > 0
@tp_drain = [@battler.mp, value * @drain_configuration[1] / 100].min if @mp_damage > 0
end
end
return @success
end
#--------------------------------------------------------------------------
# ◎ HP ダメージの文章を取得
#--------------------------------------------------------------------------
def hp_damage_text
if @hp_damage > 0
fmt = @battler.actor? ? Vocab::ActorDamage : Vocab::EnemyDamage
sprintf(fmt, @battler.name, @hp_damage)
elsif @hp_damage < 0
fmt = @battler.actor? ? Vocab::ActorRecovery : Vocab::EnemyRecovery
sprintf(fmt, @battler.name, Vocab::hp, -hp_damage)
else
fmt = @battler.actor? ? Vocab::ActorNoDamage : Vocab::EnemyNoDamage
sprintf(fmt, @battler.name)
end
end
#--------------------------------------------------------------------------
# ◎ MP ダメージの文章を取得
#--------------------------------------------------------------------------
def mp_damage_text
if @mp_damage > 0
fmt = @battler.actor? ? Vocab::ActorLoss : Vocab::EnemyLoss
sprintf(fmt, @battler.name, Vocab::mp, @mp_damage)
elsif @mp_damage < 0
fmt = @battler.actor? ? Vocab::ActorRecovery : Vocab::EnemyRecovery
sprintf(fmt, @battler.name, Vocab::mp, -@mp_damage)
else
""
end
end
#--------------------------------------------------------------------------
# ● HP吸収の文章を取得
#--------------------------------------------------------------------------
def hp_drain_damage_text
@drain_flag = false
if @hp_drain > 0
fmt = @battler.actor? ? Vocab::ActorDrain : Vocab::EnemyDrain
sprintf(fmt, @battler.name, Vocab::hp, @hp_drain)
else
fmt = @battler.actor? ? GCC::ACTOR_DRAIN_FAILURE_MESSAGE : GCC::ENEMY_DRAIN_FAILURE_MESSAGE
sprintf(fmt, @battler.name, Vocab::hp)
end
end
#--------------------------------------------------------------------------
# ● MP吸収の文章を取得
#--------------------------------------------------------------------------
def mp_drain_damage_text
@drain_flag = false
if @mp_drain > 0
fmt = @battler.actor? ? Vocab::ActorDrain : Vocab::EnemyDrain
sprintf(fmt, @battler.name, Vocab::mp, @mp_drain)
else
fmt = @battler.actor? ? GCC::ACTOR_DRAIN_FAILURE_MESSAGE : GCC::ENEMY_DRAIN_FAILURE_MESSAGE
sprintf(fmt, @battler.name, Vocab::mp)
end
end
#--------------------------------------------------------------------------
# ● TP吸収の文章を取得
#--------------------------------------------------------------------------
def tp_drain_damage_text
@drain_flag = false
if @tp_drain > 0
fmt = @battler.actor? ? Vocab::ActorDrain : Vocab::EnemyDrain
sprintf(fmt, @battler.name, Vocab::tp, @tp_drain)
else
fmt = @battler.actor? ? GCC::ACTOR_DRAIN_FAILURE_MESSAGE : GCC::ENEMY_DRAIN_FAILURE_MESSAGE
sprintf(fmt, @battler.name, Vocab::tp)
end
end
end
class Game_Battler < Game_BattlerBase
#--------------------------------------------------------------------------
# 〇 ダメージの処理
# 呼び出し前に @result.hp_damage @result.mp_damage @result.hp_drain
# @result.mp_drain が設定されていること。
#--------------------------------------------------------------------------
alias execute_drain_damage execute_damage
def execute_damage(user)
execute_drain_damage(user)
user.tp += @result.tp_drain
end
end
class Window_BattleLog < Window_Selectable
#--------------------------------------------------------------------------
# 〇 ダメージの表示
#--------------------------------------------------------------------------
alias display_drain_damage display_damage
def display_damage(target, item)
display_drain_damage(target, item)
if !target.result.missed && !target.result.evaded && target.result.drain_flag
display_hp_drain_damage(target, item) if target.result.drain_configuration[0] == 0
display_mp_drain_damage(target, item) if target.result.drain_configuration[0] == 1
display_tp_drain_damage(target, item) if target.result.drain_configuration[0] == 2
end
end
#--------------------------------------------------------------------------
# ◎ HP ダメージ表示
#--------------------------------------------------------------------------
def display_hp_damage(target, item)
return if target.result.hp_damage == 0 && item && !item.damage.to_hp?
if target.result.hp_damage > 0 || target.result.hp_drain > 0
target.perform_damage_effect
end
Sound.play_recovery if target.result.hp_damage < 0
add_text(target.result.hp_damage_text)
wait
end
#--------------------------------------------------------------------------
# ◎ MP ダメージ表示
#--------------------------------------------------------------------------
def display_mp_damage(target, item)
return if target.dead? || target.result.mp_damage == 0
if target.result.mp_damage > 0 || target.result.mp_drain > 0
target.perform_damage_effect
end
Sound.play_recovery if target.result.mp_damage < 0
add_text(target.result.mp_damage_text)
wait
end
#--------------------------------------------------------------------------
# ● HP吸収の表示
#--------------------------------------------------------------------------
def display_hp_drain_damage(target, item)
replace_text(target.result.hp_drain_damage_text)
wait
end
#--------------------------------------------------------------------------
# ● MP吸収の表示
#--------------------------------------------------------------------------
def display_mp_drain_damage(target, item)
replace_text(target.result.mp_drain_damage_text)
wait
end
#--------------------------------------------------------------------------
# ● TP吸収の表示
#--------------------------------------------------------------------------
def display_tp_drain_damage(target, item)
replace_text(target.result.tp_drain_damage_text)
wait
end
end
データベースの「用語」から吸収用の属性を1つ作ってから設定するため、デフォルトのダメージタイプ「HP 吸収」と「MP 吸収」が不要になる。分かり易いように吸収という名前の属性を登録しておけば良いと思う。ダメージ計算は該当の属性有効度が考慮される。また、吸収属性のスキルを使っているのに、<吸収:xxx>タグがメモ欄に無い場合、また記載方法が間違っている場合は効果が出ない。ダメージ時の挙動についてはデフォルトがいい場合、Window_BattleLogの◎ HP ダメージ表示(display_hp_damage)と◎ MP ダメージ表示(display_mp_damage)だけコメントアウトするか削除するか。個人的には魔法でMP吸収したとしても、普通にダメージ音があってもいいと思っている。ドラクエで言うところのマホトラとか、静かにMPを吸い取るような挙動だと確かに何も無いほうがいいのかもしれない。スキル内容次第だろうか、その辺りは。
作り始めたから形になるまで頑張ったものの、よく探したら誰かが既に作っているかもしれない。自分のは素人すぎて何もサポート出来ないし、既出ならそちらを使ったほうがいいと思う心から。「吸収」で多少検索した限りでは無さそうだった。
※追記:行数増やさないほうがスマートかと思ったので、吸収表示はテキスト置換える方法に切り替えてみた。