Running Breathing

Mod紹介

走っている時の呼吸音を追加します。Elzeeさんの作品です。

Nexus

使い方

普通にインストールするだけです。

走ると呼吸音が再生されるようになります。音は結構小さいので、ヘッドフォンで聞かないとわかりにくいかもしれません。

改造してみた

呼吸音の再生条件が「走っている時」なので、走り出すとすぐに呼吸音が再生され、走るのをやめるとすぐに再生が止まります。これを走り出してしばらくしたら呼吸音が再生され、走るのをやめてもしばらくは再生を続けるようにしてみました。

スタミナの概念を追加する

SkyrimにはスタミナというActor Valueがありました。Falloutシリーズではスタミナがなく、かわりにAPがあります。

Fallout 4はActor Valueを自由に作成できるようになったので、スタミナを作りました。

Actor Valueのメリットとして、Actor単位でリソースを管理できる、各種Conditionに使える、Magic Effectで増減できるという点があげられます。何よりデータ構造的に理にかなっており美しいので、Modの開発がやりやすくなります。

SkyrimではActor Valueを増やせないので、かわりにグローバル変数を使ったり、Factionに所属させて代用したりする方法がありました。グローバル変数はゲーム内全体で共有するのでActor単位で作ると管理が大変になってしまう問題があります。FactionはRankをうまく使えばActorごとにリソースを管理できそうですが、元々派閥管理ために用意された仕組みを他のことに転用するため不具合の起こる可能性があがります。

Actor ValueはFO4EditではActor Value Informationになります。
Flagsは意味が不明なので、既存のModを参考にいい加減に設定しました。

スタミナが増減するアビリティを作る

走るとスタミナが減り、走るのをやめるとスタミナが回復するアビリティを用意します。これをプレイヤーに持たせると、自然にスタミナが増減するようになります。

スタミナというリソースを使うメリットは、走る以外にもスタミナを増減する機会を追加していきやすいという点があります。例えば地雷を踏んだらスタミナが大幅に減るとか、怪我をしている最中はスタミナが減り続けるとか、いろいろと応用がききます。

スタミナ増減アビリティと呼吸音アビリティになります。
スタミナが増えすぎないよう、減りすぎないように条件を設定します。
Actor Valueを変更するMagic EffectにはPower Affects Magnitudeフラグを忘れずに設定します。こちらは減る方なのでDetrimentalフラグも設定してあります。回復する方は付けません。

スタミナが減っている時に呼吸音を再生する

スタミナが一定値以下になったら効果が出るアビリティを用意します。

スタミナは最大値を20としたので、15以下で呼吸音を再生するようにしました。つまり走り出して5秒後です。

効果(Magic Effect)にはスクリプトを付け、そこで呼吸音を再生します。

ScriptName ElzeeBreathe:ElzeeBreatheEffectScript extends ActiveMagicEffect

;-- Properties --------------------------------------
Sound Property FemaleBreathInSound Auto Const
Sound Property FemaleBreathOutSound Auto Const
Sound Property MaleBreathInSound Auto Const
Sound Property MaleBreathOutSound Auto Const
ActorValue Property Stamina Auto

;-- Variables ---------------------------------------
Sound BreathInSound
Sound BreathOutSound
bool bIn = True
Actor MySelf

;-- Functions ---------------------------------------

Event OnEffectStart(Actor akTarget, Actor akCaster)
	Debug.Trace("ElzeeBreathe:ElzeeBreatheEffectScript OnEffectStart")

	MySelf = akTarget

	if MySelf.GetActorBase().GetSex() != 0
		BreathInSound = FemaleBreathInSound
		BreathOutSound = FemaleBreathOutSound
	else
		BreathInSound = MaleBreathInSound
		BreathOutSound = MaleBreathOutSound
	endif

	Self.starttimer(0.0, 0)
EndEvent

Event ontimer(int tid)
	Debug.Trace("ElzeeBreathe:ElzeeBreatheEffectScript ontimer")

	if bIn
		BreathInSound.play(MySelf)
		bIn = False
	else
		BreathOutSound.play(MySelf)
		bIn = True
	endif

	if MySelf.GetValue(Stamina) < 7
		Self.starttimer(1.0, 0)
	else
		Self.starttimer(2.0, 0)
	endif
EndEvent

スタミナが7未満なら呼吸音を荒く、7以上15未満ならゆっくりとしました。

既存のコードを調整

オリジナルは常時稼働するクエストにてプレイヤーの左足の足音発生イベントを監視して、足音の発生に合わせて呼吸音を再生しています。このクエストの稼働を止め、かわりに上記のアビリティをプレイヤーに持たせるようにします。

サウンドはすべてに「走っている」という条件が設定されていますので、これを取り除きます。これで立ち止まっている時でも呼吸音が再生されます。

注意事項

Actor Valueを増やすとActor全員に設定される関係上、セーブデータが大きくなることになります。もしかすると、初期値のまま増減させなければ理屈の上ではセーブデータに含める必要がないので、気にする必要はないのかもしれませんが、ベセスダがそこまで考えて実装しているのかは不明です。

機能をプレイヤーだけに限定するのならグローバル変数を使う方法もあります。ただしスタミナの増減はグローバル変数の書き換えになるため、スクリプト化が必須となってしまいます。個人的にはこちらの方が嫌なのでActor Valueとしました。

Actor Valueの初期値はなぜか一律100になってしまいます。これを変更する方法がわからなかったので、クエストの初期化処理のところにプレイヤーのスタミナを20にする処理を追加しました。

スクリプトからActor Valueにダメージを与えたり回復させる際はDamageValue関数やRestoreValue関数を使います。ModValueやSetValueは恒久的な変化になってしまうため、以降の処理が狂います。

関数名用途
DamageValue一時的に減らす。
ダメージを与える。
RestoreValue一時的に減っている値を戻す。
ダメージを回復する。
ModValue指定した値だけ増減させて変更する。
ずっとそのまま。
SetValue指定した値に変更する。
ずっとそのまま。

スタミナが減る機会を増やす

おまけとして、いくつか例をまとめておきます。

爆発を受けた時

ScriptName SampleQuestScript extends Quest

Actor Property PlayerRef Auto Const
ActorValue Property Stamina Auto
Keyword Property WeaponTypeExplosive Auto

Event OnInit()
	RegisterForHitEvent(PlayerRef, akSourceFilter = WeaponTypeExplosive)
EndEvent

Event OnHit(ObjectReference akTarget, ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, \
	bool abSneakAttack, bool abBashAttack, bool abHitBlocked, string apMaterial)

	Float fStamina = PlayerRef.GetValue(Stamina)
	PlayerRef.DamageValue(Stamina, fStamina)

	Utility.Wait(5.0)
	RegisterForHitEvent(PlayerRef, akSourceFilter = WeaponTypeExplosive)
EndEvent

WeaponTypeExplosiveというキーワードは手榴弾や地雷にあるので便利です。

怪我をした時

ScriptName SampleQuestScript extends Quest

Actor Property PlayerRef Auto Const
ActorValue Property Stamina Auto
Keyword Property WeaponTypeExplosive Auto

Event OnInit()
	Self.RegisterForRemoteEvent(PlayerRef, "OnCripple")
EndEvent

Event Actor.OnCripple(Actor akSender, ActorValue akActorValue, Bool abCrippled)
	if abCrippled
		Float fStamina = PlayerRef.GetValue(Stamina)
		PlayerRef.DamageValue(Stamina, fStamina)
	endif
EndEvent
タイトルとURLをコピーしました